mirror of
https://github.com/SabreTools/MPF.git
synced 2026-02-04 13:45:29 +00:00
Compare commits
1566 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
301a0cb188 | ||
|
|
64231da666 | ||
|
|
5f56977021 | ||
|
|
436ccf7a34 | ||
|
|
ef7510804e | ||
|
|
8c61b87954 | ||
|
|
17ba117949 | ||
|
|
0737ba7641 | ||
|
|
e9dba0767e | ||
|
|
2d142e9e9d | ||
|
|
7a928decff | ||
|
|
eb5409bdee | ||
|
|
1578193068 | ||
|
|
131c95e6ef | ||
|
|
a7790a271f | ||
|
|
1b342d56ef | ||
|
|
a500211129 | ||
|
|
4d798fa547 | ||
|
|
597ebdc973 | ||
|
|
c6a8a9265f | ||
|
|
393c53769d | ||
|
|
fa21999d3f | ||
|
|
dafbb05b16 | ||
|
|
1c1b23a84b | ||
|
|
fd0fe4912d | ||
|
|
b5b54d13a2 | ||
|
|
da77987db3 | ||
|
|
774f44c8ce | ||
|
|
251b3754e4 | ||
|
|
963acc3336 | ||
|
|
90588a0f8b | ||
|
|
a56c212488 | ||
|
|
6484ab5fe0 | ||
|
|
1ff48258b8 | ||
|
|
81019f9d56 | ||
|
|
d47c435236 | ||
|
|
d59b114cba | ||
|
|
7f26dcba4e | ||
|
|
5e2766f982 | ||
|
|
c883f899bb | ||
|
|
8c9950d5fa | ||
|
|
3e842af273 | ||
|
|
b837623da2 | ||
|
|
6742901243 | ||
|
|
d6460a2b68 | ||
|
|
7af59dacc6 | ||
|
|
fc3ef36fef | ||
|
|
6298487346 | ||
|
|
727d9844d5 | ||
|
|
72e7619e2d | ||
|
|
24b4647037 | ||
|
|
713b3f0557 | ||
|
|
f796a9b131 | ||
|
|
2cdf92bf92 | ||
|
|
ccc1687f1a | ||
|
|
6057ec3a59 | ||
|
|
2a5e736285 | ||
|
|
010ef9016b | ||
|
|
02606318b0 | ||
|
|
d4f641b122 | ||
|
|
a1dd6e2d21 | ||
|
|
d35679d688 | ||
|
|
83f5083ce7 | ||
|
|
5b6457f4b7 | ||
|
|
c6517d526b | ||
|
|
e35f1fc2ec | ||
|
|
14f4128d4a | ||
|
|
5465252dc7 | ||
|
|
2573b47a79 | ||
|
|
fe20905524 | ||
|
|
88f19180a4 | ||
|
|
de89968a1d | ||
|
|
8fc53c91b0 | ||
|
|
1a1fbd4b40 | ||
|
|
cac6c3049b | ||
|
|
6a6871e922 | ||
|
|
4a02a3efac | ||
|
|
f6eb961af4 | ||
|
|
faeaaef02a | ||
|
|
ebf393e634 | ||
|
|
3fbd4ea719 | ||
|
|
d09ff6cf1c | ||
|
|
1dc0d57d47 | ||
|
|
a748bd4d3a | ||
|
|
35dec7fe57 | ||
|
|
c22d16349a | ||
|
|
0d77a8950c | ||
|
|
285e94ca69 | ||
|
|
747ac4ea3b | ||
|
|
405ae7c7e4 | ||
|
|
f5ebe968c0 | ||
|
|
06a61b17cb | ||
|
|
9e8e4f6e36 | ||
|
|
fa72211b57 | ||
|
|
d5f66000a9 | ||
|
|
a52ba0aa7a | ||
|
|
eb045928f9 | ||
|
|
440302495b | ||
|
|
0732e9db78 | ||
|
|
a167652b2b | ||
|
|
cfa07c1918 | ||
|
|
53b31f91cf | ||
|
|
01cbd2cff5 | ||
|
|
65ad629ee0 | ||
|
|
06adbde715 | ||
|
|
1e5000bd8a | ||
|
|
8cb0b37e80 | ||
|
|
32c12e1332 | ||
|
|
09b307aa24 | ||
|
|
a5a8fbbf51 | ||
|
|
b366d236c8 | ||
|
|
a833e926f3 | ||
|
|
950be07bf0 | ||
|
|
4c5c1417e9 | ||
|
|
6fdc3412e0 | ||
|
|
807b0c5f9e | ||
|
|
9e0b64a1d1 | ||
|
|
8cfbf2d9f1 | ||
|
|
0064737130 | ||
|
|
292e3999c5 | ||
|
|
5ed1e94d84 | ||
|
|
5b094f57cb | ||
|
|
8066b5541e | ||
|
|
921d0207c2 | ||
|
|
4374ff7f74 | ||
|
|
0be5825b5e | ||
|
|
14c630bea7 | ||
|
|
9a66c685fd | ||
|
|
5e0fa1ad47 | ||
|
|
79065dcc69 | ||
|
|
3d7355aee1 | ||
|
|
6e9a6724c3 | ||
|
|
be35acfb48 | ||
|
|
f1a46c2e82 | ||
|
|
872959c889 | ||
|
|
b848a401f8 | ||
|
|
ee4762f8b3 | ||
|
|
d68bcfb96a | ||
|
|
d2433e4749 | ||
|
|
56ec0e7057 | ||
|
|
26e5d33d17 | ||
|
|
8b8b51ace4 | ||
|
|
f350904441 | ||
|
|
8e8e3368d0 | ||
|
|
4d8153dba1 | ||
|
|
e4e4b5ecde | ||
|
|
8373a6b8f5 | ||
|
|
45c51ebc80 | ||
|
|
af27085cc1 | ||
|
|
82e3707dce | ||
|
|
85192e8d3e | ||
|
|
6f784a352e | ||
|
|
ee707cf1af | ||
|
|
a14c998b3b | ||
|
|
004208df6a | ||
|
|
2f765146d1 | ||
|
|
a7d548f7ce | ||
|
|
fbdb9875f3 | ||
|
|
39a524e3cc | ||
|
|
9740ca3a7a | ||
|
|
f8d81972bf | ||
|
|
fe9302a553 | ||
|
|
c0ed7a7a0e | ||
|
|
b0b48743ac | ||
|
|
47e79dab31 | ||
|
|
90edc42fdf | ||
|
|
45db365705 | ||
|
|
952828dddd | ||
|
|
4a1e953ffd | ||
|
|
25740c2936 | ||
|
|
3696257940 | ||
|
|
4d46b7db5c | ||
|
|
21f5f29ac0 | ||
|
|
436e198826 | ||
|
|
91eb8c96c3 | ||
|
|
edf0bcb4fe | ||
|
|
1526714ab9 | ||
|
|
767e0bb05b | ||
|
|
52e781329c | ||
|
|
0c1395d3ec | ||
|
|
791d9cdb7b | ||
|
|
7d7dc4ee4e | ||
|
|
97fd04b13a | ||
|
|
899db4c8c0 | ||
|
|
bba204cbfe | ||
|
|
145660e9f9 | ||
|
|
24de14aea5 | ||
|
|
d57161e4d1 | ||
|
|
a066a5234a | ||
|
|
229db5dda2 | ||
|
|
4f2a8d354a | ||
|
|
b886471d72 | ||
|
|
2bab266ae2 | ||
|
|
6c5fd9bac8 | ||
|
|
08e93d7f13 | ||
|
|
7a510e084b | ||
|
|
da46d20ffc | ||
|
|
234c0bfbab | ||
|
|
82d60dbf4a | ||
|
|
6dffb80609 | ||
|
|
267c0e3184 | ||
|
|
033ccbbe67 | ||
|
|
c31b3f5894 | ||
|
|
9b1a303fea | ||
|
|
80a0f6da35 | ||
|
|
0c30eb7a60 | ||
|
|
7a8125bb71 | ||
|
|
c4beffd845 | ||
|
|
f97c112a53 | ||
|
|
5ef43ab6be | ||
|
|
2c399f99bf | ||
|
|
42e9eb0b96 | ||
|
|
e67d65f908 | ||
|
|
4ec8954b14 | ||
|
|
1a6abb039c | ||
|
|
bb5d1e5ac8 | ||
|
|
03c4c475eb | ||
|
|
04d7817d28 | ||
|
|
7cd100bc53 | ||
|
|
019924232a | ||
|
|
b5fc9f0275 | ||
|
|
44509b72ed | ||
|
|
d532a63dbd | ||
|
|
227785b079 | ||
|
|
0e364be998 | ||
|
|
7ae1f64ee3 | ||
|
|
92463a103d | ||
|
|
101cdb7b34 | ||
|
|
e924299f85 | ||
|
|
b983f7eb4a | ||
|
|
33b4be8b24 | ||
|
|
71a4edc8ba | ||
|
|
ceb305eb54 | ||
|
|
0b0d13dcf3 | ||
|
|
9f02368622 | ||
|
|
152010ee14 | ||
|
|
c6d5f0aea5 | ||
|
|
8c2ad64bb8 | ||
|
|
fa54d694b6 | ||
|
|
dc35b08624 | ||
|
|
4429515ba2 | ||
|
|
fdbc7b34e5 | ||
|
|
a1ab442cf0 | ||
|
|
9ed5c297f6 | ||
|
|
4ce9b214b0 | ||
|
|
7dcdadda75 | ||
|
|
f87a4d9fe2 | ||
|
|
e4e5d173f0 | ||
|
|
115b242d59 | ||
|
|
706bf8a431 | ||
|
|
87ecf1aa99 | ||
|
|
b5cf274333 | ||
|
|
4f4b6879b6 | ||
|
|
3b19463913 | ||
|
|
37386cd182 | ||
|
|
e04bdad16c | ||
|
|
e37f12705d | ||
|
|
5c8dc2c23a | ||
|
|
e9121f3b03 | ||
|
|
d68175db4e | ||
|
|
9d8181b0e2 | ||
|
|
6d657f268a | ||
|
|
3b3c5f823d | ||
|
|
09fc313492 | ||
|
|
316d0f6e54 | ||
|
|
a0033238bd | ||
|
|
5b1c6a7f46 | ||
|
|
8c0dff6552 | ||
|
|
43b230c84a | ||
|
|
f1b657011d | ||
|
|
e4d8ac8e1c | ||
|
|
08f44173dd | ||
|
|
54765c71fd | ||
|
|
01f8b49214 | ||
|
|
e8b0b3efaa | ||
|
|
f637938858 | ||
|
|
ae326c1d2f | ||
|
|
a4a1e6bf0a | ||
|
|
ecee44966e | ||
|
|
83437977ba | ||
|
|
8fcac1d425 | ||
|
|
705b5f1049 | ||
|
|
367d0c104b | ||
|
|
5d4bed2d9e | ||
|
|
63756192d8 | ||
|
|
b68ec78184 | ||
|
|
c55d5183fb | ||
|
|
f82e925944 | ||
|
|
c19f9ea173 | ||
|
|
76b2dd79ab | ||
|
|
c96ff23ad1 | ||
|
|
cd68b55b93 | ||
|
|
cad14d96f7 | ||
|
|
daaf9f1932 | ||
|
|
cb7502b450 | ||
|
|
ece142bbf1 | ||
|
|
611fee4605 | ||
|
|
791e2d0272 | ||
|
|
81742a4676 | ||
|
|
1ff3f2210c | ||
|
|
be9e4b91d5 | ||
|
|
854dcc5f95 | ||
|
|
29b71db33a | ||
|
|
2ee64b222a | ||
|
|
afda54f97b | ||
|
|
ad37c573b6 | ||
|
|
b6cb3104ae | ||
|
|
af9b0dc214 | ||
|
|
b5440032de | ||
|
|
a8e783235c | ||
|
|
fc97fe99e3 | ||
|
|
1c73b1133f | ||
|
|
908eccaafa | ||
|
|
e114d126c5 | ||
|
|
c07b4e4a28 | ||
|
|
06491a6611 | ||
|
|
b9a35850ad | ||
|
|
17a0c5d083 | ||
|
|
1b9523c799 | ||
|
|
ae80ecefc8 | ||
|
|
50ae32e3db | ||
|
|
2d43873398 | ||
|
|
a3df433fef | ||
|
|
35e71d8527 | ||
|
|
c5d07e4be1 | ||
|
|
0df5093b45 | ||
|
|
05d920d095 | ||
|
|
d2f7ac9843 | ||
|
|
857a302aad | ||
|
|
46de589791 | ||
|
|
f14961061c | ||
|
|
453fcf5cb1 | ||
|
|
24cdb27cdb | ||
|
|
24235c5896 | ||
|
|
c226f8cf58 | ||
|
|
b8f6c9f65f | ||
|
|
bb42e2db10 | ||
|
|
db544fd4b7 | ||
|
|
370c6bde5a | ||
|
|
d7965ee37f | ||
|
|
b2c6e07ed1 | ||
|
|
19cef20ceb | ||
|
|
058a1aeeaa | ||
|
|
d185077925 | ||
|
|
e3948ba91b | ||
|
|
4a30f94007 | ||
|
|
1ae27bf9e3 | ||
|
|
bc88103471 | ||
|
|
9ec6fbfe52 | ||
|
|
ebdb8de6b3 | ||
|
|
b8b56f6308 | ||
|
|
0726f5a402 | ||
|
|
90da5d1a7e | ||
|
|
bd3c518fa0 | ||
|
|
44272f60bf | ||
|
|
640ce8d854 | ||
|
|
74732058f2 | ||
|
|
22e480ccd1 | ||
|
|
32a0cb0394 | ||
|
|
88551bc2ed | ||
|
|
039af56f6a | ||
|
|
7a428e2add | ||
|
|
c8dd85eb72 | ||
|
|
7c7a19c5a0 | ||
|
|
9bedd26b24 | ||
|
|
09afdf52fb | ||
|
|
c69afe69dd | ||
|
|
ab18c7920a | ||
|
|
5af1841d13 | ||
|
|
8c324e3b8b | ||
|
|
d99099d587 | ||
|
|
fa7b46a516 | ||
|
|
f7c746b536 | ||
|
|
b6e109133f | ||
|
|
0d694c1bde | ||
|
|
47f45fa46f | ||
|
|
481f4b41d1 | ||
|
|
359ad87faa | ||
|
|
ba47cb7da2 | ||
|
|
8927c49963 | ||
|
|
21f9668093 | ||
|
|
371571d13f | ||
|
|
b231f82c4c | ||
|
|
1741326253 | ||
|
|
1878ef5ad6 | ||
|
|
ae42f5edd7 | ||
|
|
4362ed71e0 | ||
|
|
f02904ea49 | ||
|
|
abf4eb9b7c | ||
|
|
1f942977cc | ||
|
|
7edadd4739 | ||
|
|
cb09816c63 | ||
|
|
48f0a826ca | ||
|
|
9c10842924 | ||
|
|
def499769f | ||
|
|
5e1e61a441 | ||
|
|
4896a12ec5 | ||
|
|
b28ad5d3cd | ||
|
|
4cdbbcedf0 | ||
|
|
6ab63ba651 | ||
|
|
d36c5099f3 | ||
|
|
8ba8347a0c | ||
|
|
4c5184eac5 | ||
|
|
9914b94716 | ||
|
|
150e69eca5 | ||
|
|
f09923974b | ||
|
|
d98bc28930 | ||
|
|
ee4a7ab653 | ||
|
|
6b20aee320 | ||
|
|
a5849325f3 | ||
|
|
86d2d83fbe | ||
|
|
308e0d6937 | ||
|
|
3541bca2d0 | ||
|
|
2496099532 | ||
|
|
6001395181 | ||
|
|
fa2192a284 | ||
|
|
f09155936e | ||
|
|
a07fca6a7b | ||
|
|
5fe7a1dac8 | ||
|
|
16ed2f9595 | ||
|
|
9004d2bc7b | ||
|
|
cc98b38290 | ||
|
|
18ef0cddff | ||
|
|
d9ca55d96c | ||
|
|
816c94de58 | ||
|
|
c2ba58148a | ||
|
|
d9533f2448 | ||
|
|
5126d1854c | ||
|
|
6baaf132a7 | ||
|
|
98a30e6558 | ||
|
|
0912b78568 | ||
|
|
d92a1d566d | ||
|
|
ff40d18ed3 | ||
|
|
4d9cd85ba6 | ||
|
|
b6ae390cee | ||
|
|
4692028cfb | ||
|
|
3ada7db916 | ||
|
|
aa4b2f415d | ||
|
|
56e91bf177 | ||
|
|
228c752585 | ||
|
|
6ce7ccfa91 | ||
|
|
c8c98278b6 | ||
|
|
0fc57c58cf | ||
|
|
3dcac28488 | ||
|
|
4cd7073bf6 | ||
|
|
1af21e7aba | ||
|
|
52adcd0b46 | ||
|
|
8a91593e58 | ||
|
|
729f8273fc | ||
|
|
78df6f6583 | ||
|
|
dc8dae4df7 | ||
|
|
53db9dbf81 | ||
|
|
22755a4af9 | ||
|
|
ba28b414ba | ||
|
|
95d10ecb1e | ||
|
|
c5ab2c747a | ||
|
|
476c494f4e | ||
|
|
758c49c1cc | ||
|
|
d80ad3b3cf | ||
|
|
3d06f80703 | ||
|
|
7344460409 | ||
|
|
19f58d9dde | ||
|
|
ad9f39f832 | ||
|
|
d51117b058 | ||
|
|
0d65d5114a | ||
|
|
30fec3c3d0 | ||
|
|
8eb86fde90 | ||
|
|
7616c6b2ba | ||
|
|
e0742cdfc7 | ||
|
|
a19937d630 | ||
|
|
fa92402bc5 | ||
|
|
cdc3da5839 | ||
|
|
3430f8c1db | ||
|
|
12fd55e76c | ||
|
|
0013606d61 | ||
|
|
4d520d7d63 | ||
|
|
7bfe174680 | ||
|
|
4951e7bf42 | ||
|
|
d7d9c468ae | ||
|
|
32faa33ad3 | ||
|
|
8a5475380a | ||
|
|
1dd5542390 | ||
|
|
5156b89eca | ||
|
|
83ea04c880 | ||
|
|
8695d2981e | ||
|
|
e0c299e6f0 | ||
|
|
16ec54f389 | ||
|
|
998bf5d5fa | ||
|
|
07ec821e9a | ||
|
|
56cf8f3574 | ||
|
|
c6ebfcd6d9 | ||
|
|
6ceffce63d | ||
|
|
f43aafc00d | ||
|
|
ab598d8377 | ||
|
|
dbd876a1c1 | ||
|
|
fd102cb56b | ||
|
|
0afb49b657 | ||
|
|
be980fe0c4 | ||
|
|
08b4e8d602 | ||
|
|
e483e1cdc6 | ||
|
|
5c2dce78e2 | ||
|
|
26ea383775 | ||
|
|
64938fd7f1 | ||
|
|
22318ee3c1 | ||
|
|
b2b54a2706 | ||
|
|
40f04e0321 | ||
|
|
a7638b8063 | ||
|
|
2abcad2a0f | ||
|
|
e088b05de4 | ||
|
|
a31d894b79 | ||
|
|
34fae4572d | ||
|
|
1ecf0ad1fa | ||
|
|
7c7509020f | ||
|
|
7c6b118282 | ||
|
|
c154a844e3 | ||
|
|
088f1b8545 | ||
|
|
fc3c636bdd | ||
|
|
14c807c882 | ||
|
|
d0e9c51786 | ||
|
|
b428bc0ba0 | ||
|
|
6dbbb91438 | ||
|
|
2066d36424 | ||
|
|
29552cd39d | ||
|
|
640e7091cc | ||
|
|
af12c18d2e | ||
|
|
f28cf614c3 | ||
|
|
888cb8ec9f | ||
|
|
04035ac524 | ||
|
|
600374eb2d | ||
|
|
6ecb932a82 | ||
|
|
4cbc9ac109 | ||
|
|
5ee0b7345b | ||
|
|
cc55330fad | ||
|
|
6589380fdf | ||
|
|
bd45482bf7 | ||
|
|
e14c8a8f03 | ||
|
|
4ac00e9a1a | ||
|
|
edf983e304 | ||
|
|
01a69ef9b3 | ||
|
|
a368afc14a | ||
|
|
d83fed16f5 | ||
|
|
949df08690 | ||
|
|
ab3abb5b3e | ||
|
|
d16e73a530 | ||
|
|
3f8c55ca47 | ||
|
|
2e9aaa50f9 | ||
|
|
36951dc5da | ||
|
|
b39c8dd738 | ||
|
|
a1155cf9b7 | ||
|
|
1d151d213e | ||
|
|
6dc0c1438a | ||
|
|
8739569db6 | ||
|
|
0dcba9ce71 | ||
|
|
8d37b85e12 | ||
|
|
43cf8e1a45 | ||
|
|
7317553483 | ||
|
|
0b342e265c | ||
|
|
08359dd45f | ||
|
|
a24415cae6 | ||
|
|
59f8161308 | ||
|
|
51f955a14c | ||
|
|
ddebdef00c | ||
|
|
6a4b6d613a | ||
|
|
97aef5e29c | ||
|
|
9549178c3a | ||
|
|
c531539c87 | ||
|
|
fa04461631 | ||
|
|
83d230dfe1 | ||
|
|
ca18bbb72c | ||
|
|
de0f2c1ad9 | ||
|
|
2f0019282e | ||
|
|
72ca479c9f | ||
|
|
de3c4362e7 | ||
|
|
987348fee8 | ||
|
|
100e012fe6 | ||
|
|
af59ebe1ff | ||
|
|
0762c88655 | ||
|
|
bbe9c94545 | ||
|
|
c7efda7da8 | ||
|
|
5c78f9bc29 | ||
|
|
e7c17c7b4b | ||
|
|
7a2497f168 | ||
|
|
5172f6f253 | ||
|
|
9017472fa4 | ||
|
|
6659c410c6 | ||
|
|
8c7b66a2f5 | ||
|
|
8f57d78200 | ||
|
|
ad2ee9efa8 | ||
|
|
192964f65a | ||
|
|
672f30af35 | ||
|
|
a7a17298f2 | ||
|
|
e17ad8e4a1 | ||
|
|
2a544676e6 | ||
|
|
6abfa9581d | ||
|
|
a6de548e5d | ||
|
|
9dc3e579b5 | ||
|
|
c5be7d7f73 | ||
|
|
70c0da703b | ||
|
|
1cbe81fba6 | ||
|
|
420e356f34 | ||
|
|
0e0ff0cb80 | ||
|
|
9003d05ae2 | ||
|
|
c247225cac | ||
|
|
4bccaa8ecf | ||
|
|
b579fec7ab | ||
|
|
37e4525c98 | ||
|
|
2269537848 | ||
|
|
441fb91222 | ||
|
|
89e0473019 | ||
|
|
3e13b35c84 | ||
|
|
fd4910fc36 | ||
|
|
964685770f | ||
|
|
634d64b5a1 | ||
|
|
19ec1c448f | ||
|
|
e3532d6f02 | ||
|
|
aaf0aabb55 | ||
|
|
575a5936ca | ||
|
|
391d265353 | ||
|
|
f90d19821c | ||
|
|
b79babf57e | ||
|
|
a929bb0022 | ||
|
|
975eb97e27 | ||
|
|
49800cf0ed | ||
|
|
de18609e00 | ||
|
|
9911446bf9 | ||
|
|
a9223211ab | ||
|
|
54c4eeba03 | ||
|
|
a30ee3e6ff | ||
|
|
1fa19489a3 | ||
|
|
f6298dfe89 | ||
|
|
79802a53f6 | ||
|
|
54bf43fd6b | ||
|
|
bb2b2f668b | ||
|
|
ecca27e012 | ||
|
|
fe0699ca48 | ||
|
|
73b2f0921f | ||
|
|
c56230c3af | ||
|
|
919b62822d | ||
|
|
21b0c9a08d | ||
|
|
63fafd05b3 | ||
|
|
0a2493a953 | ||
|
|
87ab750714 | ||
|
|
5cf3eca9eb | ||
|
|
b4a079b65f | ||
|
|
7f2d501edf | ||
|
|
c981f94092 | ||
|
|
afba46b8b0 | ||
|
|
4e416df3c8 | ||
|
|
1b54e52351 | ||
|
|
5e1568a148 | ||
|
|
8f0ac56cf8 | ||
|
|
37f0f9d4a4 | ||
|
|
a48f75c704 | ||
|
|
58a683e3c9 | ||
|
|
907637b128 | ||
|
|
85f3e97a44 | ||
|
|
beae9691fd | ||
|
|
b7876d54cc | ||
|
|
5b24223cb5 | ||
|
|
88cadff9ef | ||
|
|
b92b39e7eb | ||
|
|
8d29a29591 | ||
|
|
daf516bf9c | ||
|
|
115d9857af | ||
|
|
b322146e9e | ||
|
|
b6e3c9da82 | ||
|
|
6abdc632dc | ||
|
|
335ca6d5ac | ||
|
|
8752426694 | ||
|
|
5357ba5900 | ||
|
|
f2686096bd | ||
|
|
c4ef14ea3c | ||
|
|
03668bd6af | ||
|
|
2d90a63ca7 | ||
|
|
11e6e37331 | ||
|
|
b229a2d59e | ||
|
|
c61af9316f | ||
|
|
02e3040e1b | ||
|
|
60bbe29435 | ||
|
|
3274ea08aa | ||
|
|
97a61dea32 | ||
|
|
6cccf20b03 | ||
|
|
0a7e17ed00 | ||
|
|
706f75c0eb | ||
|
|
022e87c4bb | ||
|
|
8b29ac7e47 | ||
|
|
4d5b8baf6f | ||
|
|
e199e5a08c | ||
|
|
6cc2351bf7 | ||
|
|
c391dbd3c8 | ||
|
|
709d980b67 | ||
|
|
0903855d5c | ||
|
|
6ad2505bf8 | ||
|
|
5db8756639 | ||
|
|
5d176408a2 | ||
|
|
ab0b569798 | ||
|
|
ee76d49e56 | ||
|
|
c75d2dcae2 | ||
|
|
7c411d36db | ||
|
|
ca767cf576 | ||
|
|
b57e0bb97e | ||
|
|
5f059253a4 | ||
|
|
e0f8443653 | ||
|
|
4c23a4bbf3 | ||
|
|
0c1486bbce | ||
|
|
6f41c9a331 | ||
|
|
2879dd29d6 | ||
|
|
42e1ef45b4 | ||
|
|
19493fdf0c | ||
|
|
5870ad0673 | ||
|
|
cbd2850d1b | ||
|
|
e7c36c104a | ||
|
|
960840d9ba | ||
|
|
b8ac1bc9d4 | ||
|
|
89edf9a8f6 | ||
|
|
eb8db0b311 | ||
|
|
b10cf8b78a | ||
|
|
1dd5c0d6d0 | ||
|
|
a1e00d23a4 | ||
|
|
1a9d38dd0e | ||
|
|
2f3e7d105d | ||
|
|
a72b3c32b1 | ||
|
|
a479b16ae2 | ||
|
|
a9e7b6f5b3 | ||
|
|
60605d7d00 | ||
|
|
9dc7f726e9 | ||
|
|
46134032d6 | ||
|
|
9847c8f351 | ||
|
|
7b506586cd | ||
|
|
40bbd422b7 | ||
|
|
285fd69ab4 | ||
|
|
b436e19bbb | ||
|
|
bf6e079289 | ||
|
|
b623866b6e | ||
|
|
df7046723c | ||
|
|
3cd3047790 | ||
|
|
abd60612c5 | ||
|
|
02292acee1 | ||
|
|
c923899898 | ||
|
|
fcdd2ad036 | ||
|
|
02d3af0ac1 | ||
|
|
0516bccece | ||
|
|
2d6389d54d | ||
|
|
60d5a117b5 | ||
|
|
9b7e2e35f5 | ||
|
|
ddfb383f23 | ||
|
|
a1707486f4 | ||
|
|
451101ec67 | ||
|
|
83c583b7e6 | ||
|
|
33cb3d3c97 | ||
|
|
3d98f345c1 | ||
|
|
de8ce5c110 | ||
|
|
fd9ed77316 | ||
|
|
d974b73cce | ||
|
|
da8a67fcad | ||
|
|
471bc60ed7 | ||
|
|
fef46be34c | ||
|
|
9a92dbdedb | ||
|
|
d6be0a4154 | ||
|
|
d3ae372903 | ||
|
|
7621ef1a13 | ||
|
|
148fdd0590 | ||
|
|
232256310a | ||
|
|
5e938791ef | ||
|
|
08405dd9b4 | ||
|
|
512c637ea3 | ||
|
|
909ebd72a1 | ||
|
|
123136e90e | ||
|
|
299d25af27 | ||
|
|
9eee2f6444 | ||
|
|
2afb10b73b | ||
|
|
1b016e5915 | ||
|
|
1c403e1748 | ||
|
|
a372a133ca | ||
|
|
08a7df504b | ||
|
|
39f9d9a86d | ||
|
|
bdd5af65ce | ||
|
|
92d7d2ab91 | ||
|
|
8d4d7ce449 | ||
|
|
d2d650cace | ||
|
|
772cefd700 | ||
|
|
e20350160b | ||
|
|
08f4e91b27 | ||
|
|
021237bc38 | ||
|
|
78c36db2f9 | ||
|
|
7fd2562cb5 | ||
|
|
15a3be2e66 | ||
|
|
9b6a540ec6 | ||
|
|
2b51085bc2 | ||
|
|
822134070b | ||
|
|
26cd874779 | ||
|
|
9f21b68541 | ||
|
|
e49d95663b | ||
|
|
2c70392ada | ||
|
|
1b2248b1e7 | ||
|
|
a322dc6353 | ||
|
|
7c78ae47c6 | ||
|
|
a14dec1b7e | ||
|
|
53b5862697 | ||
|
|
83d379c7b5 | ||
|
|
be33db8339 | ||
|
|
97e9924a0b | ||
|
|
7daab55639 | ||
|
|
9d70b7469a | ||
|
|
b5504902c4 | ||
|
|
f5e82ccd75 | ||
|
|
f4c4c21a10 | ||
|
|
661d2440f2 | ||
|
|
f4af8097f6 | ||
|
|
e1822905e7 | ||
|
|
e5154dad5b | ||
|
|
30f8932039 | ||
|
|
c4f0792c77 | ||
|
|
79c7f13ff9 | ||
|
|
dbeeb0c69b | ||
|
|
58c53ff5e2 | ||
|
|
87c441887a | ||
|
|
8ee4dab239 | ||
|
|
e01ebf8d8e | ||
|
|
e92bcd378c | ||
|
|
80156e73d1 | ||
|
|
97803cd860 | ||
|
|
9a5feee095 | ||
|
|
84410056bd | ||
|
|
acd0e41703 | ||
|
|
c7dfb9dca7 | ||
|
|
0efd82bd59 | ||
|
|
426ceff451 | ||
|
|
f2be7ed34c | ||
|
|
5dcc783b95 | ||
|
|
d1c641e934 | ||
|
|
59be63785d | ||
|
|
0bf85ec729 | ||
|
|
b54c2dc254 | ||
|
|
021fcd0641 | ||
|
|
f2dadae7a3 | ||
|
|
7ce7df2625 | ||
|
|
09fcd384ab | ||
|
|
5f8625a384 | ||
|
|
621011af7a | ||
|
|
a0b81941d1 | ||
|
|
e735335773 | ||
|
|
7b62572a56 | ||
|
|
0f921c926b | ||
|
|
4d8a4d23c0 | ||
|
|
9d7eaa46fd | ||
|
|
cc9664f7d6 | ||
|
|
573b3e9d1c | ||
|
|
9808694d89 | ||
|
|
d70d8f5b6e | ||
|
|
b75c2d80bf | ||
|
|
aa747ff651 | ||
|
|
bcbf5daf0d | ||
|
|
aee1c05a45 | ||
|
|
0bb96a8dd3 | ||
|
|
1e1d2c7b63 | ||
|
|
f12375cddc | ||
|
|
ed26e6611a | ||
|
|
98f77eca07 | ||
|
|
1b2b560f8f | ||
|
|
b49cc0c9bd | ||
|
|
4ba58ea861 | ||
|
|
3f52a20c90 | ||
|
|
580089d06e | ||
|
|
1397ab0fa6 | ||
|
|
87400793eb | ||
|
|
45f79d95b1 | ||
|
|
c8a4a61028 | ||
|
|
44091981b2 | ||
|
|
d3352643fc | ||
|
|
114c7fb38a | ||
|
|
dc7da708dc | ||
|
|
72e56aa1c7 | ||
|
|
99ceab07ad | ||
|
|
c0f6c072ce | ||
|
|
e039124f6c | ||
|
|
c96e4a4c7a | ||
|
|
622a08acf3 | ||
|
|
f44b6bf0d0 | ||
|
|
a6d75e15ea | ||
|
|
a02f03c4cb | ||
|
|
d48f5132fb | ||
|
|
ed4ac24efa | ||
|
|
9f3b8a7c2c | ||
|
|
612d4bb1f5 | ||
|
|
b58a50d246 | ||
|
|
af83811d57 | ||
|
|
66835fe6ab | ||
|
|
34cc1d33c6 | ||
|
|
a42d14e3b8 | ||
|
|
87aa165edf | ||
|
|
d217d62007 | ||
|
|
27bcc0d40a | ||
|
|
e1df075cde | ||
|
|
8358692e8d | ||
|
|
e1fae01dab | ||
|
|
d206ab140a | ||
|
|
9d8722ab17 | ||
|
|
c4fa40c403 | ||
|
|
1d0b06bfbe | ||
|
|
2cdf473dcb | ||
|
|
1af9e2c2da | ||
|
|
9a1815fa1e | ||
|
|
f601961c49 | ||
|
|
406acd34c5 | ||
|
|
31cdcbbc25 | ||
|
|
2215ce71c9 | ||
|
|
1872fbb1c8 | ||
|
|
d99f912ac2 | ||
|
|
00a76fb648 | ||
|
|
187e951a47 | ||
|
|
c0b9b27aae | ||
|
|
b76bb17396 | ||
|
|
2efa6d3623 | ||
|
|
3972ce633d | ||
|
|
0dc7901393 | ||
|
|
a25ba6eaa5 | ||
|
|
4ea48dfe57 | ||
|
|
8f7ad8b2ee | ||
|
|
3b9800df07 | ||
|
|
4c80d3234e | ||
|
|
9e4af1d66b | ||
|
|
73555df2ea | ||
|
|
3ca78604fd | ||
|
|
0138046923 | ||
|
|
2129184209 | ||
|
|
dd2116f8a6 | ||
|
|
814c2d9149 | ||
|
|
b3f7276044 | ||
|
|
ad88aa980b | ||
|
|
aca55e9203 | ||
|
|
cc3330bb27 | ||
|
|
1370909db7 | ||
|
|
08cc0c394b | ||
|
|
cb6692aea3 | ||
|
|
b3badb3a55 | ||
|
|
cbf73901d3 | ||
|
|
4822e45d58 | ||
|
|
1d930d36bf | ||
|
|
9effcc403d | ||
|
|
05dcc039bd | ||
|
|
cb08656abc | ||
|
|
69b22fc736 | ||
|
|
bf857f6ce7 | ||
|
|
7ebf2378b3 | ||
|
|
aec25dab37 | ||
|
|
e11969780d | ||
|
|
02c98b1547 | ||
|
|
c864589478 | ||
|
|
bdea1593be | ||
|
|
f6b78c07ca | ||
|
|
982a217d32 | ||
|
|
06588752ad | ||
|
|
9b057d7141 | ||
|
|
93fb3a85b5 | ||
|
|
7320f9ba66 | ||
|
|
a94f43ae0c | ||
|
|
e19a3f02e5 | ||
|
|
375c2c896c | ||
|
|
b151e79aed | ||
|
|
b45901c133 | ||
|
|
fab54ca0ae | ||
|
|
31dd32f19b | ||
|
|
f51c79d282 | ||
|
|
743c943363 | ||
|
|
91f6e266d1 | ||
|
|
8e843647bf | ||
|
|
151402dc50 | ||
|
|
057f340c9c | ||
|
|
f3f9c63156 | ||
|
|
7910a79917 | ||
|
|
cc7acfcd00 | ||
|
|
5580e208f5 | ||
|
|
56ef06d651 | ||
|
|
204dfca126 | ||
|
|
eb337a8aaf | ||
|
|
aa6fd781e8 | ||
|
|
32bcfa1d42 | ||
|
|
3b2e14d0de | ||
|
|
88a0ce38f9 | ||
|
|
110c8337aa | ||
|
|
3dc79fea6b | ||
|
|
fb036385f9 | ||
|
|
428bb2817b | ||
|
|
791caff240 | ||
|
|
d92015d071 | ||
|
|
de98bd9e0b | ||
|
|
67f5a7794a | ||
|
|
fbef94f634 | ||
|
|
0e8363f06e | ||
|
|
a1bafe0426 | ||
|
|
c51461592c | ||
|
|
ef5f996ec4 | ||
|
|
aa5998a52e | ||
|
|
37207c1cb0 | ||
|
|
d1813fdbc7 | ||
|
|
faf9d1d6f8 | ||
|
|
0360df0604 | ||
|
|
fe6487eeb4 | ||
|
|
b9eedd1cf6 | ||
|
|
26281b8f0b | ||
|
|
f0508fdf93 | ||
|
|
166d69c7ec | ||
|
|
fabf08ba55 | ||
|
|
0e5d8af0e9 | ||
|
|
3e1263ebff | ||
|
|
c0ed830241 | ||
|
|
4209158807 | ||
|
|
6d79ebf449 | ||
|
|
88ab691f07 | ||
|
|
37b1dc574c | ||
|
|
ad56e249ed | ||
|
|
f28cfe3d69 | ||
|
|
9643442281 | ||
|
|
dd44ec7ac1 | ||
|
|
801c1126cf | ||
|
|
4fd72efc46 | ||
|
|
9ec045cb21 | ||
|
|
52801ee94c | ||
|
|
2077d53964 | ||
|
|
14046e9217 | ||
|
|
2766debffc | ||
|
|
4f4688899c | ||
|
|
8151db9696 | ||
|
|
227c61b588 | ||
|
|
61224fba7b | ||
|
|
1dbf5516d8 | ||
|
|
10fe6ac32a | ||
|
|
e39ee66726 | ||
|
|
fff2db75d0 | ||
|
|
3a14db53c6 | ||
|
|
8b76b82e0f | ||
|
|
e110c55e1a | ||
|
|
85c30fbad3 | ||
|
|
14e5c74c65 | ||
|
|
b180e31b56 | ||
|
|
d172a45891 | ||
|
|
e74289116e | ||
|
|
68b932bad0 | ||
|
|
c4793e849c | ||
|
|
1c525a6d2e | ||
|
|
c8610ee16a | ||
|
|
0fb3bc1106 | ||
|
|
3cf133d750 | ||
|
|
f0be6b0bc9 | ||
|
|
e0ccb8b10d | ||
|
|
940afae1fd | ||
|
|
94ba339ef2 | ||
|
|
bfead10d87 | ||
|
|
97f9a73fc1 | ||
|
|
7f4921a47c | ||
|
|
07359d2a63 | ||
|
|
e5ba670c04 | ||
|
|
3096c369d3 | ||
|
|
333368675a | ||
|
|
d78d744ae2 | ||
|
|
a8efe056c1 | ||
|
|
9b2475a854 | ||
|
|
33e2b27e6d | ||
|
|
91fe9d9bec | ||
|
|
b1b9b3134f | ||
|
|
ca5386b529 | ||
|
|
347beca874 | ||
|
|
27ca4fd1af | ||
|
|
6d57a05f8c | ||
|
|
4d81449cfa | ||
|
|
76fcb3ae10 | ||
|
|
b913f5f9ae | ||
|
|
68fa1eecfb | ||
|
|
dc84f17ac5 | ||
|
|
c91137130b | ||
|
|
972b07551f | ||
|
|
61562fe995 | ||
|
|
01b6c3cc98 | ||
|
|
b461dc76b9 | ||
|
|
03eeed4113 | ||
|
|
07615cb336 | ||
|
|
9a9a977cc4 | ||
|
|
ab5869331b | ||
|
|
1c9ebfd703 | ||
|
|
a9bc3587a6 | ||
|
|
b1af2b6061 | ||
|
|
2fccd53098 | ||
|
|
a7ad3e41d9 | ||
|
|
1fc6476f71 | ||
|
|
53e5a1b1b1 | ||
|
|
119e9dc4cc | ||
|
|
9263769906 | ||
|
|
ebaf9539b2 | ||
|
|
818fb5ab34 | ||
|
|
2f514082a9 | ||
|
|
5c5379e972 | ||
|
|
c39894d9fc | ||
|
|
2c6cf0e736 | ||
|
|
7e96bbee27 | ||
|
|
f7019546d1 | ||
|
|
086f54abf0 | ||
|
|
143a4149bd | ||
|
|
20aed68d58 | ||
|
|
7a2061a36e | ||
|
|
191c7b080e | ||
|
|
aab0813688 | ||
|
|
9ad564772c | ||
|
|
20bb34c3c7 | ||
|
|
b15ddf390b | ||
|
|
18d1562ad3 | ||
|
|
d6f2ecbd25 | ||
|
|
3620686afa | ||
|
|
1524224bc3 | ||
|
|
35200d53d6 | ||
|
|
4b7d4e05e7 | ||
|
|
7e73f69433 | ||
|
|
9e1a972df5 | ||
|
|
1edac34c1a | ||
|
|
9adc588c9c | ||
|
|
71bfdcba8f | ||
|
|
9854c9970a | ||
|
|
0c68164d6d | ||
|
|
a413357b57 | ||
|
|
5e283c9e80 | ||
|
|
500eb66e30 | ||
|
|
411e5245a5 | ||
|
|
d270501c2d | ||
|
|
f7f924593f | ||
|
|
5126a66eb9 | ||
|
|
7fddef238d | ||
|
|
ace673f90d | ||
|
|
e063df63df | ||
|
|
22b15710d0 | ||
|
|
87199c1b0d | ||
|
|
7e5952bbb8 | ||
|
|
1a52a3a205 | ||
|
|
742db4c854 | ||
|
|
4fd51dbe45 | ||
|
|
096a8a6a06 | ||
|
|
ad5cd5b8f9 | ||
|
|
3230d59f6a | ||
|
|
96fa8d8cef | ||
|
|
01bf3c9efb | ||
|
|
da0bf64e94 | ||
|
|
d39cf5d13f | ||
|
|
7c7e78fd4e | ||
|
|
d2c504898a | ||
|
|
58028b4f18 | ||
|
|
54e835687b | ||
|
|
10f2318541 | ||
|
|
eb4e95e5db | ||
|
|
203418eebc | ||
|
|
136c6c8fbf | ||
|
|
2c216d6a58 | ||
|
|
f7ec19cc5d | ||
|
|
e8c4a97158 | ||
|
|
5e5fc4c812 | ||
|
|
5e0d99ff5d | ||
|
|
e88e67c927 | ||
|
|
d963dbbd5f | ||
|
|
11ce78fca2 | ||
|
|
fd4022ba84 | ||
|
|
f91aecad8e | ||
|
|
709b7d357f | ||
|
|
59980fa160 | ||
|
|
180caf83cc | ||
|
|
7047ee832a | ||
|
|
4b5532e1b0 | ||
|
|
137155d3dc | ||
|
|
793dd8289a | ||
|
|
bcf298e40b | ||
|
|
589aef1e21 | ||
|
|
9ab0b7ab3b | ||
|
|
4c5ea13aac | ||
|
|
0cf48bbdaa | ||
|
|
8fc9cc18a3 | ||
|
|
b1e156eed6 | ||
|
|
a8b3a837ef | ||
|
|
3f3a1c9a44 | ||
|
|
cf4d2f5055 | ||
|
|
2d19d51bc7 | ||
|
|
4842bdd38b | ||
|
|
7cc4f6d6a7 | ||
|
|
b284ffd99d | ||
|
|
81d0cc2cc2 | ||
|
|
70f368d6e9 | ||
|
|
bfbae5cf5c | ||
|
|
7cc231f5fd | ||
|
|
eda34b3477 | ||
|
|
bfb67ec0c9 | ||
|
|
275fd0da48 | ||
|
|
1ad5c25ed0 | ||
|
|
512f7ae016 | ||
|
|
3a00efc7fd | ||
|
|
3068c74ad7 | ||
|
|
9bdead5616 | ||
|
|
0ed5feb96b | ||
|
|
ec80ef2ede | ||
|
|
617591cc26 | ||
|
|
c855aa5cef | ||
|
|
e2a27479f5 | ||
|
|
c8cfe76aa3 | ||
|
|
ecb0234258 | ||
|
|
24ce4bcc51 | ||
|
|
162af3de31 | ||
|
|
7c0af96dc9 | ||
|
|
026f999b46 | ||
|
|
bbbc3e98a0 | ||
|
|
f78ad4e7b6 | ||
|
|
d756ae2163 | ||
|
|
701738ce25 | ||
|
|
620bdc9132 | ||
|
|
71f474c26c | ||
|
|
c48137a5c1 | ||
|
|
e248368484 | ||
|
|
7225b8c32d | ||
|
|
20e475e130 | ||
|
|
88dc005592 | ||
|
|
40792ff0eb | ||
|
|
6ae59e91de | ||
|
|
5c7aa5f7f5 | ||
|
|
aaa1ed674f | ||
|
|
42def3bbe5 | ||
|
|
9cdab52556 | ||
|
|
5c104ebf3d | ||
|
|
7ab72e542c | ||
|
|
3a8420cd2f | ||
|
|
916aa9fd70 | ||
|
|
8809df10b6 | ||
|
|
34d65a9d70 | ||
|
|
2830d7c8a2 | ||
|
|
c702c8b0ac | ||
|
|
e1df9a9754 | ||
|
|
03fe5ce8a5 | ||
|
|
432a9dda16 | ||
|
|
1dfc0f731e | ||
|
|
af515e0adf | ||
|
|
2222b57143 | ||
|
|
d8cfa2e6a4 | ||
|
|
a622cdd4e0 | ||
|
|
2a4ec83d0d | ||
|
|
b1d144d091 | ||
|
|
23a8b66c16 | ||
|
|
381ebd5961 | ||
|
|
b4d1f7d6c3 | ||
|
|
b3eff64275 | ||
|
|
f15c00acca | ||
|
|
a66d0d4722 | ||
|
|
66cdade01b | ||
|
|
9e9f001768 | ||
|
|
3514bdcbc4 | ||
|
|
312df37365 | ||
|
|
6214d91940 | ||
|
|
23d500434b | ||
|
|
7ee5e3ab43 | ||
|
|
6be4bb7c85 | ||
|
|
d620c13e22 | ||
|
|
73b585cdd2 | ||
|
|
2f33581e4a | ||
|
|
f3dba9a026 | ||
|
|
d7d0af369c | ||
|
|
2ab9a45a71 | ||
|
|
dc0bf642a9 | ||
|
|
9e32435972 | ||
|
|
c2b724e949 | ||
|
|
195d3c6ff7 | ||
|
|
04a8079cee | ||
|
|
0b2daf7d30 | ||
|
|
1353ee603b | ||
|
|
e9d272d139 | ||
|
|
0308c7a81e | ||
|
|
4caad10c9b | ||
|
|
85c1623d33 | ||
|
|
5be1825bb5 | ||
|
|
ec5e533bd8 | ||
|
|
c3e4c7fa78 | ||
|
|
bf66a3fcbd | ||
|
|
101193cb78 | ||
|
|
b610c29be6 | ||
|
|
999c4dceb5 | ||
|
|
2957370fac | ||
|
|
5dd36d7b06 | ||
|
|
47b5bbe7e7 | ||
|
|
5a2e4ca77e | ||
|
|
c479ddb80b | ||
|
|
da1f59e0c1 | ||
|
|
9574832e86 | ||
|
|
3df7842d23 | ||
|
|
62a0f6e49a | ||
|
|
60c180e4dd | ||
|
|
343d937362 | ||
|
|
f20b321433 | ||
|
|
ba19b0825f | ||
|
|
5abb44957c | ||
|
|
b9d9cf812f | ||
|
|
d1529f428a | ||
|
|
5061a79c4c | ||
|
|
eab3e25cf2 | ||
|
|
33e73a8992 | ||
|
|
a63972b549 | ||
|
|
bc57df7fc1 | ||
|
|
e16f616286 | ||
|
|
c5497d787b | ||
|
|
64f60004c4 | ||
|
|
020c063177 | ||
|
|
a3e6f8157f | ||
|
|
f27040cd1c | ||
|
|
3a490cfc8d | ||
|
|
1f8c5998c1 | ||
|
|
f96d4ee37e | ||
|
|
d0d15f03af | ||
|
|
eff6407206 | ||
|
|
c1e559568a | ||
|
|
ef030b290c | ||
|
|
71630591a1 | ||
|
|
31505745be | ||
|
|
e40444b60c | ||
|
|
44edf387a6 | ||
|
|
d3d225644d | ||
|
|
3afd9200a9 | ||
|
|
c5c340ff12 | ||
|
|
b28b85f7c6 | ||
|
|
c60684b83c | ||
|
|
a183a1ec91 | ||
|
|
abd8488185 | ||
|
|
e6dea158e5 | ||
|
|
24150c7b3c | ||
|
|
040720a1c2 | ||
|
|
70d30d370f | ||
|
|
a50b99da07 | ||
|
|
2cecbe69ad | ||
|
|
557410660f | ||
|
|
0d75dbaaa2 | ||
|
|
d38f95c73a | ||
|
|
c9d59a90e4 | ||
|
|
fc6a34d987 | ||
|
|
8acabb692f | ||
|
|
61f8871839 | ||
|
|
69d61ad185 | ||
|
|
27391ed31b | ||
|
|
ed56c92101 | ||
|
|
ab8ae1524f | ||
|
|
de7c247583 | ||
|
|
997fd8f7ac | ||
|
|
e39e07246a | ||
|
|
e0b0406d76 | ||
|
|
1efbe9a784 | ||
|
|
fab921c2dd | ||
|
|
56896b4bea | ||
|
|
54eb7d8ecd | ||
|
|
114587b9f6 | ||
|
|
cad33c6c07 | ||
|
|
8154999f1c | ||
|
|
3a30c14085 | ||
|
|
db8b1df480 | ||
|
|
e20cac8a80 | ||
|
|
ce9b4e39f5 | ||
|
|
ddff4b2e58 | ||
|
|
16a470475c | ||
|
|
6e01473e87 | ||
|
|
8682089151 | ||
|
|
f45cb0075f | ||
|
|
afccb48798 | ||
|
|
ce6995fba0 | ||
|
|
3328d1adea | ||
|
|
33d79df9a8 | ||
|
|
4fb64b19d6 | ||
|
|
bf0f495c8b | ||
|
|
5d5f8e8d8c | ||
|
|
91aa248355 | ||
|
|
633c6c1efb | ||
|
|
facb1f673f | ||
|
|
9c8938c7f2 | ||
|
|
17f75f3ce6 | ||
|
|
b99c48afa2 | ||
|
|
9481fada23 | ||
|
|
7efbc5043c | ||
|
|
92880d3148 | ||
|
|
9800f2b8ae | ||
|
|
a5d01604cb | ||
|
|
aaab84f90a | ||
|
|
318a1a303c | ||
|
|
0061de6b2e | ||
|
|
b3db7c547f | ||
|
|
1da29464a8 | ||
|
|
d1d4ff41c6 | ||
|
|
673c2745a9 | ||
|
|
4ad88441cc | ||
|
|
71bb822856 | ||
|
|
2a7789bd12 | ||
|
|
1d0417cc1c | ||
|
|
905c578d90 | ||
|
|
a457c85e53 | ||
|
|
36630fc0ed | ||
|
|
f509ac60da | ||
|
|
bf8aac6f81 | ||
|
|
ceddcc0722 | ||
|
|
3a2bda6fb6 | ||
|
|
aea2403153 | ||
|
|
6e334df42f | ||
|
|
04cb68c9bd | ||
|
|
06060c071b | ||
|
|
02903686ad | ||
|
|
00cbed725d | ||
|
|
dabccd3a8a | ||
|
|
0e1e499a66 | ||
|
|
b4f485a0cc | ||
|
|
5bad68b9ff | ||
|
|
2db686fc47 | ||
|
|
d705a4b316 | ||
|
|
0154ee5bb6 | ||
|
|
29f14f5690 | ||
|
|
dd6f7b0794 | ||
|
|
e5c9591d64 | ||
|
|
df8da8bd46 | ||
|
|
c9b21006d1 | ||
|
|
2b37882322 | ||
|
|
8a2b3f2c89 | ||
|
|
c16a9aeb70 | ||
|
|
d5a0797c92 | ||
|
|
a55a769886 | ||
|
|
fd18c60f28 | ||
|
|
2704d1f88d | ||
|
|
c16c938fa4 | ||
|
|
497e2a09fd | ||
|
|
8bc8887ce6 | ||
|
|
7e5a5586f9 | ||
|
|
eee068db7e | ||
|
|
79e70173fa | ||
|
|
4f732557b9 | ||
|
|
6cbcebd661 | ||
|
|
f74dc01657 | ||
|
|
4735bef7b4 | ||
|
|
52a925df12 | ||
|
|
3e10199cb0 | ||
|
|
470e641a8c | ||
|
|
f61b84d058 | ||
|
|
5e77b43be1 | ||
|
|
46530a9fca | ||
|
|
12610c0d69 | ||
|
|
9bb9d3f407 | ||
|
|
a0ed20042c | ||
|
|
37c253aac2 | ||
|
|
68135c58ae | ||
|
|
f9efa71fcc | ||
|
|
184913ad28 | ||
|
|
ff52767a02 | ||
|
|
34ac5f9ba0 | ||
|
|
7296d109cc | ||
|
|
9be705ae30 | ||
|
|
af8b376f5a | ||
|
|
03f9668048 | ||
|
|
3bb23fa7cc | ||
|
|
f85c9d4e7e | ||
|
|
5de3d209be | ||
|
|
f1b136c817 | ||
|
|
c18829e0b3 | ||
|
|
d114b7f868 | ||
|
|
445cc173ce | ||
|
|
1e28fcad2e | ||
|
|
8d4e5155d9 | ||
|
|
027f562573 | ||
|
|
74caf084ca | ||
|
|
7396b02543 | ||
|
|
8035826b1b | ||
|
|
c6e73582c5 | ||
|
|
ca09d8c703 | ||
|
|
40b6551c7a | ||
|
|
95b664705d | ||
|
|
6bda7b35a2 | ||
|
|
6fedebf2a9 | ||
|
|
02f98c674b | ||
|
|
fb1e4130df | ||
|
|
c507f52b80 | ||
|
|
7b2784f1a2 | ||
|
|
7a7c83e8cf | ||
|
|
b86ef09763 | ||
|
|
71c050edf6 | ||
|
|
988f25b514 | ||
|
|
e878e8b904 | ||
|
|
bd3484cb3d | ||
|
|
3d769ed707 | ||
|
|
613be66f91 | ||
|
|
81e0ffbc3c | ||
|
|
8f3d325e7d | ||
|
|
a63472c6e6 | ||
|
|
8c98005605 | ||
|
|
8062d6cf17 | ||
|
|
78bf6e63ed | ||
|
|
68e0d759f7 | ||
|
|
26e72284af | ||
|
|
0efecd6601 | ||
|
|
9a3c2eb626 | ||
|
|
ca753b4526 | ||
|
|
230b6ca721 | ||
|
|
dc90f9af3f | ||
|
|
b5898c7ea3 | ||
|
|
36f1aea509 | ||
|
|
6742444182 | ||
|
|
e01fd37e6b | ||
|
|
ca7071f82a | ||
|
|
3cb67e3e65 | ||
|
|
e67dd589b5 | ||
|
|
74f491eaaa | ||
|
|
9ebd28ef5a | ||
|
|
2a58052bfd | ||
|
|
5ed73aff2b | ||
|
|
5a6ad09004 | ||
|
|
6a43b74043 | ||
|
|
69dc91aa1a | ||
|
|
f840db5143 | ||
|
|
f33cd41ebb | ||
|
|
da7896e62a | ||
|
|
08b5b4a1aa | ||
|
|
c397701818 | ||
|
|
617eb00f21 | ||
|
|
751fd0cf1e | ||
|
|
84c64e6073 | ||
|
|
ff5bc464ab | ||
|
|
b09a87c7e4 | ||
|
|
4032b48e63 | ||
|
|
12fad35065 | ||
|
|
c28be2da72 | ||
|
|
122cc0d20b | ||
|
|
89db32dd53 | ||
|
|
59040ae0f0 | ||
|
|
d8035745a9 | ||
|
|
c73e13c1f0 | ||
|
|
af75c7c949 | ||
|
|
896eb28308 | ||
|
|
6ca3d39e5f | ||
|
|
a7af0d0d7b | ||
|
|
04f5a7ea8d | ||
|
|
5d82cc5622 | ||
|
|
2f37f51c0c | ||
|
|
4690db61e1 | ||
|
|
672ec42903 | ||
|
|
cb39599a46 | ||
|
|
80b5ff3920 | ||
|
|
f27d3a91d3 | ||
|
|
b18357bff5 | ||
|
|
e3cd5b7082 | ||
|
|
16d7a6224b | ||
|
|
f8e32ec06c | ||
|
|
7073d4e298 | ||
|
|
f7f464920b | ||
|
|
e677dc20e9 | ||
|
|
9871eb9928 | ||
|
|
12b43cf688 | ||
|
|
7dd6db66ee | ||
|
|
d7726a070e | ||
|
|
fbc9d04782 | ||
|
|
24b08dd245 | ||
|
|
c7ebe69b05 | ||
|
|
22ffda4b5a | ||
|
|
b89c051d7d | ||
|
|
8b41f03472 | ||
|
|
700ff50eef | ||
|
|
95ac7236ff | ||
|
|
755f1b8e95 | ||
|
|
d431a4c87f | ||
|
|
04348d2d58 | ||
|
|
6f5214c1a4 | ||
|
|
1fe12be0b5 | ||
|
|
9c9ca16366 | ||
|
|
1702db71d1 | ||
|
|
0ba7ccdb9a | ||
|
|
3ccf65190e | ||
|
|
6b9ee3d5ed | ||
|
|
3ee0355034 |
4
.editorconfig
Normal file
4
.editorconfig
Normal file
@@ -0,0 +1,4 @@
|
||||
[*.cs]
|
||||
|
||||
# SYSLIB1045: Convert to 'GeneratedRegexAttribute'.
|
||||
dotnet_diagnostic.SYSLIB1045.severity = silent
|
||||
28
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
28
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: For when you know better than me what you want
|
||||
title: "[Request]"
|
||||
labels: enhancement
|
||||
assignees: mnadareski
|
||||
|
||||
---
|
||||
|
||||
**Before You Submit**
|
||||
|
||||
- Remember to try the [latest WIP build](https://ci.appveyor.com/project/mnadareski/mpf/build/artifacts) to see if the feature already exists.
|
||||
- Is it copy protection related? If so, report the issue [here](hhttps://github.com/SabreTools/BinaryObjectScanner/issues) instead.
|
||||
- Check [previous issues](https://github.com/SabreTools/MPF/issues) to see if any of those are related to what you're about to ask for.
|
||||
|
||||
If none of those apply, then continue...
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
22
.github/ISSUE_TEMPLATE/informational.md
vendored
Normal file
22
.github/ISSUE_TEMPLATE/informational.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
name: Info
|
||||
about: Something you need to tell me
|
||||
title: "[Info]"
|
||||
labels: question
|
||||
assignees: mnadareski
|
||||
|
||||
---
|
||||
|
||||
**Before You Submit**
|
||||
|
||||
- Remember to try the [latest WIP build](https://ci.appveyor.com/project/mnadareski/mpf/build/artifacts) to see if the feature already exists.
|
||||
- Is it copy protection related? If so, report the issue [here](hhttps://github.com/SabreTools/BinaryObjectScanner/issues) instead.
|
||||
- Check [previous issues](https://github.com/SabreTools/MPF/issues) to see if any of those are related to what you're about to ask for.
|
||||
|
||||
If none of those apply, then continue...
|
||||
|
||||
**Is your information related to one of the dumping programs supported or something that isn't a bug in the code? Please describe.**
|
||||
A clear and concise description of what the information is. Ex. With the latest build of DumpingProgram, it [...]
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the information here.
|
||||
49
.github/ISSUE_TEMPLATE/issue-report.md
vendored
Normal file
49
.github/ISSUE_TEMPLATE/issue-report.md
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
---
|
||||
name: Issue Report
|
||||
about: Tell me what's wrong, seriously
|
||||
title: "[Problem]"
|
||||
labels: bug
|
||||
assignees: mnadareski
|
||||
|
||||
---
|
||||
|
||||
**Before You Submit**
|
||||
|
||||
- Remember to try the [latest WIP build](https://ci.appveyor.com/project/mnadareski/mpf/build/artifacts) to see if the issue has already been addressed.
|
||||
- Is it copy protection related? If so, report the issue [here](hhttps://github.com/SabreTools/BinaryObjectScanner/issues) instead.
|
||||
- Check multiple discs to help narrow down the issue
|
||||
- Check the Options to see if changing any of those affects your issue.
|
||||
|
||||
If all of those fail, then continue...
|
||||
|
||||
**Version**
|
||||
What version are you using?
|
||||
|
||||
- [ ] Stable release (version here)
|
||||
- [ ] WIP release (version here)
|
||||
|
||||
**Build**
|
||||
What runtime version are you using?
|
||||
|
||||
- [ ] .NET 6.0 running on (Operating System)
|
||||
- [ ] .NET 8.0 running on (Operating System)
|
||||
|
||||
**Describe the issue**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
50
.github/workflows/build_check.yml
vendored
Normal file
50
.github/workflows/build_check.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: MPF Check
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
project: [MPF.Check]
|
||||
runtime: [win-x86, win-x64, linux-x64, osx-x64] #[win-x86, win-x64, win-arm64, linux-x64, linux-arm64, osx-x64]
|
||||
framework: [net8.0] #[net20, net35, net40, net452, net472, net48, netcoreapp3.1, net5.0, net6.0, net7.0, net8.0]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
|
||||
- name: Build
|
||||
run: dotnet publish ${{ matrix.project }}/${{ matrix.project }}.csproj -f ${{ matrix.framework }} -r ${{ matrix.runtime }} -c Debug --self-contained true --version-suffix ${{ github.sha }} ${{ (startsWith(matrix.framework, 'net5') || startsWith(matrix.framework, 'net6') || startsWith(matrix.framework, 'net7') || startsWith(matrix.framework, 'net8')) && '-p:PublishSingleFile=true' || ''}}
|
||||
|
||||
- name: Archive build
|
||||
run: zip -r ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_debug.zip ${{ matrix.project }}/bin/Debug/${{ matrix.framework }}/${{ matrix.runtime }}/publish/
|
||||
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_debug
|
||||
path: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_debug.zip
|
||||
|
||||
- name: Upload to rolling
|
||||
uses: ncipollo/release-action@v1.14.0
|
||||
with:
|
||||
allowUpdates: True
|
||||
artifacts: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_debug.zip
|
||||
body: 'Last built commit: ${{ github.sha }}'
|
||||
name: 'Rolling Release'
|
||||
prerelease: True
|
||||
replacesArtifacts: True
|
||||
tag: "rolling"
|
||||
updateOnlyUnreleased: True
|
||||
57
.github/workflows/build_ui.yml
vendored
Normal file
57
.github/workflows/build_ui.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
name: MPF UI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
project: [MPF]
|
||||
runtime: [win-x86, win-x64]
|
||||
framework: [net8.0-windows] #[net40, net452, net472, net48, netcoreapp3.1, net5.0-windows, net6.0-windows, net7.0-windows, net8.0-windows]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
|
||||
- name: Build
|
||||
run: dotnet publish ${{ matrix.project }}/${{ matrix.project }}.csproj -f ${{ matrix.framework }} -r ${{ matrix.runtime }} -c Debug --self-contained true --version-suffix ${{ github.sha }} ${{ (startsWith(matrix.framework, 'net5') || startsWith(matrix.framework, 'net6') || startsWith(matrix.framework, 'net7') || startsWith(matrix.framework, 'net8')) && '-p:PublishSingleFile=true' || ''}}
|
||||
|
||||
- name: Bundle Redumper
|
||||
run: |
|
||||
wget https://github.com/superg/redumper/releases/download/build_311/redumper-2024.01.08_build311-win64.zip
|
||||
unzip redumper-2024.01.08_build311-win64.zip
|
||||
mkdir -p MPF/bin/Debug/${{ matrix.framework }}/${{ matrix.runtime }}/publish/Programs/Redumper
|
||||
mv redumper-2024.01.08_build311-win64/bin/redumper.exe MPF/bin/Debug/${{ matrix.framework }}/${{ matrix.runtime }}/publish/Programs/Redumper/
|
||||
|
||||
- name: Archive build
|
||||
run: zip -r ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_debug.zip ${{ matrix.project }}/bin/Debug/${{ matrix.framework }}/${{ matrix.runtime }}/publish/
|
||||
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_debug
|
||||
path: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_debug.zip
|
||||
|
||||
- name: Upload to rolling
|
||||
uses: ncipollo/release-action@v1.14.0
|
||||
with:
|
||||
allowUpdates: True
|
||||
artifacts: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_debug.zip
|
||||
body: 'Last built commit: ${{ github.sha }}'
|
||||
name: 'Rolling Release'
|
||||
prerelease: True
|
||||
replacesArtifacts: True
|
||||
tag: "rolling"
|
||||
updateOnlyUnreleased: True
|
||||
23
.github/workflows/check_pr.yml
vendored
Normal file
23
.github/workflows/check_pr.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: Build PR
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
|
||||
- name: Build
|
||||
run: dotnet build --no-restore
|
||||
|
||||
- name: Test
|
||||
run: dotnet test --no-restore --verbosity normal
|
||||
0
.gitmodules
vendored
Normal file
0
.gitmodules
vendored
Normal file
27
.vscode/launch.json
vendored
Normal file
27
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
// Use IntelliSense to find out which attributes exist for C# debugging
|
||||
// Use hover for the description of the existing attributes
|
||||
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": ".NET Core Launch (console)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/MPF.Check/bin/Debug/net6.0/MPF.Check.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/MPF.Check",
|
||||
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Attach",
|
||||
"type": "coreclr",
|
||||
"request": "attach",
|
||||
"processId": "${command:pickProcess}"
|
||||
}
|
||||
]
|
||||
}
|
||||
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"omnisharp.projectLoadTimeout": 480
|
||||
}
|
||||
28
.vscode/tasks.json
vendored
Normal file
28
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/MPF.sln",
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "watch",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"watch",
|
||||
"run",
|
||||
"${workspaceFolder}/MPF/MPF.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
}
|
||||
1170
CHANGELIST.md
1170
CHANGELIST.md
File diff suppressed because it is too large
Load Diff
@@ -1,59 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{8CFDE289-E171-4D49-A40D-5293265C1253}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>DICUI.Check</RootNamespace>
|
||||
<AssemblyName>DICUI.Check</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DICUI.Library\DICUI.Library.csproj">
|
||||
<Project>{51ab0928-13f9-44bf-a407-b6957a43a056}</Project>
|
||||
<Name>DICUI.Library</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -1,179 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
|
||||
namespace DICUI.Check
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// Help options
|
||||
if (args.Length == 0
|
||||
|| args[0] == "/h" || args[0] == "/?"
|
||||
|| args[0] == "-h" || args[0] == "-?")
|
||||
{
|
||||
DisplayHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
// List options
|
||||
if (args[0] == "/lm" || args[0] == "/listmedia"
|
||||
|| args[0] == "-lm" || args[0] == "--listmedia")
|
||||
{
|
||||
ListMediaTypes();
|
||||
Console.ReadLine();
|
||||
return;
|
||||
}
|
||||
else if (args[0] == "/ls" || args[0] == "/listsystems"
|
||||
|| args[0] == "-ls" || args[0] == "--listsystems")
|
||||
{
|
||||
ListKnownSystems();
|
||||
Console.ReadLine();
|
||||
return;
|
||||
}
|
||||
|
||||
// Normal operation check
|
||||
if (args.Length < 3)
|
||||
{
|
||||
DisplayHelp("Invalid number of arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the MediaType
|
||||
var mediaType = Converters.StringToMediaType(args[0].Trim('"'));
|
||||
if (mediaType == MediaType.NONE)
|
||||
{
|
||||
DisplayHelp($"{args[0]} is not a recognized media type");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the KnownSystem
|
||||
var knownSystem = Converters.StringToKnownSystem(args[1].Trim('"'));
|
||||
if (knownSystem == KnownSystem.NONE)
|
||||
{
|
||||
DisplayHelp($"{args[1]} is not a recognized system");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for Redump login credentials
|
||||
string username = null, password = null;
|
||||
int startIndex = 2;
|
||||
if (args[2] == "-c" || args[2] == "--credentials")
|
||||
{
|
||||
username = args[3];
|
||||
password = args[4];
|
||||
startIndex = 5;
|
||||
}
|
||||
|
||||
// Make a new Progress object
|
||||
var progress = new Progress<Result>();
|
||||
progress.ProgressChanged += ProgressUpdated;
|
||||
|
||||
// Loop through all the rest of the args
|
||||
for (int i = startIndex; i < args.Length; i++)
|
||||
{
|
||||
// Check for a file
|
||||
if (!File.Exists(args[i]))
|
||||
{
|
||||
DisplayHelp($"{args[i]} does not exist");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the full file path
|
||||
string filepath = Path.GetFullPath(args[i]);
|
||||
|
||||
// Now populate an environment
|
||||
var env = new DumpEnvironment
|
||||
{
|
||||
OutputDirectory = "",
|
||||
OutputFilename = filepath,
|
||||
System = knownSystem,
|
||||
Type = mediaType,
|
||||
ScanForProtection = false,
|
||||
|
||||
Username = username,
|
||||
Password = password,
|
||||
};
|
||||
env.FixOutputPaths();
|
||||
|
||||
// Finally, attempt to do the output dance
|
||||
var result = env.VerifyAndSaveDumpOutput(progress);
|
||||
Console.WriteLine(result.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display help for DICUI.Check
|
||||
/// </summary>
|
||||
/// <param name="error">Error string to prefix the help text with</param>
|
||||
private static void DisplayHelp(string error = null)
|
||||
{
|
||||
if (error != null)
|
||||
Console.WriteLine(error);
|
||||
|
||||
Console.WriteLine("Usage:");
|
||||
Console.WriteLine("DICUI.Check.exe <mediatype> <system> [-c username password] </path/to/output.bin> ...");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(@"Common Media Types:\r\n
|
||||
bd / bluray - BD-ROM
|
||||
cd / cdrom - CD-ROM
|
||||
dvd - DVD-ROM
|
||||
fd / floppy - Floppy Disk
|
||||
gd / gdrom - GD-ROM
|
||||
umd - UMD");
|
||||
Console.WriteLine("Run 'DICUI.Check.exe [-lm|--listmedia' for more options");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(@"Common Systems:\r\n
|
||||
apple / mac - Apple Macintosh
|
||||
cdi - Philips CD-i
|
||||
ibm / ibmpc - IBM PC Compatible
|
||||
psx / ps1 - Sony PlayStation
|
||||
ps2 - Sony PlayStation 2
|
||||
psp - Sony PlayStation Portable
|
||||
saturn - Sega Saturn
|
||||
xbox - Microsoft XBOX
|
||||
x360 - Microsoft XBOX 360");
|
||||
Console.WriteLine("Run 'DICUI.Check.exe [-ls|--listsystems' for more options");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List all media types with their short usable names
|
||||
/// </summary>
|
||||
private static void ListMediaTypes()
|
||||
{
|
||||
Console.WriteLine("Supported Media Types:");
|
||||
foreach (var val in Enum.GetValues(typeof(MediaType)))
|
||||
{
|
||||
if (((MediaType)val) == MediaType.NONE)
|
||||
continue;
|
||||
|
||||
Console.WriteLine($"{((MediaType?)val).ShortName()} - {((MediaType?)val).LongName()}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List all known systems with their short usable names
|
||||
/// </summary>
|
||||
private static void ListKnownSystems()
|
||||
{
|
||||
Console.WriteLine("Supported Known Systems:");
|
||||
foreach (var val in Enum.GetValues(typeof(KnownSystem)))
|
||||
{
|
||||
if (((KnownSystem)val) == KnownSystem.NONE)
|
||||
continue;
|
||||
|
||||
Console.WriteLine($"{((KnownSystem?)val).ShortName()} - {((KnownSystem?)val).LongName()}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple process counter to write to console
|
||||
/// </summary>
|
||||
private static void ProgressUpdated(object sender, Result value)
|
||||
{
|
||||
Console.WriteLine(value.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("DICUI.Check")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("DICUI.Check")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2019")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("8cfde289-e171-4d49-a40d-5293265c1253")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -1,111 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{51AB0928-13F9-44BF-A407-B6957A43A056}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>DICUI</RootNamespace>
|
||||
<AssemblyName>DICUI.Library</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="BurnOutSharp, Version=1.3.7.1, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BurnOutSharp.1.3.7.1\lib\net461\BurnOutSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="LessIO, Version=0.5.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\LessIO.0.5.0\lib\net40\LessIO.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="libmspackn, Version=0.8.0.0, Culture=neutral, processorArchitecture=x86">
|
||||
<HintPath>..\packages\libmspack4n.0.8.0\lib\net40\libmspackn.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="UnshieldSharp, Version=1.4.2.2, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\UnshieldSharp.1.4.2.2\lib\net461\UnshieldSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="zlib.net, Version=1.0.3.0, Culture=neutral, PublicKeyToken=47d7877cb3620160">
|
||||
<HintPath>..\packages\zlib.net.1.0.4.0\lib\zlib.net.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Data\Constants.cs" />
|
||||
<Compile Include="Data\Enumerations.cs" />
|
||||
<Compile Include="Data\SubmissionInfo.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Utilities\Converters.cs" />
|
||||
<Compile Include="Utilities\Drive.cs" />
|
||||
<Compile Include="Utilities\DumpEnvironment.cs" />
|
||||
<Compile Include="Utilities\Extensions.cs" />
|
||||
<Compile Include="Utilities\Parameters.cs" />
|
||||
<Compile Include="Utilities\Result.cs" />
|
||||
<Compile Include="Utilities\Validators.cs" />
|
||||
<Compile Include="Web\CookieAwareWebClient.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Web\RedumpAccess.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="mspack.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<COMReference Include="IMAPI2">
|
||||
<Guid>{2735412F-7F64-5B0F-8F00-5D77AFBE261E}</Guid>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
<COMReference Include="IMAPI2FS">
|
||||
<Guid>{2C941FD0-975B-59BE-A960-9A2A262853A5}</Guid>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -1,130 +0,0 @@
|
||||
namespace DICUI.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Top-level commands for DiscImageCreator
|
||||
/// </summary>
|
||||
public static class DICCommandStrings
|
||||
{
|
||||
public const string Audio = "audio";
|
||||
public const string BluRay = "bd";
|
||||
public const string Close = "close";
|
||||
public const string CompactDisc = "cd";
|
||||
public const string Data = "data";
|
||||
public const string DigitalVideoDisc = "dvd";
|
||||
public const string DriveSpeed = "ls";
|
||||
public const string Eject = "eject";
|
||||
public const string Floppy = "fd";
|
||||
public const string GDROM = "gd";
|
||||
public const string MDS = "mds";
|
||||
public const string Merge = "merge";
|
||||
public const string Reset = "reset";
|
||||
public const string SACD = "sacd";
|
||||
public const string Start = "start";
|
||||
public const string Stop = "stop";
|
||||
public const string Sub = "sub";
|
||||
public const string Swap = "swap";
|
||||
public const string XBOX = "xbox";
|
||||
public const string XBOXSwap = "xboxswap";
|
||||
public const string XGD2Swap = "xgd2swap";
|
||||
public const string XGD3Swap = "xgd3swap";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dumping flags for DiscImageCreator
|
||||
/// </summary>
|
||||
public static class DICFlagStrings
|
||||
{
|
||||
public const string AddOffset = "/a";
|
||||
public const string AMSF = "/p";
|
||||
public const string BEOpcode = "/be";
|
||||
public const string C2Opcode = "/c2";
|
||||
public const string CopyrightManagementInformation = "/c";
|
||||
public const string D8Opcode = "/d8";
|
||||
public const string DisableBeep = "/q";
|
||||
public const string ForceUnitAccess = "/f";
|
||||
public const string MCN = "/m";
|
||||
public const string MultiSession = "/ms";
|
||||
public const string NoFixSubP = "/np";
|
||||
public const string NoFixSubQ = "/nq";
|
||||
public const string NoFixSubQLibCrypt = "/nl";
|
||||
public const string NoFixSubRtoW = "/nr";
|
||||
public const string NoFixSubQSecuROM = "/ns";
|
||||
public const string NoSkipSS = "/nss";
|
||||
public const string Raw = "/raw";
|
||||
public const string Reverse = "/r";
|
||||
public const string ScanAntiMod = "/am";
|
||||
public const string ScanFileProtect = "/sf";
|
||||
public const string ScanSectorProtect = "/ss";
|
||||
public const string SeventyFour = "/74";
|
||||
public const string SkipSector = "/sk";
|
||||
public const string SubchannelReadLevel = "/s";
|
||||
public const string VideoNow = "/vn";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Template field values for submission info
|
||||
/// </summary>
|
||||
public static class Template
|
||||
{
|
||||
// Manual information
|
||||
|
||||
public const string TitleField = "Title";
|
||||
public const string ForeignTitleField = "Foreign Title (Non-latin)";
|
||||
public const string DiscNumberField = "Disc Number / Letter";
|
||||
public const string DiscTitleField = "Disc Title";
|
||||
public const string SystemField = "System";
|
||||
public const string MediaTypeField = "Media Type";
|
||||
public const string CategoryField = "Category";
|
||||
public const string RegionField = "Region";
|
||||
public const string LanguagesField = "Languages";
|
||||
public const string PlaystationLanguageSelectionViaField = "Language Selection Via";
|
||||
public const string DiscSerialField = "Disc Serial";
|
||||
public const string BarcodeField = "Barcode";
|
||||
public const string CommentsField = "Comments";
|
||||
public const string ContentsField = "Contents";
|
||||
public const string VersionField = "Version";
|
||||
public const string EditionField = "Edition/Release";
|
||||
public const string PlayStation3WiiDiscKeyField = "Disc Key";
|
||||
public const string PlayStation3DiscIDField = "Disc ID";
|
||||
public const string GameCubeWiiBCAField = "BCA";
|
||||
public const string CopyProtectionField = "Copy Protection";
|
||||
public const string MasteringRingField = "Mastering Code (laser branded/etched)";
|
||||
public const string MasteringSIDField = "Mastering SID Code";
|
||||
public const string MouldSIDField = "Mould SID Code";
|
||||
public const string AdditionalMouldField = "Additional Mould";
|
||||
public const string ToolstampField = "Toolstamp or Mastering Code (engraved/stamped)";
|
||||
|
||||
// Automatic Information
|
||||
|
||||
public const string PVDField = "Primary Volume Descriptor (PVD)";
|
||||
public const string DATField = "DAT";
|
||||
public const string SizeField = "Size";
|
||||
public const string CRC32Field = "CRC32";
|
||||
public const string MD5Field = "MD5";
|
||||
public const string SHA1Field = "SHA1";
|
||||
public const string MatchingIDsField = "Matching IDs";
|
||||
public const string ErrorCountField = "Error Count";
|
||||
public const string CuesheetField = "Cuesheet";
|
||||
public const string SubIntentionField = "SubIntention Data (SecuROM/LibCrypt)";
|
||||
public const string WriteOffsetField = "Write Offset";
|
||||
public const string LayerbreakField = "Layerbreak";
|
||||
public const string EXEDateBuildDate = "EXE/Build Date";
|
||||
public const string HeaderField = "Header";
|
||||
public const string PICField = "Permanent Information & Control (PIC)";
|
||||
public const string PlayStationEDCField = "EDC";
|
||||
public const string PlayStationAntiModchipField = "Anti-modchip";
|
||||
public const string PlayStationLibCryptField = "LibCrypt";
|
||||
public const string XBOXDMIHash = "DMI.bin Hashes";
|
||||
public const string XBOXPFIHash = "PFI.bin Hashes";
|
||||
public const string XBOXSSHash = "SS.bin Hashes";
|
||||
public const string XBOXSSRanges = "Security Sector Ranges";
|
||||
public const string XBOXSSVersion = "Security Sector Version";
|
||||
|
||||
// Default values
|
||||
|
||||
public const string RequiredValue = "(REQUIRED)";
|
||||
public const string RequiredIfExistsValue = "(REQUIRED, IF EXISTS)";
|
||||
public const string OptionalValue = "(OPTIONAL)";
|
||||
public const string DiscNotDetected = "Disc Not Detected";
|
||||
}
|
||||
}
|
||||
@@ -1,570 +0,0 @@
|
||||
namespace DICUI.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Category for Redump
|
||||
/// </summary>
|
||||
public enum Category
|
||||
{
|
||||
Games = 1,
|
||||
Demos = 2,
|
||||
Video = 3,
|
||||
Audio = 4,
|
||||
Multimedia = 5,
|
||||
Applications = 6,
|
||||
Coverdiscs = 7,
|
||||
Educational = 8,
|
||||
BonusDiscs = 9,
|
||||
Preproduction = 10,
|
||||
AddOns = 11,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supported DIC commands
|
||||
/// </summary>
|
||||
public enum DICCommand
|
||||
{
|
||||
NONE = 0,
|
||||
Audio,
|
||||
BluRay,
|
||||
Close,
|
||||
CompactDisc,
|
||||
Data,
|
||||
DigitalVideoDisc,
|
||||
DriveSpeed,
|
||||
Eject,
|
||||
Floppy,
|
||||
GDROM,
|
||||
MDS,
|
||||
Merge,
|
||||
Reset,
|
||||
SACD,
|
||||
Start,
|
||||
Stop,
|
||||
Sub,
|
||||
Swap,
|
||||
XBOX,
|
||||
XBOXSwap,
|
||||
XGD2Swap,
|
||||
XGD3Swap,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supported DIC flags
|
||||
/// </summary>
|
||||
public enum DICFlag
|
||||
{
|
||||
NONE = 0,
|
||||
AddOffset,
|
||||
AMSF,
|
||||
BEOpcode,
|
||||
C2Opcode,
|
||||
CopyrightManagementInformation,
|
||||
D8Opcode,
|
||||
DisableBeep,
|
||||
ForceUnitAccess,
|
||||
MCN,
|
||||
MultiSession,
|
||||
NoFixSubP,
|
||||
NoFixSubQ,
|
||||
NoFixSubQLibCrypt,
|
||||
NoFixSubRtoW,
|
||||
NoFixSubQSecuROM,
|
||||
NoSkipSS,
|
||||
Raw,
|
||||
Reverse,
|
||||
ScanAntiMod,
|
||||
ScanFileProtect,
|
||||
ScanSectorProtect,
|
||||
SeventyFour,
|
||||
SkipSector,
|
||||
SubchannelReadLevel,
|
||||
VideoNow,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dump status for Redump
|
||||
/// </summary>
|
||||
public enum DumpStatus
|
||||
{
|
||||
BadDumpRed = 2,
|
||||
PossibleBadDumpYellow = 3,
|
||||
OriginalMediaBlue = 4,
|
||||
TwoOrMoreDumpsGreen = 5,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Known systems
|
||||
/// </summary>
|
||||
public enum KnownSystem
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
#region Disc-Based Consoles
|
||||
|
||||
AtariJaguarCD,
|
||||
BandaiPlaydiaQuickInteractiveSystem,
|
||||
BandaiApplePippin,
|
||||
CommodoreAmigaCD32,
|
||||
CommodoreAmigaCDTV,
|
||||
EnvizionsEVOSmartConsole,
|
||||
FujitsuFMTownsMarty,
|
||||
HasbroVideoNow,
|
||||
HasbroVideoNowColor,
|
||||
HasbroVideoNowJr,
|
||||
HasbroVideoNowXP,
|
||||
MattelHyperscan,
|
||||
MicrosoftXBOX,
|
||||
MicrosoftXBOX360,
|
||||
MicrosoftXBOXOne,
|
||||
NECPCEngineTurboGrafxCD,
|
||||
NECPCFX,
|
||||
NintendoGameCube,
|
||||
NintendoSonySuperNESCDROMSystem,
|
||||
NintendoWii,
|
||||
NintendoWiiU,
|
||||
Panasonic3DOInteractiveMultiplayer, // The 3DO Company 3DO Interactive Multiplayer
|
||||
PhilipsCDi,
|
||||
PioneerLaserActive,
|
||||
SegaCDMegaCD,
|
||||
SegaDreamcast,
|
||||
SegaSaturn,
|
||||
SNKNeoGeoCD,
|
||||
SonyPlayStation,
|
||||
SonyPlayStation2,
|
||||
SonyPlayStation3,
|
||||
SonyPlayStation4,
|
||||
SonyPlayStationPortable,
|
||||
TandyMemorexVisualInformationSystem,
|
||||
VMLabsNuon,
|
||||
VTechVFlashVSmilePro,
|
||||
ZAPiTGamesGameWaveFamilyEntertainmentSystem,
|
||||
|
||||
MarkerDiscBasedConsoleEnd,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cartridge-Based and Other Consoles
|
||||
|
||||
/*
|
||||
AmstradGX4000,
|
||||
APFMicrocomputerSystem,
|
||||
Atari2600VCS,
|
||||
Atari5200,
|
||||
Atari7800,
|
||||
AtariJaguar,
|
||||
AtariXEVideoGameSystem,
|
||||
Audiosonic1292AdvancedProgrammableVideoSystem,
|
||||
BallyAstrocade,
|
||||
BitCorporationDina,
|
||||
CasioLoopy,
|
||||
CasioPV1000,
|
||||
Commodore64GamesSystem,
|
||||
DaewooElectronicsZemmix,
|
||||
EmersonArcadia2001,
|
||||
EpochCassetteVision,
|
||||
EpochSuperCassetteVision,
|
||||
FairchildChannelF,
|
||||
FuntechSuperACan,
|
||||
GeneralConsumerElectricVectrex,
|
||||
HeberBBCBridgeCompanion,
|
||||
IntertonVC4000,
|
||||
JungleTacVii,
|
||||
LeapFrogClickStart,
|
||||
LJNVideoArt,
|
||||
MagnavoxOdyssey2,
|
||||
MattelIntellivision,
|
||||
NECPCEngineTurboGrafx16,
|
||||
NichibutsuMyVision,
|
||||
Nintendo64,
|
||||
Nintendo64DD,
|
||||
NintendoFamilyComputerNintendoEntertainmentSystem,
|
||||
NintendoFamilyComputerDiskSystem,
|
||||
NintendoSuperFamicomSuperNintendoEntertainmentSystem,
|
||||
NintendoSwitch,
|
||||
PhilipsVideopacPlusG7400,
|
||||
RCAStudioII,
|
||||
Sega32X,
|
||||
SegaMarkIIIMasterSystem,
|
||||
SegaMegaDriveGenesis,
|
||||
SegaSG1000,
|
||||
SNKNeoGeo,
|
||||
SSDCOMPANYLIMITEDXaviXPORT,
|
||||
ViewMasterInteractiveVision,
|
||||
VTechCreatiVision,
|
||||
VTechVSmile,
|
||||
VTechSocrates,
|
||||
WorldsOfWonderActionMax,
|
||||
|
||||
MarkerOtherConsoleEnd,
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region Computers
|
||||
|
||||
AcornArchimedes,
|
||||
AppleMacintosh,
|
||||
CommodoreAmiga,
|
||||
FujitsuFMTowns,
|
||||
IBMPCCompatible,
|
||||
NECPC88,
|
||||
NECPC98,
|
||||
SharpX68000,
|
||||
|
||||
MarkerComputerEnd,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Arcade
|
||||
|
||||
AmigaCUBOCD32,
|
||||
AmericanLaserGames3DO,
|
||||
Atari3DO,
|
||||
Atronic,
|
||||
AUSCOMSystem1,
|
||||
BallyGameMagic,
|
||||
CapcomCPSystemIII,
|
||||
GlobalVRVarious,
|
||||
GlobalVRVortek,
|
||||
GlobalVRVortekV3,
|
||||
ICEPCHardware,
|
||||
IncredibleTechnologiesEagle,
|
||||
IncredibleTechnologiesVarious,
|
||||
KonamieAmusement,
|
||||
KonamiFirebeat,
|
||||
KonamiGVSystem,
|
||||
KonamiM2,
|
||||
KonamiPython,
|
||||
KonamiPython2,
|
||||
KonamiSystem573,
|
||||
KonamiTwinkle,
|
||||
KonamiVarious,
|
||||
MeritIndustriesBoardwalk,
|
||||
MeritIndustriesMegaTouchForce,
|
||||
MeritIndustriesMegaTouchION,
|
||||
MeritIndustriesMegaTouchMaxx,
|
||||
MeritIndustriesMegaTouchXL,
|
||||
NamcoCapcomSystem256,
|
||||
NamcoCapcomTaitoSystem246,
|
||||
NamcoSegaNintendoTriforce,
|
||||
NamcoSystem12,
|
||||
NamcoSystem357,
|
||||
NewJatreCDi,
|
||||
NichibutsuHighRateSystem,
|
||||
NichibutsuSuperCD,
|
||||
NichibutsuXRateSystem,
|
||||
PanasonicM2,
|
||||
PhotoPlayVarious,
|
||||
RawThrillsVarious,
|
||||
SegaChihiro,
|
||||
SegaEuropaR,
|
||||
SegaLindbergh,
|
||||
SegaNaomi,
|
||||
SegaNaomi2,
|
||||
SegaNu,
|
||||
SegaRingEdge,
|
||||
SegaRingEdge2,
|
||||
SegaRingWide,
|
||||
SegaTitanVideo,
|
||||
SegaSystem32,
|
||||
SeibuCATSSystem,
|
||||
TABAustriaQuizard,
|
||||
TsunamiTsuMoMultiGameMotionSystem,
|
||||
|
||||
MarkerArcadeEnd,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Other
|
||||
|
||||
AudioCD,
|
||||
BDVideo,
|
||||
DVDVideo,
|
||||
EnhancedCD,
|
||||
HDDVDVideo,
|
||||
NavisoftNaviken21,
|
||||
PalmOS,
|
||||
PhilipsCDiDigitalVideo,
|
||||
PhotoCD,
|
||||
PlayStationGameSharkUpdates,
|
||||
RainbowDisc,
|
||||
SuperAudioCD,
|
||||
TaoiKTV,
|
||||
TomyKissSite,
|
||||
VideoCD,
|
||||
|
||||
MarkerOtherEnd,
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Known system category
|
||||
/// </summary>
|
||||
public enum KnownSystemCategory
|
||||
{
|
||||
DiscBasedConsole = 0,
|
||||
OtherConsole,
|
||||
Computer,
|
||||
Arcade,
|
||||
Other,
|
||||
Custom
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of all disc langauges
|
||||
/// </summary>
|
||||
public enum Language
|
||||
{
|
||||
Afrikaans,
|
||||
Arabic,
|
||||
Basque,
|
||||
Bulgarian,
|
||||
Catalan,
|
||||
Chinese,
|
||||
Croatian,
|
||||
Czech,
|
||||
Danish,
|
||||
Dutch,
|
||||
English,
|
||||
Finnish,
|
||||
French,
|
||||
Gaelic,
|
||||
German,
|
||||
Greek,
|
||||
Hebrew,
|
||||
Hindi,
|
||||
Hungarian,
|
||||
Italian,
|
||||
Japanese,
|
||||
Korean,
|
||||
Norwegian,
|
||||
Polish,
|
||||
Portuguese,
|
||||
Punjabi,
|
||||
Romanian,
|
||||
Russian,
|
||||
Slovak,
|
||||
Slovenian,
|
||||
Spanish,
|
||||
Swedish,
|
||||
Tamil,
|
||||
Thai,
|
||||
Turkish,
|
||||
Ukrainian,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Known media types
|
||||
/// </summary>
|
||||
public enum MediaType
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
#region Punched Media
|
||||
|
||||
ApertureCard,
|
||||
JacquardLoomCard,
|
||||
MagneticStripeCard,
|
||||
OpticalPhonecard,
|
||||
PunchedCard,
|
||||
PunchedTape,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tape
|
||||
|
||||
Cassette,
|
||||
DataCartridge,
|
||||
OpenReel,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Disc / Disc
|
||||
|
||||
BluRay,
|
||||
CDROM,
|
||||
DVD,
|
||||
FloppyDisk,
|
||||
Floptical,
|
||||
GDROM,
|
||||
HDDVD,
|
||||
HardDisk,
|
||||
IomegaBernoulliDisk,
|
||||
IomegaJaz,
|
||||
IomegaZip,
|
||||
LaserDisc, // LD-ROM and LV-ROM variants
|
||||
Nintendo64DD,
|
||||
NintendoFamicomDiskSystem,
|
||||
NintendoGameCubeGameDisc,
|
||||
NintendoWiiOpticalDisc,
|
||||
NintendoWiiUOpticalDisc,
|
||||
UMD,
|
||||
|
||||
#endregion
|
||||
|
||||
// Unsorted Formats
|
||||
Cartridge,
|
||||
CED,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of all known Redump systems
|
||||
/// </summary>
|
||||
public enum RedumpSystem
|
||||
{
|
||||
// Special BIOS sets
|
||||
MicrosoftXboxBIOS,
|
||||
NintendoGameCubeBIOS,
|
||||
SonyPlayStationBIOS,
|
||||
SonyPlayStation2BIOS,
|
||||
|
||||
// Regular systems
|
||||
AcornArchimedes,
|
||||
AppleMacintosh,
|
||||
AudioCD,
|
||||
BDVideo,
|
||||
BandaiPippin,
|
||||
BandaiPlaydiaQuickInteractiveSystem,
|
||||
CommodoreAmigaCD,
|
||||
CommodoreAmigaCD32,
|
||||
CommodoreAmigaCDTV,
|
||||
DVDVideo,
|
||||
FujitsuFMTownsseries,
|
||||
HasbroVideoNow,
|
||||
HasbroVideoNowColor,
|
||||
HasbroVideoNowJr,
|
||||
HasbroVideoNowXP,
|
||||
IBMPCcompatible,
|
||||
IncredibleTechnologiesEagle,
|
||||
KonamiFireBeat,
|
||||
KonamiM2,
|
||||
KonamiSystem573,
|
||||
KonamiSystemGV,
|
||||
KonamiTwinkle,
|
||||
KonamieAmusement,
|
||||
MattelHyperScan,
|
||||
MemorexVisualInformationSystem,
|
||||
MicrosoftXbox,
|
||||
MicrosoftXbox360,
|
||||
MicrosoftXboxOne,
|
||||
NECPC88series,
|
||||
NECPC98series,
|
||||
NECPCEngineCDTurboGrafxCD,
|
||||
NECPCFXPCFXGA,
|
||||
NamcoSystem12,
|
||||
NamcoSystem246,
|
||||
NavisoftNaviken21,
|
||||
NinendoGameCube,
|
||||
NintendoWii,
|
||||
NintendoWiiU,
|
||||
PalmOS,
|
||||
Panasonic3DOInteractiveMultiplayer,
|
||||
PanasonicM2,
|
||||
PhilipsCDi,
|
||||
PhilipsCDiDigitalVideo,
|
||||
PhotoCD,
|
||||
PlayStationGameSharkUpdates,
|
||||
SegaChihiro,
|
||||
SegaDreamcast,
|
||||
SegaLindbergh,
|
||||
SegaMegaCDSegaCD,
|
||||
SegaNaomi,
|
||||
SegaNaomi2,
|
||||
SegaRingEdge,
|
||||
SegaRingEdge2,
|
||||
SegaSaturn,
|
||||
SegaTitanVideo,
|
||||
SegaTriforce,
|
||||
SharpX68000,
|
||||
SNKNeoGeoCD,
|
||||
SonyPlayStation,
|
||||
SonyPlayStation2,
|
||||
SonyPlayStation3,
|
||||
SonyPlayStation4,
|
||||
SonyPlayStationPortable,
|
||||
TABAustriaQuizard,
|
||||
TaoiKTV,
|
||||
TomyKissSite,
|
||||
VideoCD,
|
||||
VMLabsNUON,
|
||||
VTechVFlashVSmilePro,
|
||||
ZAPiTGamesGameWaveFamilyEntertainmentSystem,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of all known Redump regions
|
||||
/// </summary>
|
||||
public enum Region
|
||||
{
|
||||
Argentina,
|
||||
Asia,
|
||||
AsiaEurope,
|
||||
AsiaUSA,
|
||||
Australia,
|
||||
Austria,
|
||||
AustriaSwitzerland,
|
||||
Belgium,
|
||||
BelgiumNetherlands,
|
||||
Brazil,
|
||||
Canada,
|
||||
China,
|
||||
Croatia,
|
||||
Czech,
|
||||
Denmark,
|
||||
Europe,
|
||||
EuropeAsia,
|
||||
EuropeAustralia,
|
||||
Finland,
|
||||
France,
|
||||
FranceSpain,
|
||||
Germany,
|
||||
Greece,
|
||||
Hungary,
|
||||
India,
|
||||
Ireland,
|
||||
Israel,
|
||||
Italy,
|
||||
Japan,
|
||||
JapanAsia,
|
||||
JapanEurope,
|
||||
JapanKorea,
|
||||
JapanUSA,
|
||||
Korea,
|
||||
LatinAmerica,
|
||||
Netherlands,
|
||||
Norway,
|
||||
Poland,
|
||||
Portugal,
|
||||
Russia,
|
||||
Scandinavia,
|
||||
Singapore,
|
||||
Slovakia,
|
||||
SouthAfrica,
|
||||
Spain,
|
||||
Sweden,
|
||||
Switzerland,
|
||||
Taiwan,
|
||||
Thailand,
|
||||
Turkey,
|
||||
UnitedArabEmirates,
|
||||
UK,
|
||||
Ukraine,
|
||||
USA,
|
||||
USAAsia,
|
||||
USABrazil,
|
||||
USAEurope,
|
||||
USAJapan,
|
||||
World,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generic yes/no values for Redump
|
||||
/// </summary>
|
||||
public enum YesNo
|
||||
{
|
||||
NULL = 0,
|
||||
No = 1,
|
||||
Yes = 2,
|
||||
}
|
||||
}
|
||||
@@ -1,447 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using DICUI.Utilities;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace DICUI.Data
|
||||
{
|
||||
public class SubmissionInfo
|
||||
{
|
||||
#region Common disc info
|
||||
|
||||
// TODO: Name not defined
|
||||
[JsonProperty(PropertyName = "d_system", Required = Required.AllowNull)]
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public KnownSystem? System { get; set; }
|
||||
|
||||
// TODO: Name not defined
|
||||
[JsonProperty(PropertyName = "d_media", Required = Required.AllowNull)]
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public MediaType? Media { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_title", Required = Required.AllowNull)]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_title_foreign", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public string ForeignTitleNonLatin { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_number", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string DiscNumberLetter { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_label", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string DiscTitle { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_category", Required = Required.AllowNull)]
|
||||
public Category? Category { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_region", Required = Required.AllowNull)]
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public Region? Region { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_languages", Required = Required.AllowNull)]
|
||||
public Language?[] Languages { get; set; }
|
||||
|
||||
// "Bios settings", "Language selector", "Options menu"
|
||||
[JsonProperty(PropertyName = "d_languages_selection", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string[] LanguageSelection { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_serial", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Serial { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Ring { get; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_id", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string RingId { get; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_ma1", Required = Required.AllowNull)]
|
||||
public string MasteringRingFirstLayerDataSide { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_ma1_sid", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string MasteringSIDCodeFirstLayerDataSide { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_ts1", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string ToolstampMasteringCodeFirstLayerDataSide { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_mo1_sid", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string MouldSIDCodeFirstLayerDataSide { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "dr_ring_0_mo1", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string AdditionalMouldFirstLayerDataSide { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_ma2", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string MasteringRingSecondLayerLabelSide { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_ma2_sid", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string MasteringSIDCodeSecondLayerLabelSide { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_ts2", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string ToolstampMasteringCodeSecondLayerLabelSide { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_mo2_sid", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string MouldSIDCodeSecondLayerLabelSide { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "dr_ring_0_mo2", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string AdditionalMouldSecondLayerLabelSide { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_offsets", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string RingOffsetsHidden { get { return "1"; } }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_0_id", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string RingZeroId { get; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_0_density", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string RingZeroDensity { get; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_0_value", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string RingWriteOffset { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_count", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string RingCount { get { return "1"; } }
|
||||
|
||||
[JsonProperty(PropertyName = "d_barcode", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Barcode { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_date", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string EXEDateBuildDate { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_errors", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string ErrorsCount { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_comments", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Comments { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_contents", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Contents { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Version and Editions
|
||||
|
||||
[JsonProperty(PropertyName = "d_version", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Version { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_version_datfile", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string VersionDatfile { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_editions", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string[] CommonEditions { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_editions_text", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string OtherEditions { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region EDC (PSX-only)
|
||||
|
||||
[JsonProperty(PropertyName = "d_edc", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public YesNo EDC { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Parent/Clone relationship
|
||||
|
||||
[JsonProperty(PropertyName = "d_parent_id", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string ParentID { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_is_regional_parent", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public bool RegionalParent { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extras
|
||||
|
||||
[JsonProperty(PropertyName = "d_pvd", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string PVD { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_d1_key", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string DiscKey { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_d2_key", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string DiscID { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_pic_data", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string PIC { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_header", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Header { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_bca", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string BCA { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ssranges", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string SecuritySectorRanges { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Copy protection
|
||||
|
||||
[JsonProperty(PropertyName = "d_protection_a", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public YesNo AntiModchip { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_protection_1", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public YesNo LibCrypt { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_libcrypt", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string LibCryptData { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_protection", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Protection { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_securom", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string SecuROMData { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dumpers and Status (Moderator only)
|
||||
|
||||
[JsonProperty(PropertyName = "d_status", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public DumpStatus Status { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_dumpers", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string[] Dumpers { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_dumpers_text", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string OtherDumpers { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tracks and write offsets (CD,GD-baed)
|
||||
|
||||
[JsonProperty(PropertyName = "d_tracks", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string ClrMameProData { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_cue", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Cuesheet { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_offset", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public int[] CommonWriteOffsets { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_offset_text", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string OtherWriteOffsets { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Size & Checksum (DVD,BD,UMD-based)
|
||||
|
||||
[JsonProperty(PropertyName = "d_layerbreak", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public long Layerbreak { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_size", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public long Size { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_crc32", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string CRC32 { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_md5", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string MD5 { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_sha1", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string SHA1 { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nonstandard Information
|
||||
|
||||
[JsonIgnore]
|
||||
public List<int> MatchedIDs { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public DateTime? Added { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public DateTime? LastModified { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Regexes
|
||||
|
||||
private readonly Regex addedRegex = new Regex(@"<tr><th>Added</th><td>(.*?)</td></tr>");
|
||||
private readonly Regex barcodeRegex = new Regex(@"<tr><th>Barcode</th></tr><tr><td>(.*?)</td></tr>");
|
||||
private readonly Regex bcaRegex = new Regex(@"<h3>BCA .*?/></h3></td><td .*?></td></tr>"
|
||||
+ "<tr><th>Row</th><th>Contents</th><th>ASCII</th></tr>"
|
||||
+ "<tr><td>(?<row1number>.*?)</td><td>(?<row1contents>.*?)</td><td>(?<row1ascii>.*?)</td></tr>"
|
||||
+ "<tr><td>(?<row2number>.*?)</td><td>(?<row2contents>.*?)</td><td>(?<row2ascii>.*?)</td></tr>"
|
||||
+ "<tr><td>(?<row3number>.*?)</td><td>(?<row3contents>.*?)</td><td>(?<row3ascii>.*?)</td></tr>"
|
||||
+ "<tr><td>(?<row4number>.*?)</td><td>(?<row4contents>.*?)</td><td>(?<row4ascii>.*?)</td></tr>");
|
||||
private readonly Regex categoryRegex = new Regex(@"<tr><th>Category</th><td>(.*?)</td></tr>");
|
||||
private readonly Regex commentsRegex = new Regex(@"<tr><th>Comments</th></tr><tr><td>(.*?)</td></tr>");
|
||||
private readonly Regex contentsRegex = new Regex(@"<tr><th>Contents</th></tr><tr .*?><td>(.*?)</td></tr>");
|
||||
private readonly Regex discNumberLetterRegex = new Regex(@"\((.*?)\)");
|
||||
private readonly Regex dumpersRegex = new Regex(@"<a href=""/discs/dumper/(.*?)/"">");
|
||||
private readonly Regex editionRegex = new Regex(@"<tr><th>Edition</th><td>(.*?)</td></tr>");
|
||||
private readonly Regex errorCountRegex = new Regex(@"<tr><th>Errors count</th><td>(.*?)</td></tr>");
|
||||
private readonly Regex foreignTitleRegex = new Regex(@"<h2>(.*?)</h2>");
|
||||
private readonly Regex fullMatchRegex = new Regex(@"<td class=""static"">full match ids: (.*?)</td>");
|
||||
private readonly Regex languagesRegex = new Regex(@"<img src=""/images/languages/(.*?)\.png"" alt="".*?"" title="".*?"" />\s*");
|
||||
private readonly Regex lastModifiedRegex = new Regex(@"<tr><th>Last modified</th><td>(.*?)</td></tr>");
|
||||
private readonly Regex mediaRegex = new Regex(@"<tr><th>Media</th><td>(.*?)</td></tr>");
|
||||
private readonly Regex partialMatchRegex = new Regex(@"<td class=""static"">partial match ids: (.*?)</td>");
|
||||
private readonly Regex pvdRegex = new Regex(@"<h3>Primary Volume Descriptor (PVD) <img .*?/></h3></td><td .*?></td></tr>"
|
||||
+ @"<tr><th>Record / Entry</th><th>Contents</th><th>Date</th><th>Time</th><th>GMT</th></tr>"
|
||||
+ @"<tr><td>Creation</td><td>(?<creationbytes>.*?)</td><td>(?<creationdate>.*?)</td><td>(?<creationtime>.*?)</td><td>(?<creationtimezone>.*?)</td></tr>"
|
||||
+ @"<tr><td>Modification</td><td>(?<modificationbytes>.*?)</td><td>(?<modificationdate>.*?)</td><td>(?<modificationtime>.*?)</td><td>(?<modificationtimezone>.*?)</td></tr>"
|
||||
+ @"<tr><td>Expiration</td><td>(?<expirationbytes>.*?)</td><td>(?<expirationdate>.*?)</td><td>(?<expirationtime>.*?)</td><td>(?<expirationtimezone>.*?)</td></tr>"
|
||||
+ @"<tr><td>Effective</td><td>(?<effectivebytes>.*?)</td><td>(?<effectivedate>.*?)</td><td>(?<effectivetime>.*?)</td><td>(?<effectivetimezone>.*?)</td></tr>");
|
||||
private readonly Regex regionRegex = new Regex(@"<tr><th>Region</th><td><a href=""/discs/region/(.*?)/"">");
|
||||
private readonly Regex ringCodeDoubleRegex = new Regex(@""); // Varies based on available fields, like Addtional Mould
|
||||
private readonly Regex ringCodeSingleRegex = new Regex(@""); // Varies based on available fields, like Addtional Mould
|
||||
private readonly Regex serialRegex = new Regex(@"<tr><th>Serial</th><td>(.*?)</td></tr>");
|
||||
private readonly Regex systemRegex = new Regex(@"<tr><th>System</th><td><a href=""/discs/system/(.*?)/"">");
|
||||
private readonly Regex titleRegex = new Regex(@"<h1>(.*?)</h1>");
|
||||
private readonly Regex trackRegex = new Regex(@"<tr><td>(?<number>.*?)</td><td>(?<type>.*?)</td><td>(?<pregap>.*?)</td><td>(?<length>.*?)</td><td>(?<sectors>.*?)</td><td>(?<size>.*?)</td><td>(?<crc32>.*?)</td><td>(?<md5>.*?)</td><td>(?<sha1>.*?)</td></tr>");
|
||||
private readonly Regex trackCountRegex = new Regex(@"<tr><th>Number of tracks</th><td>(.*?)</td></tr>");
|
||||
private readonly Regex versionRegex = new Regex(@"<tr><th>Version</th><td>(.*?)</td></tr>");
|
||||
private readonly Regex writeOffsetRegex = new Regex(@"<tr><th>Write offset</th><td>(.*?)</td></tr>");
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Fill in information from a Redump disc page
|
||||
/// </summary>
|
||||
/// <param name="discData">String representation of the disc page</param>
|
||||
public void FillFromDiscPage(string discData)
|
||||
{
|
||||
// Title, Disc Number/Letter, Disc Title
|
||||
var match = titleRegex.Match(discData);
|
||||
if (match.Success)
|
||||
{
|
||||
string title = match.Groups[1].Value;
|
||||
|
||||
// If we have parenthesis, title is everything before the first one
|
||||
int firstParenLocation = title.IndexOf(" (");
|
||||
if (firstParenLocation >= 0)
|
||||
{
|
||||
this.Title = title.Substring(0, firstParenLocation);
|
||||
var subMatches = discNumberLetterRegex.Match(title);
|
||||
for (int i = 1; i < subMatches.Groups.Count; i++)
|
||||
{
|
||||
string subMatch = subMatches.Groups[i].Value;
|
||||
|
||||
// Disc number or letter
|
||||
if (subMatch.StartsWith("Disc"))
|
||||
this.DiscNumberLetter = subMatch.Remove(0, "Disc ".Length);
|
||||
|
||||
// Disc title
|
||||
else
|
||||
this.DiscTitle = subMatch;
|
||||
}
|
||||
}
|
||||
// Otherwise, leave the title as-is
|
||||
else
|
||||
{
|
||||
this.Title = title;
|
||||
}
|
||||
}
|
||||
|
||||
// Foreign Title
|
||||
match = foreignTitleRegex.Match(discData);
|
||||
if (match.Success)
|
||||
this.ForeignTitleNonLatin = match.Groups[1].Value;
|
||||
else
|
||||
this.ForeignTitleNonLatin = null;
|
||||
|
||||
// Category
|
||||
match = categoryRegex.Match(discData);
|
||||
if (match.Success)
|
||||
this.Category = Converters.StringToCategory(match.Groups[1].Value);
|
||||
else
|
||||
this.Category = Data.Category.Games;
|
||||
|
||||
// Region
|
||||
match = regionRegex.Match(discData);
|
||||
if (match.Success)
|
||||
this.Region = Converters.StringToRegion(match.Groups[1].Value);
|
||||
|
||||
// Languages
|
||||
var matches = languagesRegex.Matches(discData);
|
||||
if (matches.Count > 0)
|
||||
{
|
||||
List<Language?> tempLanguages = new List<Language?>();
|
||||
foreach (Match submatch in matches)
|
||||
tempLanguages.Add(Converters.StringToLanguage(submatch.Groups[1].Value));
|
||||
|
||||
this.Languages = tempLanguages.ToArray();
|
||||
}
|
||||
|
||||
// Serial
|
||||
match = serialRegex.Match(discData);
|
||||
if (match.Success)
|
||||
this.Serial = match.Groups[1].Value;
|
||||
|
||||
// Error count
|
||||
match = errorCountRegex.Match(discData);
|
||||
if (match.Success)
|
||||
{
|
||||
// If the error counts don't match, then use the one from the disc page
|
||||
if (!string.IsNullOrEmpty(this.ErrorsCount) && match.Groups[1].Value != this.ErrorsCount)
|
||||
this.ErrorsCount = match.Groups[1].Value;
|
||||
}
|
||||
|
||||
// Version
|
||||
match = versionRegex.Match(discData);
|
||||
if (match.Success)
|
||||
this.Version = match.Groups[1].Value;
|
||||
|
||||
// Edition
|
||||
match = editionRegex.Match(discData);
|
||||
if (match.Success)
|
||||
this.OtherEditions = match.Groups[1].Value;
|
||||
|
||||
// Dumpers
|
||||
matches = dumpersRegex.Matches(discData);
|
||||
if (matches.Count > 0)
|
||||
{
|
||||
// Start with any currently listed dumpers
|
||||
List<string> tempDumpers = new List<string>();
|
||||
if (this.Dumpers.Length > 0)
|
||||
{
|
||||
foreach (string dumper in this.Dumpers)
|
||||
tempDumpers.Add(dumper);
|
||||
}
|
||||
|
||||
foreach (Match submatch in matches)
|
||||
tempDumpers.Add(submatch.Groups[1].Value);
|
||||
|
||||
this.Dumpers = tempDumpers.ToArray();
|
||||
}
|
||||
|
||||
// Barcode
|
||||
match = barcodeRegex.Match(discData);
|
||||
if (match.Success)
|
||||
this.Barcode = match.Groups[1].Value;
|
||||
|
||||
// Comments
|
||||
match = commentsRegex.Match(discData);
|
||||
if (match.Success)
|
||||
{
|
||||
this.Comments = match.Groups[1].Value
|
||||
.Replace("<br />", "\n")
|
||||
.Replace("<b>ISBN</b>", "[T:ISBN]") + "\n";
|
||||
}
|
||||
|
||||
// Contents
|
||||
match = contentsRegex.Match(discData);
|
||||
if (match.Success)
|
||||
{
|
||||
this.Contents = match.Groups[1].Value
|
||||
.Replace("<br />", "\n")
|
||||
.Replace("</div>", "");
|
||||
this.Contents = Regex.Replace(this.Contents, @"<div .*?>", "");
|
||||
}
|
||||
|
||||
// Added
|
||||
match = addedRegex.Match(discData);
|
||||
if (match.Success)
|
||||
this.Added = DateTime.Parse(match.Groups[1].Value);
|
||||
|
||||
// Last Modified
|
||||
match = lastModifiedRegex.Match(discData);
|
||||
if (match.Success)
|
||||
this.LastModified = DateTime.Parse(match.Groups[1].Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("DICUI.Library")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("DICUI.Library")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2019")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("51ab0928-13f9-44bf-a407-b6957a43a056")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.13")]
|
||||
[assembly: AssemblyFileVersion("1.13.0.0")]
|
||||
[assembly: InternalsVisibleTo("DICUI.Test")]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,52 +0,0 @@
|
||||
namespace DICUI.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents information for a single drive
|
||||
/// </summary>
|
||||
public class Drive
|
||||
{
|
||||
/// <summary>
|
||||
/// Windows drive letter
|
||||
/// </summary>
|
||||
public char Letter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Represents if it is a floppy drive
|
||||
/// </summary>
|
||||
public bool IsFloppy { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Media label as read by Windows
|
||||
/// </summary>
|
||||
public string VolumeLabel { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Represents if Windows has marked the drive as active
|
||||
/// </summary>
|
||||
public bool MarkedActive { get; private set; }
|
||||
|
||||
private Drive(char letter, string volumeLabel, bool isFloppy, bool markedActive)
|
||||
{
|
||||
this.Letter = letter;
|
||||
this.IsFloppy = isFloppy;
|
||||
this.VolumeLabel = volumeLabel;
|
||||
this.MarkedActive = markedActive;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new Floppy drive instance
|
||||
/// </summary>
|
||||
/// <param name="letter">Drive letter to use</param>
|
||||
/// <returns>Drive object for a Floppy drive</returns>
|
||||
public static Drive Floppy(char letter) => new Drive(letter, null, true, true);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new Optical drive instance
|
||||
/// </summary>
|
||||
/// <param name="letter">Drive letter to use</param>
|
||||
/// <param name="volumeLabel">Media label, if it exists</param>
|
||||
/// <param name="active">True if the drive is marked active, false otherwise</param>
|
||||
/// <returns>Drive object for an Optical drive</returns>
|
||||
public static Drive Optical(char letter, string volumeLabel, bool active) => new Drive(letter, volumeLabel, false, active);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,252 +0,0 @@
|
||||
using DICUI.Data;
|
||||
|
||||
namespace DICUI.Utilities
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
#region Redump Information Lists
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that are not publically accessible
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem[] BannedSystems = new RedumpSystem[]
|
||||
{
|
||||
RedumpSystem.AudioCD,
|
||||
RedumpSystem.BDVideo,
|
||||
RedumpSystem.DVDVideo,
|
||||
RedumpSystem.HasbroVideoNow,
|
||||
RedumpSystem.HasbroVideoNowColor,
|
||||
RedumpSystem.HasbroVideoNowJr,
|
||||
RedumpSystem.HasbroVideoNowXP,
|
||||
RedumpSystem.KonamiM2,
|
||||
RedumpSystem.MicrosoftXbox360,
|
||||
RedumpSystem.MicrosoftXboxOne,
|
||||
RedumpSystem.NavisoftNaviken21,
|
||||
RedumpSystem.NintendoWii,
|
||||
RedumpSystem.NintendoWiiU,
|
||||
RedumpSystem.PanasonicM2,
|
||||
RedumpSystem.PhilipsCDiDigitalVideo,
|
||||
RedumpSystem.SegaRingEdge,
|
||||
RedumpSystem.SegaRingEdge2,
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
RedumpSystem.SonyPlayStation4,
|
||||
RedumpSystem.VideoCD,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that have a Cues pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem[] HasCues = new RedumpSystem[]
|
||||
{
|
||||
RedumpSystem.AppleMacintosh,
|
||||
RedumpSystem.AudioCD,
|
||||
RedumpSystem.BandaiPippin,
|
||||
RedumpSystem.BandaiPlaydiaQuickInteractiveSystem,
|
||||
RedumpSystem.CommodoreAmigaCD,
|
||||
RedumpSystem.CommodoreAmigaCD32,
|
||||
RedumpSystem.CommodoreAmigaCDTV,
|
||||
RedumpSystem.FujitsuFMTownsseries,
|
||||
RedumpSystem.HasbroVideoNow,
|
||||
RedumpSystem.HasbroVideoNowJr,
|
||||
RedumpSystem.IBMPCcompatible,
|
||||
RedumpSystem.IncredibleTechnologiesEagle,
|
||||
RedumpSystem.KonamieAmusement,
|
||||
RedumpSystem.KonamiFireBeat,
|
||||
RedumpSystem.KonamiM2,
|
||||
RedumpSystem.KonamiSystemGV,
|
||||
RedumpSystem.MattelHyperScan,
|
||||
RedumpSystem.MicrosoftXbox,
|
||||
RedumpSystem.MicrosoftXbox360,
|
||||
RedumpSystem.NamcoSystem246,
|
||||
RedumpSystem.NavisoftNaviken21,
|
||||
RedumpSystem.NECPC88series,
|
||||
RedumpSystem.NECPC98series,
|
||||
RedumpSystem.NECPCEngineCDTurboGrafxCD,
|
||||
RedumpSystem.NECPCFXPCFXGA,
|
||||
RedumpSystem.PalmOS,
|
||||
RedumpSystem.Panasonic3DOInteractiveMultiplayer,
|
||||
RedumpSystem.PanasonicM2,
|
||||
RedumpSystem.PhilipsCDi,
|
||||
RedumpSystem.PhilipsCDiDigitalVideo,
|
||||
RedumpSystem.PhotoCD,
|
||||
RedumpSystem.PlayStationGameSharkUpdates,
|
||||
RedumpSystem.SegaChihiro,
|
||||
RedumpSystem.SegaDreamcast,
|
||||
RedumpSystem.SegaMegaCDSegaCD,
|
||||
RedumpSystem.SegaNaomi,
|
||||
RedumpSystem.SegaNaomi2,
|
||||
RedumpSystem.SegaSaturn,
|
||||
RedumpSystem.SegaTriforce,
|
||||
RedumpSystem.SNKNeoGeoCD,
|
||||
RedumpSystem.SonyPlayStation,
|
||||
RedumpSystem.SonyPlayStation2,
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
RedumpSystem.TABAustriaQuizard,
|
||||
RedumpSystem.TomyKissSite,
|
||||
RedumpSystem.VideoCD,
|
||||
RedumpSystem.VTechVFlashVSmilePro,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that has a Dat pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem[] HasDat = new RedumpSystem[]
|
||||
{
|
||||
RedumpSystem.MicrosoftXboxBIOS,
|
||||
RedumpSystem.NintendoGameCubeBIOS,
|
||||
RedumpSystem.SonyPlayStationBIOS,
|
||||
RedumpSystem.SonyPlayStation2BIOS,
|
||||
|
||||
RedumpSystem.AppleMacintosh,
|
||||
RedumpSystem.AudioCD,
|
||||
RedumpSystem.BDVideo,
|
||||
RedumpSystem.BandaiPippin,
|
||||
RedumpSystem.BandaiPlaydiaQuickInteractiveSystem,
|
||||
RedumpSystem.CommodoreAmigaCD,
|
||||
RedumpSystem.CommodoreAmigaCD32,
|
||||
RedumpSystem.CommodoreAmigaCDTV,
|
||||
RedumpSystem.DVDVideo,
|
||||
RedumpSystem.FujitsuFMTownsseries,
|
||||
RedumpSystem.HasbroVideoNow,
|
||||
RedumpSystem.HasbroVideoNowJr,
|
||||
RedumpSystem.IBMPCcompatible,
|
||||
RedumpSystem.IncredibleTechnologiesEagle,
|
||||
RedumpSystem.KonamiFireBeat,
|
||||
RedumpSystem.KonamiM2,
|
||||
RedumpSystem.KonamiSystemGV,
|
||||
RedumpSystem.KonamieAmusement,
|
||||
RedumpSystem.MattelHyperScan,
|
||||
RedumpSystem.MicrosoftXbox,
|
||||
RedumpSystem.MicrosoftXbox360,
|
||||
RedumpSystem.MicrosoftXboxOne,
|
||||
RedumpSystem.NamcoSystem246,
|
||||
RedumpSystem.NavisoftNaviken21,
|
||||
RedumpSystem.NECPC88series,
|
||||
RedumpSystem.NECPC98series,
|
||||
RedumpSystem.NECPCEngineCDTurboGrafxCD,
|
||||
RedumpSystem.NECPCFXPCFXGA,
|
||||
RedumpSystem.NinendoGameCube,
|
||||
RedumpSystem.NintendoWii,
|
||||
RedumpSystem.NintendoWiiU,
|
||||
RedumpSystem.PalmOS,
|
||||
RedumpSystem.Panasonic3DOInteractiveMultiplayer,
|
||||
RedumpSystem.PanasonicM2,
|
||||
RedumpSystem.PhilipsCDi,
|
||||
RedumpSystem.PhilipsCDiDigitalVideo,
|
||||
RedumpSystem.PhotoCD,
|
||||
RedumpSystem.PlayStationGameSharkUpdates,
|
||||
RedumpSystem.SegaChihiro,
|
||||
RedumpSystem.SegaDreamcast,
|
||||
RedumpSystem.SegaLindbergh,
|
||||
RedumpSystem.SegaMegaCDSegaCD,
|
||||
RedumpSystem.SegaNaomi,
|
||||
RedumpSystem.SegaNaomi2,
|
||||
RedumpSystem.SegaRingEdge,
|
||||
RedumpSystem.SegaRingEdge2,
|
||||
RedumpSystem.SegaSaturn,
|
||||
RedumpSystem.SegaTriforce,
|
||||
RedumpSystem.SNKNeoGeoCD,
|
||||
RedumpSystem.SonyPlayStation,
|
||||
RedumpSystem.SonyPlayStation2,
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
RedumpSystem.SonyPlayStation4,
|
||||
RedumpSystem.SonyPlayStationPortable,
|
||||
RedumpSystem.TABAustriaQuizard,
|
||||
RedumpSystem.TomyKissSite,
|
||||
RedumpSystem.VideoCD,
|
||||
RedumpSystem.VMLabsNUON,
|
||||
RedumpSystem.VTechVFlashVSmilePro,
|
||||
RedumpSystem.ZAPiTGamesGameWaveFamilyEntertainmentSystem,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that has a Decrypted Keys pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem[] HasDkeys = new RedumpSystem[]
|
||||
{
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that has a GDI pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem[] HasGdi = new RedumpSystem[]
|
||||
{
|
||||
RedumpSystem.SegaChihiro,
|
||||
RedumpSystem.SegaDreamcast,
|
||||
RedumpSystem.SegaNaomi,
|
||||
RedumpSystem.SegaNaomi2,
|
||||
RedumpSystem.SegaTriforce,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that has a Keys pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem[] HasKeys = new RedumpSystem[]
|
||||
{
|
||||
RedumpSystem.NintendoWiiU,
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that has an SBI pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem[] HasSbi = new RedumpSystem[]
|
||||
{
|
||||
RedumpSystem.IBMPCcompatible,
|
||||
RedumpSystem.SonyPlayStation,
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
public static bool DoesSupportDriveSpeed(this MediaType? type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
case MediaType.DVD:
|
||||
case MediaType.GDROM:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.BluRay:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static KnownSystemCategory Category(this KnownSystem? system)
|
||||
{
|
||||
if (system < KnownSystem.MarkerDiscBasedConsoleEnd)
|
||||
return KnownSystemCategory.DiscBasedConsole;
|
||||
/*
|
||||
else if (system < KnownSystem.MarkerOtherConsoleEnd)
|
||||
return KnownSystemCategory.OtherConsole;
|
||||
*/
|
||||
else if (system < KnownSystem.MarkerComputerEnd)
|
||||
return KnownSystemCategory.Computer;
|
||||
else if (system < KnownSystem.MarkerArcadeEnd)
|
||||
return KnownSystemCategory.Arcade;
|
||||
else if (system < KnownSystem.MarkerOtherEnd)
|
||||
return KnownSystemCategory.Other;
|
||||
else
|
||||
return KnownSystemCategory.Custom;
|
||||
}
|
||||
|
||||
public static bool IsMarker(this KnownSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case KnownSystem.MarkerArcadeEnd:
|
||||
case KnownSystem.MarkerComputerEnd:
|
||||
case KnownSystem.MarkerDiscBasedConsoleEnd:
|
||||
// case KnownSystem.MarkerOtherConsoleEnd:
|
||||
case KnownSystem.MarkerOtherEnd:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,939 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Management;
|
||||
using System.Threading.Tasks;
|
||||
using BurnOutSharp;
|
||||
using IMAPI2;
|
||||
using DICUI.Data;
|
||||
|
||||
namespace DICUI.Utilities
|
||||
{
|
||||
public static class Validators
|
||||
{
|
||||
/// <summary>
|
||||
/// Get a list of valid MediaTypes for a given KnownSystem
|
||||
/// </summary>
|
||||
/// <param name="sys">KnownSystem value to check</param>
|
||||
/// <returns>MediaTypes, if possible</returns>
|
||||
public static List<MediaType?> GetValidMediaTypes(KnownSystem? sys)
|
||||
{
|
||||
var types = new List<MediaType?>();
|
||||
|
||||
switch (sys)
|
||||
{
|
||||
#region Consoles
|
||||
|
||||
// https://en.wikipedia.org/wiki/Atari_Jaguar_CD
|
||||
case KnownSystem.AtariJaguarCD:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Playdia
|
||||
case KnownSystem.BandaiPlaydiaQuickInteractiveSystem:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Apple_Bandai_Pippin
|
||||
case KnownSystem.BandaiApplePippin:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Amiga_CD32
|
||||
case KnownSystem.CommodoreAmigaCD32:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Commodore_CDTV
|
||||
case KnownSystem.CommodoreAmigaCDTV:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/EVO_Smart_Console
|
||||
case KnownSystem.EnvizionsEVOSmartConsole:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/FM_Towns_Marty
|
||||
case KnownSystem.FujitsuFMTownsMarty:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.FloppyDisk);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/VideoNow
|
||||
case KnownSystem.HasbroVideoNow:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/VideoNow
|
||||
case KnownSystem.HasbroVideoNowColor:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/VideoNow
|
||||
case KnownSystem.HasbroVideoNowJr:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/VideoNow
|
||||
case KnownSystem.HasbroVideoNowXP:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/HyperScan
|
||||
case KnownSystem.MattelHyperscan:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Xbox_(console)
|
||||
case KnownSystem.MicrosoftXBOX:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Xbox_360
|
||||
case KnownSystem.MicrosoftXBOX360:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Xbox_One
|
||||
case KnownSystem.MicrosoftXBOXOne:
|
||||
types.Add(MediaType.BluRay);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/TurboGrafx-16
|
||||
case KnownSystem.NECPCEngineTurboGrafxCD:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/PC-FX
|
||||
case KnownSystem.NECPCFX:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/GameCube
|
||||
case KnownSystem.NintendoGameCube:
|
||||
types.Add(MediaType.NintendoGameCubeGameDisc);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Super_NES_CD-ROM
|
||||
case KnownSystem.NintendoSonySuperNESCDROMSystem:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Wii
|
||||
case KnownSystem.NintendoWii:
|
||||
types.Add(MediaType.NintendoWiiOpticalDisc);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Wii_U
|
||||
case KnownSystem.NintendoWiiU:
|
||||
types.Add(MediaType.NintendoWiiUOpticalDisc);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/3DO_Interactive_Multiplayer
|
||||
case KnownSystem.Panasonic3DOInteractiveMultiplayer:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Philips_CD-i
|
||||
case KnownSystem.PhilipsCDi:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/LaserActive
|
||||
case KnownSystem.PioneerLaserActive:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.LaserDisc);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Sega_CD
|
||||
case KnownSystem.SegaCDMegaCD:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Dreamcast
|
||||
case KnownSystem.SegaDreamcast:
|
||||
types.Add(MediaType.CDROM); // Low density partition, MIL-CD
|
||||
types.Add(MediaType.GDROM); // High density partition
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Sega_Saturn
|
||||
case KnownSystem.SegaSaturn:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Neo_Geo_CD
|
||||
case KnownSystem.SNKNeoGeoCD:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/PlayStation_(console)
|
||||
case KnownSystem.SonyPlayStation:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/PlayStation_2
|
||||
case KnownSystem.SonyPlayStation2:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/PlayStation_3
|
||||
case KnownSystem.SonyPlayStation3:
|
||||
types.Add(MediaType.BluRay);
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/PlayStation_4
|
||||
case KnownSystem.SonyPlayStation4:
|
||||
types.Add(MediaType.BluRay);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/PlayStation_Portable
|
||||
case KnownSystem.SonyPlayStationPortable:
|
||||
types.Add(MediaType.UMD);
|
||||
types.Add(MediaType.CDROM); // Development discs only
|
||||
types.Add(MediaType.DVD); // Development discs only
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Tandy_Video_Information_System
|
||||
case KnownSystem.TandyMemorexVisualInformationSystem:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Nuon_(DVD_technology)
|
||||
case KnownSystem.VMLabsNuon:
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/V.Flash
|
||||
case KnownSystem.VTechVFlashVSmilePro:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Game_Wave_Family_Entertainment_System
|
||||
case KnownSystem.ZAPiTGamesGameWaveFamilyEntertainmentSystem:
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Computers
|
||||
|
||||
// https://en.wikipedia.org/wiki/Acorn_Archimedes
|
||||
case KnownSystem.AcornArchimedes:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.FloppyDisk);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Macintosh
|
||||
case KnownSystem.AppleMacintosh:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
types.Add(MediaType.FloppyDisk);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Amiga
|
||||
case KnownSystem.CommodoreAmiga:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.FloppyDisk);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/FM_Towns
|
||||
case KnownSystem.FujitsuFMTowns:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/IBM_PC_compatible
|
||||
case KnownSystem.IBMPCCompatible:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
types.Add(MediaType.FloppyDisk);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/PC-8800_series
|
||||
case KnownSystem.NECPC88:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.FloppyDisk);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/PC-9800_series
|
||||
case KnownSystem.NECPC98:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
types.Add(MediaType.FloppyDisk);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/X68000
|
||||
case KnownSystem.SharpX68000:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.FloppyDisk);
|
||||
break;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Arcade
|
||||
|
||||
// https://www.bigbookofamigahardware.com/bboah/product.aspx?id=36
|
||||
case KnownSystem.AmigaCUBOCD32:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Orbatak
|
||||
case KnownSystem.AmericanLaserGames3DO:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=779
|
||||
case KnownSystem.Atari3DO:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// http://newlifegames.net/nlg/index.php?topic=22003.0
|
||||
// http://newlifegames.net/nlg/index.php?topic=5486.msg119440
|
||||
case KnownSystem.Atronic:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// https://www.arcade-museum.com/members/member_detail.php?member_id=406530
|
||||
case KnownSystem.AUSCOMSystem1:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// http://newlifegames.net/nlg/index.php?topic=285.0
|
||||
case KnownSystem.BallyGameMagic:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/CP_System_III
|
||||
case KnownSystem.CapcomCPSystemIII:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// UNKNOWN
|
||||
case KnownSystem.GlobalVRVarious:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://service.globalvr.com/troubleshooting/vortek.html
|
||||
case KnownSystem.GlobalVRVortek:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://service.globalvr.com/downloads/v3/040-1001-01c-V3-System-Manual.pdf
|
||||
case KnownSystem.GlobalVRVortekV3:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://www.icegame.com/games
|
||||
case KnownSystem.ICEPCHardware:
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// https://github.com/mamedev/mame/blob/master/src/mame/drivers/iteagle.cpp
|
||||
case KnownSystem.IncredibleTechnologiesEagle:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// UNKNOWN
|
||||
case KnownSystem.IncredibleTechnologiesVarious:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/E-Amusement
|
||||
case KnownSystem.KonamieAmusement:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=828
|
||||
case KnownSystem.KonamiFirebeat:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=577
|
||||
case KnownSystem.KonamiGVSystem:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=575
|
||||
case KnownSystem.KonamiM2:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=586
|
||||
// http://system16.com/hardware.php?id=977
|
||||
case KnownSystem.KonamiPython:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=976
|
||||
// http://system16.com/hardware.php?id=831
|
||||
case KnownSystem.KonamiPython2:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=582
|
||||
// http://system16.com/hardware.php?id=822
|
||||
// http://system16.com/hardware.php?id=823
|
||||
case KnownSystem.KonamiSystem573:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=827
|
||||
case KnownSystem.KonamiTwinkle:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// UNKNOWN
|
||||
case KnownSystem.KonamiVarious:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// http://www.meritgames.com/Support_Center/manuals/PM0591-01.pdf
|
||||
case KnownSystem.MeritIndustriesBoardwalk:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// http://www.meritgames.com/Support_Center/Force%20Elite/PM0380-09.pdf
|
||||
// http://www.meritgames.com/Support_Center/Force%20Upright/PM0382-07%20FORCE%20Upright%20manual.pdf
|
||||
// http://www.meritgames.com/Support_Center/Force%20Upright/PM0383-07%20FORCE%20Upright%20manual.pdf
|
||||
case KnownSystem.MeritIndustriesMegaTouchForce:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// http://www.meritgames.com/Service%20Center/Ion%20Troubleshooting.pdf
|
||||
case KnownSystem.MeritIndustriesMegaTouchION:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// http://www.meritgames.com/Support_Center/EZ%20Maxx/Manuals/MAXX%20Elite%20with%20coin.pdf
|
||||
// http://www.meritgames.com/Support_Center/EZ%20Maxx/Manuals/MAXX%20Elite.pdf
|
||||
// http://www.meritgames.com/Support_Center/manuals/90003010%20Maxx%20TSM_Rev%20C.pdf
|
||||
case KnownSystem.MeritIndustriesMegaTouchMaxx:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// http://www.meritgames.com/Support_Center/manuals/pm0076_OA_Megatouch%20XL%20Trouble%20Shooting%20Manual.pdf
|
||||
// http://www.meritgames.com/Support_Center/MEGA%20XL/manuals/Megatouch_XL_pm0109-0D.pdf
|
||||
// http://www.meritgames.com/Support_Center/MEGA%20XL/manuals/Megatouch_XL_Super_5000_manual.pdf
|
||||
case KnownSystem.MeritIndustriesMegaTouchXL:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=546
|
||||
// http://system16.com/hardware.php?id=872
|
||||
case KnownSystem.NamcoCapcomSystem256:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=543
|
||||
case KnownSystem.NamcoCapcomTaitoSystem246:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=545
|
||||
case KnownSystem.NamcoSegaNintendoTriforce:
|
||||
types.Add(MediaType.CDROM); // Low density partition
|
||||
types.Add(MediaType.GDROM); // High density partition
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=535
|
||||
case KnownSystem.NamcoSystem12:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=900
|
||||
case KnownSystem.NamcoSystem357:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
types.Add(MediaType.BluRay);
|
||||
break;
|
||||
|
||||
// https://www.arcade-history.com/?n=the-yakyuuken-part-1&page=detail&id=33049
|
||||
case KnownSystem.NewJatreCDi:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// http://blog.system11.org/?p=2499
|
||||
case KnownSystem.NichibutsuHighRateSystem:
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// http://blog.system11.org/?p=2514
|
||||
case KnownSystem.NichibutsuSuperCD:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// http://collectedit.com/collectors/shou-time-213/arcade-pcbs-281/x-rate-dvd-series-17-newlywed-life-japan-by-nichibutsu-32245
|
||||
case KnownSystem.NichibutsuXRateSystem:
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Panasonic_M2
|
||||
case KnownSystem.PanasonicM2:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// https://github.com/mamedev/mame/blob/master/src/mame/drivers/photoply.cpp
|
||||
case KnownSystem.PhotoPlayVarious:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// UNKNOWN
|
||||
case KnownSystem.RawThrillsVarious:
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=729
|
||||
case KnownSystem.SegaChihiro:
|
||||
types.Add(MediaType.CDROM); // Low density partition
|
||||
types.Add(MediaType.GDROM); // High density partition
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=907
|
||||
case KnownSystem.SegaEuropaR:
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=985
|
||||
// http://system16.com/hardware.php?id=731
|
||||
// http://system16.com/hardware.php?id=984
|
||||
// http://system16.com/hardware.php?id=986
|
||||
case KnownSystem.SegaLindbergh:
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=721
|
||||
// http://system16.com/hardware.php?id=723
|
||||
// http://system16.com/hardware.php?id=906
|
||||
// http://system16.com/hardware.php?id=722
|
||||
case KnownSystem.SegaNaomi:
|
||||
types.Add(MediaType.CDROM); // Low density partition
|
||||
types.Add(MediaType.GDROM); // High density partition
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=725
|
||||
// http://system16.com/hardware.php?id=726
|
||||
// http://system16.com/hardware.php?id=727
|
||||
case KnownSystem.SegaNaomi2:
|
||||
types.Add(MediaType.CDROM); // Low density partition
|
||||
types.Add(MediaType.GDROM); // High density partition
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=975
|
||||
// https://en.wikipedia.org/wiki/List_of_Sega_arcade_system_boards#Sega_Nu
|
||||
case KnownSystem.SegaNu:
|
||||
types.Add(MediaType.BluRay);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=910
|
||||
// https://en.wikipedia.org/wiki/List_of_Sega_arcade_system_boards#Sega_Ring_series
|
||||
case KnownSystem.SegaRingEdge:
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=982
|
||||
// https://en.wikipedia.org/wiki/List_of_Sega_arcade_system_boards#Sega_Ring_series
|
||||
case KnownSystem.SegaRingEdge2:
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=911
|
||||
// https://en.wikipedia.org/wiki/List_of_Sega_arcade_system_boards#Sega_Ring_series
|
||||
case KnownSystem.SegaRingWide:
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=711
|
||||
case KnownSystem.SegaTitanVideo:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// http://system16.com/hardware.php?id=709
|
||||
// http://system16.com/hardware.php?id=710
|
||||
case KnownSystem.SegaSystem32:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://github.com/mamedev/mame/blob/master/src/mame/drivers/seibucats.cpp
|
||||
case KnownSystem.SeibuCATSSystem:
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// https://www.tab.at/en/support/support/downloads
|
||||
case KnownSystem.TABAustriaQuizard:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://primetimeamusements.com/product/tsumo-multi-game-motion-system/
|
||||
// https://www.highwaygames.com/arcade-machines/tsumo-tsunami-motion-8117/
|
||||
case KnownSystem.TsunamiTsuMoMultiGameMotionSystem:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Others
|
||||
|
||||
// https://en.wikipedia.org/wiki/Audio_CD
|
||||
case KnownSystem.AudioCD:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Blu-ray#Player_profiles
|
||||
case KnownSystem.BDVideo:
|
||||
types.Add(MediaType.BluRay);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/DVD-Video
|
||||
case KnownSystem.DVDVideo:
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Blue_Book_(CD_standard)
|
||||
case KnownSystem.EnhancedCD:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/HD_DVD
|
||||
case KnownSystem.HDDVDVideo:
|
||||
types.Add(MediaType.HDDVD);
|
||||
break;
|
||||
|
||||
// UNKNOWN
|
||||
case KnownSystem.NavisoftNaviken21:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// UNKNOWN
|
||||
case KnownSystem.PalmOS:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// UNKNOWN
|
||||
case KnownSystem.PhilipsCDiDigitalVideo:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Photo_CD
|
||||
case KnownSystem.PhotoCD:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// UNKNOWN
|
||||
case KnownSystem.PlayStationGameSharkUpdates:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Doors_and_Windows_(EP)
|
||||
case KnownSystem.RainbowDisc:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Super_Audio_CD
|
||||
case KnownSystem.SuperAudioCD:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://www.cnet.com/products/tao-music-iktv-karaoke-station-karaoke-system-series/
|
||||
case KnownSystem.TaoiKTV:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// http://ultimateconsoledatabase.com/golden/kiss_site.htm
|
||||
case KnownSystem.TomyKissSite:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Video_CD
|
||||
case KnownSystem.VideoCD:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
#endregion
|
||||
|
||||
case KnownSystem.NONE:
|
||||
default:
|
||||
types.Add(MediaType.NONE);
|
||||
break;
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a list of systems
|
||||
/// </summary>
|
||||
/// <returns>KnownSystems, if possible</returns>
|
||||
public static List<KnownSystem?> CreateListOfSystems()
|
||||
{
|
||||
return Enum.GetValues(typeof(KnownSystem))
|
||||
.OfType<KnownSystem?>()
|
||||
.Where(s => !s.IsMarker() && s != KnownSystem.NONE)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a list of active drives matched to their volume labels
|
||||
/// </summary>
|
||||
/// <returns>Active drives, matched to labels, if possible</returns>
|
||||
/// <remarks>
|
||||
/// https://stackoverflow.com/questions/3060796/how-to-distinguish-between-usb-and-floppy-devices?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
|
||||
/// https://msdn.microsoft.com/en-us/library/aa394173(v=vs.85).aspx
|
||||
/// </remarks>
|
||||
public static List<Drive> CreateListOfDrives()
|
||||
{
|
||||
var drives = new List<Drive>();
|
||||
|
||||
// Get the floppy drives
|
||||
try
|
||||
{
|
||||
ManagementObjectSearcher searcher =
|
||||
new ManagementObjectSearcher("root\\CIMV2",
|
||||
"SELECT * FROM Win32_LogicalDisk");
|
||||
|
||||
var collection = searcher.Get();
|
||||
foreach (ManagementObject queryObj in collection)
|
||||
{
|
||||
uint? mediaType = (uint?)queryObj["MediaType"];
|
||||
if (mediaType != null && ((mediaType > 0 && mediaType < 11) || (mediaType > 12 && mediaType < 22)))
|
||||
{
|
||||
char devId = queryObj["DeviceID"].ToString()[0];
|
||||
drives.Add(Drive.Floppy(devId));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
|
||||
// Get the optical disc drives
|
||||
List<Drive> discDrives = DriveInfo.GetDrives()
|
||||
.Where(d => d.DriveType == DriveType.CDRom)
|
||||
.Select(d => Drive.Optical(d.Name[0], (d.IsReady ? (string.IsNullOrWhiteSpace(d.VolumeLabel) ? "disc" : d.VolumeLabel) : Template.DiscNotDetected), d.IsReady))
|
||||
.ToList();
|
||||
|
||||
// Add the two lists together and order
|
||||
drives.AddRange(discDrives);
|
||||
drives = drives.OrderBy(i => i.Letter).ToList();
|
||||
|
||||
return drives;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current media type from drive letter
|
||||
/// </summary>
|
||||
/// <param name="driveLetter"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// https://stackoverflow.com/questions/11420365/detecting-if-disc-is-in-dvd-drive
|
||||
/// </remarks>
|
||||
public static MediaType? GetMediaType(char? driveLetter)
|
||||
{
|
||||
// Get the DeviceID from the current drive letter
|
||||
string deviceId = null;
|
||||
try
|
||||
{
|
||||
ManagementObjectSearcher searcher =
|
||||
new ManagementObjectSearcher("root\\CIMV2",
|
||||
"SELECT * FROM Win32_CDROMDrive WHERE Id = '" + driveLetter + ":\'");
|
||||
|
||||
var collection = searcher.Get();
|
||||
foreach (ManagementObject queryObj in collection)
|
||||
deviceId = (string)queryObj["DeviceID"];
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error was
|
||||
return null;
|
||||
}
|
||||
|
||||
// If we got no valid device, we don't care and just return
|
||||
if (deviceId == null)
|
||||
return null;
|
||||
|
||||
// Get all relevant disc information
|
||||
try
|
||||
{
|
||||
MsftDiscMaster2 discMaster = new MsftDiscMaster2();
|
||||
deviceId = deviceId.ToLower().Replace('\\', '#');
|
||||
string id = null;
|
||||
foreach (var disc in discMaster)
|
||||
{
|
||||
if (disc.ToString().Contains(deviceId))
|
||||
id = disc.ToString();
|
||||
}
|
||||
|
||||
// If we couldn't find the drive, we don't care and return
|
||||
if (id == null)
|
||||
return null;
|
||||
|
||||
// Otherwise, we get the media type, if any
|
||||
MsftDiscRecorder2 recorder = new MsftDiscRecorder2();
|
||||
recorder.InitializeDiscRecorder(id);
|
||||
MsftDiscFormat2Data dataWriter = new MsftDiscFormat2Data();
|
||||
dataWriter.Recorder = recorder;
|
||||
var media = dataWriter.CurrentPhysicalMediaType;
|
||||
if (media != IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_UNKNOWN)
|
||||
return Converters.ToMediaType(media);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error is
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current system from drive letter
|
||||
/// </summary>
|
||||
/// <param name="driveLetter"></param>
|
||||
/// <returns></returns>
|
||||
public static KnownSystem? GetKnownSystem(char? driveLetter)
|
||||
{
|
||||
// If no letter is provided, then we can't do anything
|
||||
if (driveLetter == null)
|
||||
return null;
|
||||
|
||||
string drivePath = $"{driveLetter}:\\";
|
||||
|
||||
// If we can't read the media in that drive, we can't do anything
|
||||
if (!Directory.Exists(drivePath))
|
||||
return null;
|
||||
|
||||
// Sega Dreamcast
|
||||
if (File.Exists(Path.Combine(drivePath, "IP.BIN")))
|
||||
{
|
||||
return KnownSystem.SegaDreamcast;
|
||||
}
|
||||
|
||||
// Sega Mega-CD / Sega-CD
|
||||
if (File.Exists(Path.Combine(drivePath, "_BOOT", "IP.BIN"))
|
||||
|| File.Exists(Path.Combine(drivePath, "_BOOT", "SP.BIN"))
|
||||
|| File.Exists(Path.Combine(drivePath, "_BOOT", "SP_AS.BIN"))
|
||||
|| File.Exists(Path.Combine(drivePath, "FILESYSTEM.BIN")))
|
||||
{
|
||||
return KnownSystem.SegaCDMegaCD;
|
||||
}
|
||||
|
||||
// Sony PlayStation and Sony PlayStation 2
|
||||
if (File.Exists(Path.Combine(drivePath, "SYSTEM.CNF")))
|
||||
{
|
||||
// Check for either BOOT or BOOT2
|
||||
using (StreamReader reader = File.OpenText(Path.Combine(drivePath, "SYSTEM.CNF")))
|
||||
{
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
string line = reader.ReadLine();
|
||||
if (line.Contains("BOOT2"))
|
||||
return KnownSystem.SonyPlayStation2;
|
||||
else if (line.Contains("BOOT"))
|
||||
return KnownSystem.SonyPlayStation;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a weird disc, just assume PS1
|
||||
return KnownSystem.SonyPlayStation;
|
||||
}
|
||||
|
||||
// Sony PlayStation 4
|
||||
if (File.Exists(Path.Combine(drivePath, "PSLogo.ico")))
|
||||
{
|
||||
return KnownSystem.SonyPlayStation4;
|
||||
}
|
||||
|
||||
// V.Tech V.Flash / V.Smile Pro
|
||||
if (File.Exists(Path.Combine(drivePath, "0SYSTEM")))
|
||||
{
|
||||
return KnownSystem.VTechVFlashVSmilePro;
|
||||
}
|
||||
|
||||
// Default return
|
||||
return KnownSystem.NONE;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that, given a system and a media type, they are correct
|
||||
/// </summary>
|
||||
public static Result GetSupportStatus(KnownSystem? system, MediaType? type)
|
||||
{
|
||||
// No system chosen, update status
|
||||
if (system == KnownSystem.NONE)
|
||||
return Result.Failure("Please select a valid system");
|
||||
|
||||
// If we're on an unsupported type, update the status accordingly
|
||||
switch (type)
|
||||
{
|
||||
// Fully supported types
|
||||
case MediaType.BluRay:
|
||||
case MediaType.CDROM:
|
||||
case MediaType.DVD:
|
||||
case MediaType.FloppyDisk:
|
||||
case MediaType.HDDVD:
|
||||
return Result.Success("{0} ready to dump", type.LongName());
|
||||
|
||||
// Partially supported types
|
||||
case MediaType.GDROM:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return Result.Success("{0} partially supported for dumping", type.LongName());
|
||||
|
||||
// Special case for other supported tools
|
||||
case MediaType.UMD:
|
||||
return Result.Success("{0} supported for submission info parsing", type.LongName());
|
||||
|
||||
// Specifically unknown type
|
||||
case MediaType.NONE:
|
||||
return Result.Failure("Please select a valid media type");
|
||||
|
||||
// Undumpable but recognized types
|
||||
default:
|
||||
return Result.Failure("{0} media are not supported for dumping", type.LongName());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run protection scan on a given dump environment
|
||||
/// </summary>
|
||||
/// <param name="env">DumpEnvirionment containing all required information</param>
|
||||
/// <returns>Copy protection detected in the envirionment, if any</returns>
|
||||
public static async Task<string> RunProtectionScanOnPath(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
var found = await Task.Run(() =>
|
||||
{
|
||||
return ProtectionFind.Scan(path);
|
||||
});
|
||||
|
||||
if (found == null || found.Count == 0)
|
||||
return "None found";
|
||||
|
||||
return string.Join("\n", found.Select(kvp => kvp.Key + ": " + kvp.Value).ToArray());
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "Path could not be scanned!";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace DICUI.Web
|
||||
{
|
||||
// https://stackoverflow.com/questions/1777221/using-cookiecontainer-with-webclient-class
|
||||
public class CookieAwareWebClient : WebClient
|
||||
{
|
||||
private readonly CookieContainer m_container = new CookieContainer();
|
||||
|
||||
protected override WebRequest GetWebRequest(Uri address)
|
||||
{
|
||||
WebRequest request = base.GetWebRequest(address);
|
||||
HttpWebRequest webRequest = request as HttpWebRequest;
|
||||
if (webRequest != null)
|
||||
{
|
||||
webRequest.CookieContainer = m_container;
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the last downloaded filename, if possible
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string GetLastFilename()
|
||||
{
|
||||
// Try to extract the filename from the Content-Disposition header
|
||||
if (!String.IsNullOrEmpty(this.ResponseHeaders["Content-Disposition"]))
|
||||
return this.ResponseHeaders["Content-Disposition"].Substring(this.ResponseHeaders["Content-Disposition"].IndexOf("filename=") + 9).Replace("\"", "");
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,385 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
|
||||
namespace DICUI.Web
|
||||
{
|
||||
public class RedumpAccess
|
||||
{
|
||||
#region Base URLs
|
||||
|
||||
private const string loginUrl = "http://forum.redump.org/login/";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Disc URLs and Extensions
|
||||
|
||||
private const string discPageUrl = @"http://redump.org/disc/{0}/";
|
||||
private const string wipDiscPageUrl = @"http://redump.org/newdisc/{0}/";
|
||||
|
||||
private const string changesExt = "/changes/";
|
||||
private const string cueExt = "cue/";
|
||||
private const string gdiExt = "gdi/";
|
||||
private const string keyExt = "key/";
|
||||
private const string md5Ext = "md5/";
|
||||
private const string sbiExt = "sbi/";
|
||||
private const string sfvExt = "sfv/";
|
||||
private const string sha1Ext = "sha1/";
|
||||
|
||||
#endregion
|
||||
|
||||
#region List URLs
|
||||
|
||||
private const string lastModifiedUrl = @"http://redump.org/discs/sort/modified/dir/desc?page={0}";
|
||||
private const string quickSearchUrl = @"http://redump.org/discs/quicksearch/{0}/?page={1}";
|
||||
private const string userDumpsUrl = @"http://redump.org/discs/dumper/{0}/?page={1}";
|
||||
private const string wipDumpsUrl = @"http://redump.org/discs-wip/";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Pack URLs
|
||||
|
||||
private const string packCuesUrl = @"http://redump.org/cues/{0}/";
|
||||
private const string packDatfileUrl = @"http://redump.org/datfile/{0}/";
|
||||
private const string packDkeysUrl = @"http://redump.org/dkeys/{0}/";
|
||||
private const string packGdiUrl = @"http://redump.org/gdi/{0}/";
|
||||
private const string packKeysUrl = @"http://redump.org/keys/{0}/";
|
||||
private const string packSbiUrl = @"http://redump.org/sbi/{0}/";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Regexes
|
||||
|
||||
private readonly Regex discRegex = new Regex(@"<a href=""/disc/(\d+)/"">");
|
||||
private readonly Regex newDiscRegex = new Regex(@"<a href=""/newdisc/(\d+)/"">");
|
||||
private readonly Regex tokenRegex = new Regex(@"<input type=""hidden"" name=""csrf_token"" value=""(.*?)"" />");
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Login to Redump, if possible
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to hold the login state</param>
|
||||
/// <param name="username">Redump username to log in for protected systems</param>
|
||||
/// <param name="password">Redump password to log in for protected systems</param>
|
||||
/// <returns>True login was successful, false otherwise</returns>
|
||||
public bool RedumpLogin(CookieAwareWebClient wc, string username, string password)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
|
||||
return false;
|
||||
|
||||
var loginPage = wc.DownloadString(loginUrl);
|
||||
string token = this.tokenRegex.Match(loginPage).Groups[1].Value;
|
||||
|
||||
wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
|
||||
wc.Encoding = Encoding.UTF8;
|
||||
var response = wc.UploadString(loginUrl, $"form_sent=1&redirect_url=&csrf_token={token}&req_username={username}&req_password={password}&save_pass=0");
|
||||
|
||||
if (response.Contains("Incorrect username and/or password."))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Process IDs and Pages
|
||||
|
||||
/// <summary>
|
||||
/// Get the list of the last modified IDs, in order of appearance
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to hold the login state</param>
|
||||
/// <param name="pageCount">Number of pages to grab until stopping; -1 means continue until end</param>
|
||||
/// <returns>A list of IDs in order of last modified</returns>
|
||||
private List<int> ProcessLastModified(CookieAwareWebClient wc, int pageCount = -1)
|
||||
{
|
||||
List<int> ids = new List<int>();
|
||||
|
||||
// If we have a -1 page count, set the maximum page limit
|
||||
if (pageCount == -1)
|
||||
pageCount = Int32.MaxValue;
|
||||
|
||||
// Keep getting last modified pages until there are none left
|
||||
int pageNumber = 1;
|
||||
while (pageNumber < pageCount)
|
||||
{
|
||||
List<int> pageIds = CheckSingleSitePage(wc, string.Format(lastModifiedUrl, pageNumber++));
|
||||
ids.AddRange(pageIds);
|
||||
if (pageIds.Count < 2)
|
||||
break;
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve premade packs from Redump
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to hold the login state</param>
|
||||
private void ProcessAllPacks(CookieAwareWebClient wc)
|
||||
{
|
||||
var cuesPacks = this.DownloadPacks(wc, packCuesUrl, Extensions.HasCues, "CUEs");
|
||||
var datPacks = this.DownloadPacks(wc, packDatfileUrl, Extensions.HasDat, "DATs");
|
||||
var dkeyPacks = this.DownloadPacks(wc, packDkeysUrl, Extensions.HasDkeys, "Decrypted KEYS");
|
||||
var gdiPacks = this.DownloadPacks(wc, packGdiUrl, Extensions.HasGdi, "GDIs");
|
||||
var keysPacks = this.DownloadPacks(wc, packKeysUrl, Extensions.HasKeys, "KEYS");
|
||||
var sbiPacks = this.DownloadPacks(wc, packSbiUrl, Extensions.HasSbi, "SBIs");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve premade packs from Redump
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to hold the login state</param>
|
||||
/// <param name="system">RedumpSystem to get all possible packs for</param>
|
||||
private void ProcessPacksForSystem(CookieAwareWebClient wc, RedumpSystem system)
|
||||
{
|
||||
var packs = new Dictionary<string, byte[]>();
|
||||
|
||||
if (Extensions.HasCues.Contains(system))
|
||||
packs.Add("cues", this.DownloadPack(wc, packCuesUrl, system, "CUEs"));
|
||||
|
||||
if (Extensions.HasDat.Contains(system))
|
||||
packs.Add("dat", this.DownloadPack(wc, packDatfileUrl, system, "DATs"));
|
||||
|
||||
if (Extensions.HasDkeys.Contains(system))
|
||||
packs.Add("dkeys", this.DownloadPack(wc, packDkeysUrl, system, "Decrypted KEYS"));
|
||||
|
||||
if (Extensions.HasGdi.Contains(system))
|
||||
packs.Add("gdi", this.DownloadPack(wc, packGdiUrl, system, "GDIs"));
|
||||
|
||||
if (Extensions.HasKeys.Contains(system))
|
||||
packs.Add("keys", this.DownloadPack(wc, packKeysUrl, system, "KEYS"));
|
||||
|
||||
if (Extensions.HasSbi.Contains(system))
|
||||
packs.Add("sbi", this.DownloadPack(wc, packSbiUrl, system, "SBIs"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the list of IDs that associate with a given string
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to hold the login state</param>
|
||||
/// <param name="query">Value to search for in Redump</param>
|
||||
/// <returns>A list of IDs associated with that value</returns>
|
||||
public List<int> ProcessSearch(CookieAwareWebClient wc, string query)
|
||||
{
|
||||
List<int> ids = new List<int>();
|
||||
|
||||
// Keep getting quicksearch pages until there are none left
|
||||
int pageNumber = 1;
|
||||
while (true)
|
||||
{
|
||||
List<int> pageIds = CheckSingleSitePage(wc, string.Format(quickSearchUrl, query, pageNumber++));
|
||||
ids.AddRange(pageIds);
|
||||
if (pageIds.Count < 2)
|
||||
break;
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the list of IDs associated with the given user
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to hold the login state</param>
|
||||
/// <param name="username">Redump username to get the list of IDs for</param>
|
||||
/// <returns>A list of IDs associated with that user</returns>
|
||||
private List<int> ProcessUser(CookieAwareWebClient wc, string username)
|
||||
{
|
||||
List<int> ids = new List<int>();
|
||||
|
||||
// Keep getting user pages until there are none left
|
||||
int pageNumber = 1;
|
||||
while (true)
|
||||
{
|
||||
List<int> pageIds = CheckSingleSitePage(wc, string.Format(userDumpsUrl, username, pageNumber++));
|
||||
ids.AddRange(pageIds);
|
||||
if (pageIds.Count < 2)
|
||||
break;
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Single item processing
|
||||
|
||||
/// <summary>
|
||||
/// Process a Redump site page as a list of possible IDs or disc page
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to access the pages</param>
|
||||
/// <param name="url">Page URL to check and parse</param>
|
||||
/// <returns>List of matching IDs</returns>
|
||||
private List<int> CheckSingleSitePage(CookieAwareWebClient wc, string url)
|
||||
{
|
||||
List<int> ids = new List<int>();
|
||||
|
||||
var dumpsPage = wc.DownloadString(url);
|
||||
|
||||
// If we have no dumps left
|
||||
if (dumpsPage.Contains("No discs found."))
|
||||
return ids;
|
||||
|
||||
// If we have a single disc page already
|
||||
if (dumpsPage.Contains("<b>Download:</b>"))
|
||||
{
|
||||
var value = Regex.Match(dumpsPage, @"/disc/(\d+)/sfv/").Groups[1].Value;
|
||||
if (Int32.TryParse(value, out int id))
|
||||
ids.Add(id);
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
// Otherwise, traverse each dump on the page
|
||||
var matches = discRegex.Matches(dumpsPage);
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Int32.TryParse(match.Groups[1].Value, out int value))
|
||||
ids.Add(value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"An exception has occurred: {ex}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process a Redump WIP page as a list of possible IDs or disc page
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to access the pages</param>
|
||||
/// <param name="url">Page URL to check and parse</param>
|
||||
/// <returns>List of matching IDs</returns>
|
||||
private List<int> CheckSingleWIPPage(CookieAwareWebClient wc, string url)
|
||||
{
|
||||
List<int> ids = new List<int>();
|
||||
|
||||
var wipDumpsPage = wc.DownloadString(url);
|
||||
|
||||
// If we have no WIP dumps left
|
||||
if (wipDumpsPage.Contains("No WIP discs found."))
|
||||
return ids;
|
||||
|
||||
// Otherwise, traverse each dump on the page
|
||||
var matches = newDiscRegex.Matches(wipDumpsPage);
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Int32.TryParse(match.Groups[1].Value, out int value))
|
||||
ids.Add(value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"An exception has occurred: {ex}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Download an individual pack
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to access the packs</param>
|
||||
/// <param name="url">Base URL to download using</param>
|
||||
/// <param name="system">System to download packs for</param>
|
||||
/// <param name="title">Name of the pack that is downloading</param>
|
||||
private byte[] DownloadPack(CookieAwareWebClient wc, string url, RedumpSystem system, string title)
|
||||
{
|
||||
Console.WriteLine($"Downloading {title}");
|
||||
Console.Write($"\r{system.LongName()}{new string(' ', Console.BufferWidth - system.LongName().Length - 1)}");
|
||||
var pack = wc.DownloadData(string.Format(url, system.ShortName()));
|
||||
|
||||
Console.Write($"\rComplete!{new string(' ', Console.BufferWidth - 10)}");
|
||||
Console.WriteLine();
|
||||
|
||||
return pack;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Download a set of packs
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to access the packs</param>
|
||||
/// <param name="url">Base URL to download using</param>
|
||||
/// <param name="systems">List of systems to download packs for</param>
|
||||
/// <param name="title">Name of the pack that is downloading</param>
|
||||
private Dictionary<RedumpSystem, byte[]> DownloadPacks(CookieAwareWebClient wc, string url, RedumpSystem[] systems, string title)
|
||||
{
|
||||
var dict = new Dictionary<RedumpSystem, byte[]>();
|
||||
|
||||
Console.WriteLine($"Downloading {title}");
|
||||
foreach (var system in systems)
|
||||
{
|
||||
Console.Write($"\r{system.LongName()}{new string(' ', Console.BufferWidth - system.LongName().Length - 1)}");
|
||||
dict.Add(system, wc.DownloadData(string.Format(url, system.ShortName())));
|
||||
}
|
||||
|
||||
Console.Write($"\rComplete!{new string(' ', Console.BufferWidth - 10)}");
|
||||
Console.WriteLine();
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Download an individual site ID page as a string, if possible
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to access the pages</param>
|
||||
/// <param name="id">Redump disc ID to retrieve</param>
|
||||
/// <returns>Disc page as a string, null on error</returns>
|
||||
public string DownloadSingleSiteID(CookieAwareWebClient wc, int id)
|
||||
{
|
||||
string paddedId = id.ToString().PadLeft(5, '0');
|
||||
Console.WriteLine($"Processing ID: {paddedId}");
|
||||
try
|
||||
{
|
||||
string discPage = wc.DownloadString(string.Format(discPageUrl, +id));
|
||||
if (discPage.Contains($"Disc with ID \"{id}\" doesn't exist"))
|
||||
return null;
|
||||
else
|
||||
return discPage;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"An exception has occurred: {ex}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Download an individual WIP ID page as a string, if possible
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to access the pages</param>
|
||||
/// <param name="id">Redump disc ID to retrieve</param>
|
||||
/// <returns>WIP disc page as a string, null on error</returns>
|
||||
private string DownloadSingleWIPID(CookieAwareWebClient wc, int id)
|
||||
{
|
||||
string paddedId = id.ToString().PadLeft(5, '0');
|
||||
Console.WriteLine($"Processing WIP ID: {paddedId}");
|
||||
try
|
||||
{
|
||||
string discPage = wc.DownloadString(string.Format(wipDiscPageUrl, +id));
|
||||
if (discPage.Contains($"WIP Disc with ID \"{id}\" doesn't exist"))
|
||||
return null;
|
||||
else
|
||||
return discPage;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"An exception has occurred: {ex}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="BurnOutSharp" version="1.3.7.1" targetFramework="net461" />
|
||||
<package id="LessIO" version="0.5.0" targetFramework="net461" />
|
||||
<package id="libmspack4n" version="0.8.0" targetFramework="net461" />
|
||||
<package id="Newtonsoft.Json" version="12.0.2" targetFramework="net461" />
|
||||
<package id="UnshieldSharp" version="1.4.2.2" targetFramework="net461" />
|
||||
<package id="zlib.net" version="1.0.4.0" targetFramework="net461" />
|
||||
</packages>
|
||||
@@ -1,109 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\Microsoft.NET.Test.Sdk.15.8.0\build\net45\Microsoft.Net.Test.Sdk.props" Condition="Exists('..\packages\Microsoft.NET.Test.Sdk.15.8.0\build\net45\Microsoft.Net.Test.Sdk.props')" />
|
||||
<Import Project="..\packages\Microsoft.CodeCoverage.15.8.0\build\netstandard1.0\Microsoft.CodeCoverage.props" Condition="Exists('..\packages\Microsoft.CodeCoverage.15.8.0\build\netstandard1.0\Microsoft.CodeCoverage.props')" />
|
||||
<Import Project="..\packages\xunit.runner.visualstudio.2.3.1\build\net20\xunit.runner.visualstudio.props" Condition="Exists('..\packages\xunit.runner.visualstudio.2.3.1\build\net20\xunit.runner.visualstudio.props')" />
|
||||
<Import Project="..\packages\xunit.runner.console.2.3.1\build\xunit.runner.console.props" Condition="Exists('..\packages\xunit.runner.console.2.3.1\build\xunit.runner.console.props')" />
|
||||
<Import Project="..\packages\xunit.core.2.3.1\build\xunit.core.props" Condition="Exists('..\packages\xunit.core.2.3.1\build\xunit.core.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{7CC064D2-38AB-4A05-8519-28660DE4562A}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>DICUI.Test</RootNamespace>
|
||||
<AssemblyName>DICUI.Test</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
|
||||
<IsCodedUITest>False</IsCodedUITest>
|
||||
<TestProjectType>UnitTest</TestProjectType>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.VisualStudio.CodeCoverage.Shim, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.CodeCoverage.15.8.0\lib\net45\Microsoft.VisualStudio.CodeCoverage.Shim.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="xunit.assert, Version=2.3.1.3858, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\xunit.assert.2.3.1\lib\netstandard1.1\xunit.assert.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="xunit.core, Version=2.3.1.3858, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\xunit.extensibility.core.2.3.1\lib\netstandard1.1\xunit.core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="xunit.execution.desktop, Version=2.3.1.3858, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\xunit.extensibility.execution.2.3.1\lib\net452\xunit.execution.desktop.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="UI\AllowedSpeedsTest.cs" />
|
||||
<Compile Include="Utilities\DumpEnvironmentTest.cs" />
|
||||
<Compile Include="ResultTest.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Utilities\DriveTest.cs" />
|
||||
<Compile Include="Utilities\ConvertersTest.cs" />
|
||||
<Compile Include="Utilities\KnownSystemExtensionsTest.cs" />
|
||||
<Compile Include="Utilities\MediaTypeExtensionsTest.cs" />
|
||||
<Compile Include="Utilities\ParametersTest.cs" />
|
||||
<Compile Include="Utilities\ValidatorsTest.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Analyzer Include="..\packages\xunit.analyzers.0.10.0\analyzers\dotnet\cs\xunit.analyzers.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DICUI.Library\DICUI.Library.csproj">
|
||||
<Project>{51ab0928-13f9-44bf-a407-b6957a43a056}</Project>
|
||||
<Name>DICUI.Library</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\DICUI\DICUI.csproj">
|
||||
<Project>{7b1b75eb-8940-466f-bd51-76471a57f9be}</Project>
|
||||
<Name>DICUI</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\xunit.core.2.3.1\build\xunit.core.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.3.1\build\xunit.core.props'))" />
|
||||
<Error Condition="!Exists('..\packages\xunit.core.2.3.1\build\xunit.core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.3.1\build\xunit.core.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\xunit.runner.console.2.3.1\build\xunit.runner.console.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.runner.console.2.3.1\build\xunit.runner.console.props'))" />
|
||||
<Error Condition="!Exists('..\packages\xunit.runner.visualstudio.2.3.1\build\net20\xunit.runner.visualstudio.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.runner.visualstudio.2.3.1\build\net20\xunit.runner.visualstudio.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.CodeCoverage.15.8.0\build\netstandard1.0\Microsoft.CodeCoverage.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.CodeCoverage.15.8.0\build\netstandard1.0\Microsoft.CodeCoverage.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.CodeCoverage.15.8.0\build\netstandard1.0\Microsoft.CodeCoverage.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.CodeCoverage.15.8.0\build\netstandard1.0\Microsoft.CodeCoverage.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.NET.Test.Sdk.15.8.0\build\net45\Microsoft.Net.Test.Sdk.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.NET.Test.Sdk.15.8.0\build\net45\Microsoft.Net.Test.Sdk.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.NET.Test.Sdk.15.8.0\build\net45\Microsoft.Net.Test.Sdk.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.NET.Test.Sdk.15.8.0\build\net45\Microsoft.Net.Test.Sdk.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\xunit.core.2.3.1\build\xunit.core.targets" Condition="Exists('..\packages\xunit.core.2.3.1\build\xunit.core.targets')" />
|
||||
<Import Project="..\packages\Microsoft.CodeCoverage.15.8.0\build\netstandard1.0\Microsoft.CodeCoverage.targets" Condition="Exists('..\packages\Microsoft.CodeCoverage.15.8.0\build\netstandard1.0\Microsoft.CodeCoverage.targets')" />
|
||||
<Import Project="..\packages\Microsoft.NET.Test.Sdk.15.8.0\build\net45\Microsoft.Net.Test.Sdk.targets" Condition="Exists('..\packages\Microsoft.NET.Test.Sdk.15.8.0\build\net45\Microsoft.Net.Test.Sdk.targets')" />
|
||||
</Project>
|
||||
@@ -1,20 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[assembly: AssemblyTitle("DICUI.Test")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("DICUI.Test")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
[assembly: Guid("7cc064d2-38ab-4a05-8519-28660de4562a")]
|
||||
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -1,40 +0,0 @@
|
||||
using DICUI.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace DICUI.Test
|
||||
{
|
||||
public class ResultTest
|
||||
{
|
||||
[Fact]
|
||||
public void ResultSuccessTest()
|
||||
{
|
||||
Result actual = Result.Success();
|
||||
Assert.Empty(actual.Message);
|
||||
|
||||
string message = "Success!";
|
||||
actual = Result.Success(message);
|
||||
Assert.Equal(message, actual.Message);
|
||||
|
||||
message = "Success! {0}";
|
||||
string parameter = "Parameter";
|
||||
actual = Result.Success(message, parameter);
|
||||
Assert.Equal(string.Format(message, parameter), actual.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResultFailureTest()
|
||||
{
|
||||
Result actual = Result.Failure();
|
||||
Assert.Empty(actual.Message);
|
||||
|
||||
string message = "Failure!";
|
||||
actual = Result.Failure(message);
|
||||
Assert.Equal(message, actual.Message);
|
||||
|
||||
message = "Failure! {0}";
|
||||
string parameter = "Parameter";
|
||||
actual = Result.Failure(message, parameter);
|
||||
Assert.Equal(string.Format(message, parameter), actual.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using System.Linq;
|
||||
using DICUI.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace DICUI.Test.Data
|
||||
{
|
||||
public class UIElementsTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(MediaType.CDROM, 72)]
|
||||
[InlineData(MediaType.DVD, 24)]
|
||||
[InlineData(MediaType.BluRay, 16)]
|
||||
[InlineData(MediaType.LaserDisc, 72)] // TODO: Update when fully determined
|
||||
[InlineData(null, 72)] // TODO: Update when fully determined
|
||||
public void GetAllowedDriveSpeedForMediaTypeTest(MediaType? mediaType, int maxExpected)
|
||||
{
|
||||
var actual = Constants.GetSpeedsForMediaType(mediaType);
|
||||
Assert.Equal(maxExpected, actual.Last());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
using System;
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace DICUI.Test.Utilities
|
||||
{
|
||||
public class ConvertersTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(DICCommand.Audio, MediaType.CDROM)]
|
||||
[InlineData(DICCommand.BluRay, MediaType.BluRay)]
|
||||
[InlineData(DICCommand.Close, null)]
|
||||
[InlineData(DICCommand.CompactDisc, MediaType.CDROM)]
|
||||
[InlineData(DICCommand.Data, MediaType.CDROM)]
|
||||
[InlineData(DICCommand.DigitalVideoDisc, MediaType.DVD)]
|
||||
[InlineData(DICCommand.Eject, null)]
|
||||
[InlineData(DICCommand.Floppy, MediaType.FloppyDisk)]
|
||||
[InlineData(DICCommand.GDROM, MediaType.GDROM)]
|
||||
[InlineData(DICCommand.MDS, null)]
|
||||
[InlineData(DICCommand.Reset, null)]
|
||||
[InlineData(DICCommand.SACD, MediaType.CDROM)]
|
||||
[InlineData(DICCommand.Start, null)]
|
||||
[InlineData(DICCommand.Stop, null)]
|
||||
[InlineData(DICCommand.Sub, null)]
|
||||
[InlineData(DICCommand.Swap, MediaType.GDROM)]
|
||||
[InlineData(DICCommand.XBOX, MediaType.DVD)]
|
||||
public void BaseCommandToMediaTypeTest(DICCommand command, MediaType? expected)
|
||||
{
|
||||
MediaType? actual = command.ToMediaType();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(DICCommand.Audio, KnownSystem.AudioCD)]
|
||||
[InlineData(DICCommand.BluRay, KnownSystem.SonyPlayStation3)]
|
||||
[InlineData(DICCommand.Close, null)]
|
||||
[InlineData(DICCommand.CompactDisc, KnownSystem.IBMPCCompatible)]
|
||||
[InlineData(DICCommand.Data, KnownSystem.IBMPCCompatible)]
|
||||
[InlineData(DICCommand.DigitalVideoDisc, KnownSystem.IBMPCCompatible)]
|
||||
[InlineData(DICCommand.Eject, null)]
|
||||
[InlineData(DICCommand.Floppy, KnownSystem.IBMPCCompatible)]
|
||||
[InlineData(DICCommand.GDROM, KnownSystem.SegaDreamcast)]
|
||||
[InlineData(DICCommand.MDS, null)]
|
||||
[InlineData(DICCommand.Reset, null)]
|
||||
[InlineData(DICCommand.SACD, KnownSystem.SuperAudioCD)]
|
||||
[InlineData(DICCommand.Start, null)]
|
||||
[InlineData(DICCommand.Stop, null)]
|
||||
[InlineData(DICCommand.Sub, null)]
|
||||
[InlineData(DICCommand.Swap, KnownSystem.SegaDreamcast)]
|
||||
[InlineData(DICCommand.XBOX, KnownSystem.MicrosoftXBOX)]
|
||||
public void BaseCommandToKnownSystemTest(DICCommand command, KnownSystem? expected)
|
||||
{
|
||||
KnownSystem? actual = Converters.ToKnownSystem(command);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(MediaType.CDROM, ".bin")]
|
||||
[InlineData(MediaType.DVD, ".iso")]
|
||||
[InlineData(MediaType.LaserDisc, ".raw")]
|
||||
[InlineData(MediaType.NintendoWiiUOpticalDisc, ".wud")]
|
||||
[InlineData(MediaType.FloppyDisk, ".img")]
|
||||
[InlineData(MediaType.Cassette, ".wav")]
|
||||
[InlineData(MediaType.NONE, null)]
|
||||
public void MediaTypeToExtensionTest(MediaType? mediaType, string expected)
|
||||
{
|
||||
string actual = Converters.Extension(mediaType);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(MediaType.CDROM, "CD-ROM")]
|
||||
[InlineData(MediaType.LaserDisc, "LD-ROM / LV-ROM")]
|
||||
[InlineData(MediaType.NONE, "Unknown")]
|
||||
public void MediaTypeToStringTest(MediaType? mediaType, string expected)
|
||||
{
|
||||
string actual = Converters.LongName(mediaType);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(KnownSystem.MicrosoftXBOX, "Microsoft XBOX")]
|
||||
[InlineData(KnownSystem.NECPC88, "NEC PC-88")]
|
||||
[InlineData(KnownSystem.KonamiPython, "Konami Python")]
|
||||
[InlineData(KnownSystem.HDDVDVideo, "HD-DVD-Video")]
|
||||
[InlineData(KnownSystem.NONE, "Unknown")]
|
||||
public void KnownSystemToStringTest(KnownSystem? knownSystem, string expected)
|
||||
{
|
||||
string actual = Converters.LongName(knownSystem);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void KnownSystemHasValidCategory()
|
||||
{
|
||||
var values = Validators.CreateListOfSystems();
|
||||
KnownSystem[] markers = { KnownSystem.MarkerArcadeEnd, KnownSystem.MarkerDiscBasedConsoleEnd, /* KnownSystem.MarkerOtherConsoleEnd, */ KnownSystem.MarkerComputerEnd, KnownSystem.MarkerOtherEnd };
|
||||
|
||||
values.ForEach(system => {
|
||||
if (system == KnownSystem.NONE)
|
||||
return;
|
||||
|
||||
// we check that the category is the first category value higher than the system
|
||||
KnownSystemCategory category = ((KnownSystem?)system).Category();
|
||||
KnownSystem marker = KnownSystem.NONE;
|
||||
|
||||
switch (category)
|
||||
{
|
||||
case KnownSystemCategory.Arcade: marker = KnownSystem.MarkerArcadeEnd; break;
|
||||
case KnownSystemCategory.DiscBasedConsole: marker = KnownSystem.MarkerDiscBasedConsoleEnd; break;
|
||||
/* case KnownSystemCategory.OtherConsole: marker = KnownSystem.MarkerOtherConsoleEnd; break; */
|
||||
case KnownSystemCategory.Computer: marker = KnownSystem.MarkerComputerEnd; break;
|
||||
case KnownSystemCategory.Other: marker = KnownSystem.MarkerOtherEnd; break;
|
||||
}
|
||||
|
||||
Assert.NotEqual(KnownSystem.NONE, marker);
|
||||
Assert.True(marker > system);
|
||||
|
||||
Array.ForEach(markers, mmarker =>
|
||||
{
|
||||
// a marker can be the same of the found one, or one of a category before or a category after but never in the middle between
|
||||
// the system and the mapped category
|
||||
Assert.True(mmarker == marker || mmarker < system || mmarker > marker);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using DICUI.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace DICUI.Test.Utilities
|
||||
{
|
||||
public class DriveTest
|
||||
{
|
||||
[Fact]
|
||||
public void DriveConstructorsTest()
|
||||
{
|
||||
Assert.True(Drive.Floppy('a').IsFloppy);
|
||||
Assert.False(Drive.Optical('d', "test", true).IsFloppy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace DICUI.Test
|
||||
{
|
||||
public class DumpEnvironmentTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(null, 'D', false, MediaType.NONE, false)]
|
||||
[InlineData("", 'D', false, MediaType.NONE, false)]
|
||||
[InlineData("cd F test.bin 8 /c2 20", 'F', false, MediaType.CDROM, true)]
|
||||
[InlineData("fd A test.img", 'A', true, MediaType.FloppyDisk, true)]
|
||||
[InlineData("dvd X test.iso 8 /raw", 'X', false, MediaType.FloppyDisk, false)]
|
||||
[InlineData("stop D", 'D', false, MediaType.DVD, true)]
|
||||
public void ParametersValidTest(string parameters, char letter, bool isFloppy, MediaType? mediaType, bool expected)
|
||||
{
|
||||
var env = new DumpEnvironment
|
||||
{
|
||||
DICParameters = new Parameters(parameters),
|
||||
Drive = isFloppy ? Drive.Floppy(letter) : Drive.Optical(letter, "", true),
|
||||
Type = mediaType,
|
||||
};
|
||||
|
||||
bool actual = env.ParametersValid();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null, null, null)]
|
||||
[InlineData(" ", "", " ", "")]
|
||||
[InlineData("super", "blah.bin", "super", "blah.bin")]
|
||||
[InlineData("super\\hero", "blah.bin", "super\\hero", "blah.bin")]
|
||||
[InlineData("super.hero", "blah.bin", "super_hero", "blah.bin")]
|
||||
[InlineData("superhero", "blah.rev.bin", "superhero", "blah_rev.bin")]
|
||||
[InlineData("super&hero", "blah.bin", "super_hero", "blah.bin")]
|
||||
[InlineData("superhero", "blah&foo.bin", "superhero", "blah_foo.bin")]
|
||||
public void FixOutputPathsTest(string outputDirectory, string outputFilename, string expectedOutputDirectory, string expectedOutputFilename)
|
||||
{
|
||||
var env = new DumpEnvironment
|
||||
{
|
||||
OutputDirectory = outputDirectory,
|
||||
OutputFilename = outputFilename,
|
||||
};
|
||||
|
||||
env.FixOutputPaths();
|
||||
Assert.Equal(expectedOutputDirectory, env.OutputDirectory);
|
||||
Assert.Equal(expectedOutputFilename, env.OutputFilename);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFirstTrackTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatOutputDataTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteOutputDataTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EjectDiscTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CancelDumpingTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StartDumpingTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
using System;
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace DICUI.Test.Utilities
|
||||
{
|
||||
public class KnownSystemExtensionsTest
|
||||
{
|
||||
[Fact]
|
||||
public void IsMarkerTest()
|
||||
{
|
||||
var values = (KnownSystem[])Enum.GetValues(typeof(KnownSystem));
|
||||
foreach(var system in values)
|
||||
{
|
||||
bool expected = system == KnownSystem.MarkerArcadeEnd || system == KnownSystem.MarkerComputerEnd ||
|
||||
system == KnownSystem.MarkerOtherEnd || system == KnownSystem.MarkerDiscBasedConsoleEnd;
|
||||
// || system == KnownSystem.MarkerOtherConsoleEnd;
|
||||
|
||||
bool actual = ((KnownSystem?)system).IsMarker();
|
||||
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CategoryNameNotEmptyTest()
|
||||
{
|
||||
var values = (KnownSystemCategory[])Enum.GetValues(typeof(KnownSystemCategory));
|
||||
foreach (var system in values)
|
||||
{
|
||||
string actual = ((KnownSystem?)system).LongName();
|
||||
Assert.NotEqual("", actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace DICUI.Test.Utilities
|
||||
{
|
||||
public class MediaTypeExtensionsTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(MediaType.CDROM, "CD-ROM")]
|
||||
[InlineData(MediaType.LaserDisc, "LD-ROM / LV-ROM")]
|
||||
[InlineData(MediaType.NONE, "Unknown")]
|
||||
public void NameTest(MediaType? mediaType, string expected)
|
||||
{
|
||||
string actual = mediaType.LongName();
|
||||
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(MediaType.CDROM, ".bin")]
|
||||
[InlineData(MediaType.DVD, ".iso")]
|
||||
[InlineData(MediaType.LaserDisc, ".raw")]
|
||||
[InlineData(MediaType.FloppyDisk, ".img")]
|
||||
[InlineData(MediaType.NONE, null)]
|
||||
public void ExtensionTest(MediaType? mediaType, string expected)
|
||||
{
|
||||
string actual = mediaType.Extension();
|
||||
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(MediaType.CDROM, true)]
|
||||
[InlineData(MediaType.DVD, true)]
|
||||
[InlineData(MediaType.FloppyDisk, false)]
|
||||
[InlineData(MediaType.BluRay, true)]
|
||||
[InlineData(MediaType.LaserDisc, false)]
|
||||
public void DriveSpeedSupportedTest(MediaType? mediaType, bool expected)
|
||||
{
|
||||
bool actual = mediaType.DoesSupportDriveSpeed();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace DICUI.Test.Utilities
|
||||
{
|
||||
public class ParametersTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(KnownSystem.MicrosoftXBOX, MediaType.CDROM, DICCommand.CompactDisc)]
|
||||
[InlineData(KnownSystem.MicrosoftXBOX, MediaType.DVD, DICCommand.XBOX)]
|
||||
[InlineData(KnownSystem.MicrosoftXBOX, MediaType.LaserDisc, DICCommand.NONE)]
|
||||
[InlineData(KnownSystem.SegaNu, MediaType.BluRay, DICCommand.BluRay)]
|
||||
[InlineData(KnownSystem.AppleMacintosh, MediaType.FloppyDisk, DICCommand.Floppy)]
|
||||
[InlineData(KnownSystem.RawThrillsVarious, MediaType.GDROM, DICCommand.NONE)]
|
||||
public void ParametersFromSystemAndTypeTest(KnownSystem? knownSystem, MediaType? mediaType, DICCommand expected)
|
||||
{
|
||||
Parameters actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, true, -1);
|
||||
Assert.Equal(expected, actual.Command);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(KnownSystem.AppleMacintosh, MediaType.LaserDisc, true, 20, null, null)]
|
||||
[InlineData(KnownSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc, false, 20, null, new DICFlag[] { DICFlag.Raw })]
|
||||
[InlineData(KnownSystem.IBMPCCompatible, MediaType.DVD, false, 20, null, new DICFlag[] { })]
|
||||
/* paranoid mode tests */
|
||||
[InlineData(KnownSystem.IBMPCCompatible, MediaType.CDROM, true, 1000, 2, new DICFlag[] { DICFlag.C2Opcode, DICFlag.NoFixSubQSecuROM, DICFlag.ScanFileProtect, DICFlag.ScanSectorProtect, DICFlag.SubchannelReadLevel })]
|
||||
[InlineData(KnownSystem.AppleMacintosh, MediaType.CDROM, false, 20, null, new DICFlag[] { DICFlag.C2Opcode, DICFlag.NoFixSubQSecuROM, DICFlag.ScanFileProtect })]
|
||||
[InlineData(KnownSystem.IBMPCCompatible, MediaType.DVD, true, 500, null, new DICFlag[] { DICFlag.CopyrightManagementInformation, DICFlag.ScanFileProtect })]
|
||||
[InlineData(KnownSystem.HDDVDVideo, MediaType.HDDVD, true, 500, null, new DICFlag[] { DICFlag.CopyrightManagementInformation })]
|
||||
[InlineData(KnownSystem.IBMPCCompatible, MediaType.DVD, false, 500, null, new DICFlag[] { })]
|
||||
[InlineData(KnownSystem.HDDVDVideo, MediaType.HDDVD, false, 500, null, new DICFlag[] { })]
|
||||
/* reread c2 */
|
||||
[InlineData(KnownSystem.SegaDreamcast, MediaType.GDROM, false, 1000, null, new DICFlag[] { DICFlag.C2Opcode })]
|
||||
[InlineData(KnownSystem.SegaDreamcast, MediaType.GDROM, false, -1, null, new DICFlag[] { DICFlag.C2Opcode })]
|
||||
|
||||
public void ParametersFromOptionsTest(KnownSystem? knownSystem, MediaType? mediaType, bool paranoid, int rereadC2, int? subchannelLevel, DICFlag[] expected)
|
||||
{
|
||||
Parameters actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, paranoid, rereadC2);
|
||||
|
||||
HashSet<DICFlag> expectedSet = new HashSet<DICFlag>(expected ?? new DICFlag[0]);
|
||||
HashSet<DICFlag> actualSet = new HashSet<DICFlag>(actual.Keys ?? new DICFlag[0]);
|
||||
Assert.Equal(expectedSet, actualSet);
|
||||
if (rereadC2 == -1 || !Validators.GetValidMediaTypes(knownSystem).Contains(mediaType))
|
||||
Assert.Null(actual.C2OpcodeValue[0]);
|
||||
else
|
||||
Assert.Equal(rereadC2, actual.C2OpcodeValue[0]);
|
||||
Assert.Equal(subchannelLevel, actual.SubchannelReadLevelValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null, null, null, null)]
|
||||
[InlineData("", null, null, null, null)]
|
||||
[InlineData("cd F test.bin 8 /c2 20", MediaType.CDROM, KnownSystem.IBMPCCompatible, "F", "test.bin")]
|
||||
[InlineData("fd A blah\\test.img", MediaType.FloppyDisk, KnownSystem.IBMPCCompatible, "A", "blah\\test.img")]
|
||||
[InlineData("dvd X super\\blah\\test.iso 8 /raw", MediaType.NintendoGameCubeGameDisc, KnownSystem.NintendoGameCube, "X", "super\\blah\\test.iso")]
|
||||
[InlineData("stop D", null, null, "D", null)]
|
||||
public void DetermineFlagsTest(string parameters, MediaType? expectedMediaType, KnownSystem? expectedKnownSystem, string expectedDriveLetter, string expectedPath)
|
||||
{
|
||||
Parameters actualParams = new Parameters(parameters);
|
||||
bool actual = actualParams.DetermineFlags(out MediaType? actualMediaType, out KnownSystem? actualKnownSystem, out string actualDriveLetter, out string actualPath);
|
||||
Assert.Equal(expectedMediaType, actualMediaType);
|
||||
Assert.Equal(expectedKnownSystem, actualKnownSystem);
|
||||
Assert.Equal(expectedDriveLetter, actualDriveLetter);
|
||||
Assert.Equal(expectedPath, actualPath);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, false)]
|
||||
[InlineData("", false)]
|
||||
[InlineData("cd F test.bin 8 /c2 20", true)]
|
||||
[InlineData("fd A test.img", true)]
|
||||
[InlineData("dvd X super\\test.iso 8 /raw", true)]
|
||||
[InlineData("bd D longer\\path_test.iso 16", true)]
|
||||
[InlineData("stop D", true)]
|
||||
[InlineData("ls", false)]
|
||||
public void ValidateParametersTest(string parameters, bool expected)
|
||||
{
|
||||
Parameters actual = new Parameters(parameters);
|
||||
Assert.Equal(expected, actual.IsValid());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
using System;
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace DICUI.Test.Utilities
|
||||
{
|
||||
public class ValidatorsTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(KnownSystem.BandaiApplePippin, MediaType.CDROM)]
|
||||
[InlineData(KnownSystem.MicrosoftXBOX, MediaType.DVD)]
|
||||
[InlineData(KnownSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc)]
|
||||
[InlineData(KnownSystem.NintendoWii, MediaType.NintendoWiiOpticalDisc)]
|
||||
[InlineData(KnownSystem.NintendoWiiU, MediaType.NintendoWiiUOpticalDisc)]
|
||||
[InlineData(KnownSystem.SonyPlayStationPortable, MediaType.UMD)]
|
||||
public void GetValidMediaTypesTest(KnownSystem? knownSystem, MediaType? expected)
|
||||
{
|
||||
var actual = Validators.GetValidMediaTypes(knownSystem);
|
||||
Assert.Contains(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateListOfSystemsTest()
|
||||
{
|
||||
int expected = Enum.GetValues(typeof(KnownSystem)).Length - 5; // - 4 -1 for markers categories and KnownSystem.NONE
|
||||
var actual = Validators.CreateListOfSystems();
|
||||
Assert.Equal(expected, actual.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateListOfDrivesTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDiscTypeTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.CodeCoverage" version="15.8.0" targetFramework="net461" />
|
||||
<package id="Microsoft.NET.Test.Sdk" version="15.8.0" targetFramework="net461" />
|
||||
<package id="xunit" version="2.3.1" targetFramework="net461" />
|
||||
<package id="xunit.abstractions" version="2.0.1" targetFramework="net461" />
|
||||
<package id="xunit.analyzers" version="0.10.0" targetFramework="net461" />
|
||||
<package id="xunit.assert" version="2.3.1" targetFramework="net461" />
|
||||
<package id="xunit.core" version="2.3.1" targetFramework="net461" />
|
||||
<package id="xunit.extensibility.core" version="2.3.1" targetFramework="net461" />
|
||||
<package id="xunit.extensibility.execution" version="2.3.1" targetFramework="net461" />
|
||||
<package id="xunit.runner.console" version="2.3.1" targetFramework="net461" developmentDependency="true" />
|
||||
<package id="xunit.runner.visualstudio" version="2.3.1" targetFramework="net461" developmentDependency="true" />
|
||||
</packages>
|
||||
43
DICUI.sln
43
DICUI.sln
@@ -1,43 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.28803.156
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DICUI", "DICUI\DICUI.csproj", "{7B1B75EB-8940-466F-BD51-76471A57F9BE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DICUI.Test", "DICUI.Test\DICUI.Test.csproj", "{7CC064D2-38AB-4A05-8519-28660DE4562A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DICUI.Library", "DICUI.Library\DICUI.Library.csproj", "{51AB0928-13F9-44BF-A407-B6957A43A056}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DICUI.Check", "DICUI.Check\DICUI.Check.csproj", "{8CFDE289-E171-4D49-A40D-5293265C1253}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{7B1B75EB-8940-466F-BD51-76471A57F9BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7B1B75EB-8940-466F-BD51-76471A57F9BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7B1B75EB-8940-466F-BD51-76471A57F9BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7B1B75EB-8940-466F-BD51-76471A57F9BE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7CC064D2-38AB-4A05-8519-28660DE4562A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7CC064D2-38AB-4A05-8519-28660DE4562A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7CC064D2-38AB-4A05-8519-28660DE4562A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7CC064D2-38AB-4A05-8519-28660DE4562A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{51AB0928-13F9-44BF-A407-B6957A43A056}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{51AB0928-13F9-44BF-A407-B6957A43A056}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{51AB0928-13F9-44BF-A407-B6957A43A056}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{51AB0928-13F9-44BF-A407-B6957A43A056}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8CFDE289-E171-4D49-A40D-5293265C1253}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8CFDE289-E171-4D49-A40D-5293265C1253}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8CFDE289-E171-4D49-A40D-5293265C1253}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8CFDE289-E171-4D49-A40D-5293265C1253}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {73C62E6A-6584-4D93-83B5-ECB1FBDB469B}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="DICPath" value="Programs\DiscImageCreator.exe"/>
|
||||
<add key="SubDumpPath" value="subdump.exe"/>
|
||||
<add key="DefaultOutputPath" value="ISO"/>
|
||||
<add key="PreferredDumpSpeedCD" value="72"/>
|
||||
<add key="PreferredDumpSpeedDVD" value="24"/>
|
||||
<add key="PreferredDumpSpeedBD" value="16"/>
|
||||
<add key="QuietMode" value="false"/>
|
||||
<add key="ParanoidMode" value="false"/>
|
||||
<add key="ScanForProtection" value="true"/>
|
||||
<add key="SkipMediaTypeDetection" value="false"/>
|
||||
<add key="SkipSystemDetection" value="false"/>
|
||||
<add key="RereadAmountForC2" value="20"/>
|
||||
<add key="VerboseLogging" value="true"/>
|
||||
<add key="OpenLogWindowAtStartup" value="true"/>
|
||||
<add key="AddPlaceholders" value="true"/>
|
||||
<add key="Username" value=""/>
|
||||
<add key="Password" value=""/>
|
||||
</appSettings>
|
||||
</configuration>
|
||||
@@ -1,9 +0,0 @@
|
||||
<Application x:Class="DICUI.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:DICUI"
|
||||
StartupUri="Windows\MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
@@ -1,11 +0,0 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace DICUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Media;
|
||||
using DICUI.Data;
|
||||
|
||||
namespace DICUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Variables for UI elements
|
||||
/// </summary>
|
||||
public static class Constants
|
||||
{
|
||||
public const string StartDumping = "Start Dumping";
|
||||
public const string StopDumping = "Stop Dumping";
|
||||
|
||||
public const int LogWindowMarginFromMainWindow = 10;
|
||||
|
||||
// Private lists of known drive speed ranges
|
||||
private static IReadOnlyList<int> cd { get; } = new List<int> { 1, 2, 3, 4, 6, 8, 12, 16, 20, 24, 32, 40, 44, 48, 52, 56, 72 };
|
||||
private static IReadOnlyList<int> dvd { get; } = cd.Where(s => s <= 24).ToList();
|
||||
private static IReadOnlyList<int> bd { get; } = cd.Where(s => s <= 16).ToList();
|
||||
private static IReadOnlyList<int> unknown { get; } = cd; // TODO: All or {1}? Maybe null?
|
||||
|
||||
/// <summary>
|
||||
/// Get list of all drive speeds for a given MediaType
|
||||
/// </summary>
|
||||
/// <param name="type">MediaType? that represents the current item</param>
|
||||
/// <returns>Read-only list of drive speeds</returns>
|
||||
public static IReadOnlyList<int> GetSpeedsForMediaType(MediaType? type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
case MediaType.GDROM:
|
||||
return cd;
|
||||
case MediaType.DVD:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return dvd;
|
||||
case MediaType.BluRay:
|
||||
return bd;
|
||||
default:
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
||||
// Create collections for UI based on known drive speeds
|
||||
public static DoubleCollection SpeedsForCDAsCollection { get; } = GetDoubleCollectionFromIntList(cd);
|
||||
public static DoubleCollection SpeedsForDVDAsCollection { get; } = GetDoubleCollectionFromIntList(dvd);
|
||||
public static DoubleCollection SpeedsForBDAsCollection { get; } = GetDoubleCollectionFromIntList(bd);
|
||||
private static DoubleCollection GetDoubleCollectionFromIntList(IReadOnlyList<int> list)
|
||||
=> new DoubleCollection(list.Select(i => Convert.ToDouble(i)).ToList());
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{7B1B75EB-8940-466F-BD51-76471A57F9BE}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>DICUI</RootNamespace>
|
||||
<AssemblyName>DICUI</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<PublishUrl>C:\Users\admin\Desktop\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<ApplicationRevision>1</ApplicationRevision>
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<PublishWizardCompleted>true</PublishWizardCompleted>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>Icon.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ManifestCertificateThumbprint>654CEE5FEAF46C8C1C369D7ED34DA157828A8D2F</ManifestCertificateThumbprint>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ManifestKeyFile>WpfApp1_TemporaryKey.pfx</ManifestKeyFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<GenerateManifests>true</GenerateManifests>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignManifests>false</SignManifests>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup />
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Xaml">
|
||||
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="App.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Compile Include="Constants.cs" />
|
||||
<Compile Include="EnumDescriptionConverter.cs" />
|
||||
<Compile Include="MediaTypeComboBoxItem.cs" />
|
||||
<Compile Include="Options.cs" />
|
||||
<Compile Include="Windows\LogWindow.xaml.cs">
|
||||
<DependentUpon>LogWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\OptionsWindow.xaml.cs">
|
||||
<DependentUpon>OptionsWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="KnownSystemComboBoxItem.cs" />
|
||||
<Compile Include="ViewModels.cs" />
|
||||
<Page Include="Windows\LogWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\MainWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="App.xaml.cs">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Windows\MainWindow.xaml.cs">
|
||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Page Include="Windows\OptionsWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include=".NETFramework,Version=v4.6.1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Microsoft .NET Framework 4.6.1 %28x86 and x64%29</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Icon.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DICUI.Library\DICUI.Library.csproj">
|
||||
<Project>{51ab0928-13f9-44bf-a407-b6957a43a056}</Project>
|
||||
<Name>DICUI.Library</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -1,33 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
|
||||
namespace DICUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to provide a converter to XAML files to render comboboxes with enum values
|
||||
/// </summary>
|
||||
public class EnumDescriptionConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is DICCommand)
|
||||
return ((DICCommand)value).LongName();
|
||||
else if (value is DICFlag)
|
||||
return ((DICFlag)value).LongName();
|
||||
else if (value is MediaType?)
|
||||
return ((MediaType?)value).LongName();
|
||||
else if (value is KnownSystem?)
|
||||
return ((KnownSystem?)value).LongName();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System.Windows.Media;
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
|
||||
namespace DICUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single item in the System combo box
|
||||
/// </summary>
|
||||
public class KnownSystemComboBoxItem
|
||||
{
|
||||
private object data;
|
||||
|
||||
public KnownSystemComboBoxItem(KnownSystem? system) => data = system;
|
||||
public KnownSystemComboBoxItem(KnownSystemCategory? category) => data = category;
|
||||
|
||||
public Brush Foreground { get => IsHeader() ? Brushes.Gray : Brushes.Black; }
|
||||
|
||||
public bool IsHeader() => data is KnownSystemCategory?;
|
||||
public bool IsSystem() => data is KnownSystem?;
|
||||
|
||||
public static implicit operator KnownSystem? (KnownSystemComboBoxItem item) => item.data as KnownSystem?;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsHeader())
|
||||
return "---------- " + (data as KnownSystemCategory?).LongName() + " ----------";
|
||||
else
|
||||
return (data as KnownSystem?).LongName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
|
||||
namespace DICUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single item in the MediaType combo box
|
||||
/// </summary>
|
||||
public class MediaTypeComboBoxItem
|
||||
{
|
||||
private MediaType? data;
|
||||
|
||||
public MediaTypeComboBoxItem(MediaType? mediaType) => data = mediaType;
|
||||
|
||||
public static implicit operator MediaType? (MediaTypeComboBoxItem item) => item.data;
|
||||
|
||||
public string Name { get { return data.LongName(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
197
DICUI/Options.cs
197
DICUI/Options.cs
@@ -1,197 +0,0 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using DICUI.Data;
|
||||
|
||||
namespace DICUI
|
||||
{
|
||||
public class Options
|
||||
{
|
||||
public string DefaultOutputPath { get; private set; }
|
||||
public string DICPath { get; private set; }
|
||||
public string SubDumpPath { get; private set; }
|
||||
|
||||
public int PreferredDumpSpeedCD { get; set; }
|
||||
public int PreferredDumpSpeedDVD { get; set; }
|
||||
public int PreferredDumpSpeedBD { get; set; }
|
||||
|
||||
public bool QuietMode { get; set; }
|
||||
public bool ParanoidMode { get; set; }
|
||||
public bool ScanForProtection { get; set; }
|
||||
public int RereadAmountForC2 { get; set; }
|
||||
public bool AddPlaceholders { get; set; }
|
||||
|
||||
public bool SkipMediaTypeDetection { get; set; }
|
||||
public bool SkipSystemDetection { get; set; }
|
||||
|
||||
public bool VerboseLogging { get; set; }
|
||||
public bool OpenLogWindowAtStartup { get; set; }
|
||||
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
|
||||
public void Save()
|
||||
{
|
||||
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
|
||||
|
||||
//TODO: reflection is used
|
||||
//TODO: is remove needed, doesn't the value get directly overridden
|
||||
Array.ForEach(
|
||||
GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance),
|
||||
p => {
|
||||
configFile.AppSettings.Settings.Remove(p.Name);
|
||||
configFile.AppSettings.Settings.Add(p.Name, Convert.ToString(p.GetValue(this)));
|
||||
}
|
||||
);
|
||||
|
||||
configFile.Save(ConfigurationSaveMode.Modified);
|
||||
}
|
||||
|
||||
public void Load()
|
||||
{
|
||||
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
|
||||
|
||||
//TODO: hardcoded, we should find a better way
|
||||
this.DICPath = GetStringSetting(configFile, "DICPath", "Programs\\DiscImageCreator.exe");
|
||||
this.SubDumpPath = GetStringSetting(configFile, "SubDumpPath", "subdump.exe");
|
||||
this.DefaultOutputPath = GetStringSetting(configFile, "DefaultOutputPath", "ISO");
|
||||
|
||||
this.PreferredDumpSpeedCD = GetInt32Setting(configFile, "PreferredDumpSpeedCD", 72);
|
||||
this.PreferredDumpSpeedDVD = GetInt32Setting(configFile, "PreferredDumpSpeedDVD", 24);
|
||||
this.PreferredDumpSpeedBD = GetInt32Setting(configFile, "PreferredDumpSpeedBD", 16);
|
||||
|
||||
this.QuietMode = GetBooleanSetting(configFile, "QuietMode", false);
|
||||
this.ParanoidMode = GetBooleanSetting(configFile, "ParanoidMode", false);
|
||||
this.ScanForProtection = GetBooleanSetting(configFile, "ScanForProtection", true);
|
||||
this.SkipMediaTypeDetection = GetBooleanSetting(configFile, "SkipMediaTypeDetection", false);
|
||||
this.SkipSystemDetection = GetBooleanSetting(configFile, "SkipSystemDetection", false);
|
||||
this.RereadAmountForC2 = GetInt32Setting(configFile, "RereadAmountForC2", 20);
|
||||
this.VerboseLogging = GetBooleanSetting(configFile, "VerboseLogging", true);
|
||||
this.OpenLogWindowAtStartup = GetBooleanSetting(configFile, "OpenLogWindowAtStartup", true);
|
||||
this.AddPlaceholders = GetBooleanSetting(configFile, "AddPlaceholders", true);
|
||||
|
||||
this.Username = GetStringSetting(configFile, "Username", "");
|
||||
this.Password = GetStringSetting(configFile, "Password", "");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a boolean setting from a configuration
|
||||
/// </summary>
|
||||
/// <param name="configFile">Current configuration file</param>
|
||||
/// <param name="key">Setting key to get a value for</param>
|
||||
/// <param name="defaultValue">Default value to return if no value is found</param>
|
||||
/// <returns>Setting value if possible, default value otherwise</returns>
|
||||
public bool GetBooleanSetting(Configuration configFile, string key, bool defaultValue)
|
||||
{
|
||||
var settings = configFile.AppSettings.Settings;
|
||||
if (settings.AllKeys.Contains(key))
|
||||
{
|
||||
if (Boolean.TryParse(settings[key].Value, out bool value))
|
||||
return value;
|
||||
else
|
||||
return defaultValue;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a boolean setting from a configuration
|
||||
/// </summary>
|
||||
/// <param name="configFile">Current configuration file</param>
|
||||
/// <param name="key">Setting key to get a value for</param>
|
||||
/// <param name="defaultValue">Default value to return if no value is found</param>
|
||||
/// <returns>Setting value if possible, default value otherwise</returns>
|
||||
public int GetInt32Setting(Configuration configFile, string key, int defaultValue)
|
||||
{
|
||||
var settings = configFile.AppSettings.Settings;
|
||||
if (settings.AllKeys.Contains(key))
|
||||
{
|
||||
if (Int32.TryParse(settings[key].Value, out int value))
|
||||
return value;
|
||||
else
|
||||
return defaultValue;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a boolean setting from a configuration
|
||||
/// </summary>
|
||||
/// <param name="configFile">Current configuration file</param>
|
||||
/// <param name="key">Setting key to get a value for</param>
|
||||
/// <param name="defaultValue">Default value to return if no value is found</param>
|
||||
/// <returns>Setting value if possible, default value otherwise</returns>
|
||||
public long GetInt64Setting(Configuration configFile, string key, long defaultValue)
|
||||
{
|
||||
var settings = configFile.AppSettings.Settings;
|
||||
if (settings.AllKeys.Contains(key))
|
||||
{
|
||||
if (Int64.TryParse(settings[key].Value, out long value))
|
||||
return value;
|
||||
else
|
||||
return defaultValue;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a boolean setting from a configuration
|
||||
/// </summary>
|
||||
/// <param name="configFile">Current configuration file</param>
|
||||
/// <param name="key">Setting key to get a value for</param>
|
||||
/// <param name="defaultValue">Default value to return if no value is found</param>
|
||||
/// <returns>Setting value if possible, default value otherwise</returns>
|
||||
public string GetStringSetting(Configuration configFile, string key, string defaultValue)
|
||||
{
|
||||
var settings = configFile.AppSettings.Settings;
|
||||
if (settings.AllKeys.Contains(key))
|
||||
return settings[key].Value;
|
||||
else
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
//TODO: probably should be generic for non-string options
|
||||
//TODO: using reflection for Set and Get is orthodox but it works, should be changed to a key,value map probably
|
||||
public void Set(string key, string value)
|
||||
{
|
||||
GetType().GetProperty(key, BindingFlags.Public | BindingFlags.Instance).SetValue(this, value);
|
||||
}
|
||||
|
||||
public string Get(string key)
|
||||
{
|
||||
return GetType().GetProperty(key, BindingFlags.Public | BindingFlags.Instance).GetValue(this) as string;
|
||||
}
|
||||
|
||||
public int GetPreferredDumpSpeedForMediaType(MediaType? type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
case MediaType.GDROM:
|
||||
return PreferredDumpSpeedCD;
|
||||
case MediaType.DVD:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return PreferredDumpSpeedDVD;
|
||||
case MediaType.BluRay:
|
||||
return PreferredDumpSpeedBD;
|
||||
default:
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("DICUI")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("DICUI")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2019")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//In order to begin building localizable applications, set
|
||||
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||
//inside a <PropertyGroup>. For example, if you are using US english
|
||||
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||
//the line below to match the UICulture setting in the project file.
|
||||
|
||||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
||||
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.13")]
|
||||
[assembly: AssemblyFileVersion("1.13.0.0")]
|
||||
|
||||
// Anything marked as internal can be used by the test methods
|
||||
[assembly: InternalsVisibleTo("DICUI.Test")]
|
||||
@@ -1,113 +0,0 @@
|
||||
using System;
|
||||
using System.Windows.Media;
|
||||
using DICUI.Windows;
|
||||
|
||||
namespace DICUI
|
||||
{
|
||||
public class OptionsViewModel
|
||||
{
|
||||
private Options _options;
|
||||
|
||||
public OptionsViewModel(Options options)
|
||||
{
|
||||
this._options = options;
|
||||
}
|
||||
|
||||
public bool QuietMode
|
||||
{
|
||||
get { return _options.QuietMode; }
|
||||
set { _options.QuietMode = value; }
|
||||
}
|
||||
|
||||
public bool ParanoidMode
|
||||
{
|
||||
get { return _options.ParanoidMode; }
|
||||
set { _options.ParanoidMode = value; }
|
||||
}
|
||||
|
||||
public bool ScanForProtection
|
||||
{
|
||||
get { return _options.ScanForProtection; }
|
||||
set { _options.ScanForProtection = value; }
|
||||
}
|
||||
|
||||
public bool SkipMediaTypeDetection
|
||||
{
|
||||
get { return _options.SkipMediaTypeDetection; }
|
||||
set { _options.SkipMediaTypeDetection = value; }
|
||||
}
|
||||
|
||||
public bool SkipSystemDetection
|
||||
{
|
||||
get { return _options.SkipSystemDetection; }
|
||||
set { _options.SkipSystemDetection = value; }
|
||||
}
|
||||
|
||||
public string RereadAmountForC2
|
||||
{
|
||||
get { return Convert.ToString(_options.RereadAmountForC2); }
|
||||
set
|
||||
{
|
||||
if (Int32.TryParse(value, out int result))
|
||||
_options.RereadAmountForC2 = result;
|
||||
}
|
||||
}
|
||||
|
||||
public bool VerboseLogging
|
||||
{
|
||||
get { return _options.VerboseLogging; }
|
||||
set
|
||||
{
|
||||
_options.VerboseLogging = value;
|
||||
_options.Save();
|
||||
}
|
||||
}
|
||||
|
||||
public bool OpenLogWindowAtStartup
|
||||
{
|
||||
get { return _options.OpenLogWindowAtStartup; }
|
||||
set
|
||||
{
|
||||
_options.OpenLogWindowAtStartup = value;
|
||||
_options.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LoggerViewModel
|
||||
{
|
||||
private LogWindow _logWindow;
|
||||
|
||||
public void SetWindow(LogWindow logWindow) => _logWindow = logWindow;
|
||||
|
||||
public bool WindowVisible
|
||||
{
|
||||
get => _logWindow != null ? _logWindow.IsVisible : false;
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
_logWindow.AdjustPositionToMainWindow();
|
||||
_logWindow.Show();
|
||||
}
|
||||
else
|
||||
_logWindow.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
public void VerboseLog(string text)
|
||||
{
|
||||
if (ViewModels.OptionsViewModel.VerboseLogging)
|
||||
_logWindow.AppendToTextBox(text, Brushes.Yellow);
|
||||
}
|
||||
|
||||
public void VerboseLog(string format, params object[] args) => VerboseLog(string.Format(format, args));
|
||||
public void VerboseLogLn(string format, params object[] args) => VerboseLog(string.Format(format, args) + "\n");
|
||||
}
|
||||
|
||||
public static class ViewModels
|
||||
{
|
||||
public static OptionsViewModel OptionsViewModel { get; set; }
|
||||
public static LoggerViewModel LoggerViewModel { get; set; } = new LoggerViewModel();
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
<Window x:Class="DICUI.Windows.LogWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:DICUI"
|
||||
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
|
||||
Title="Log Window" Height="350" Width="600" Closed="OnWindowClosed" Loaded="OnWindowLoaded"
|
||||
>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="40" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="40" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0" Height="22" Margin="10 10 10 0">
|
||||
<ProgressBar x:Name="progressBar" />
|
||||
<TextBlock x:Name="progressLabel" Grid.Row="0" Height="22" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="0 2 0 0" />
|
||||
</Grid>
|
||||
<Border Grid.Row="1" Background="White" BorderBrush="Gainsboro" BorderThickness="1" Margin="10">
|
||||
<ScrollViewer Name="outputViewer" SizeChanged="ScrollViewer_SizeChanged">
|
||||
<RichTextBox Name="output" FontFamily="Consolas" Background="#202020" IsReadOnly="true" TextChanged="OnTextChanged" />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
|
||||
<Grid Grid.Row="2">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="4*"/>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<CheckBox Content="Verbose" Margin="10 0 0 10" Grid.Column="0" VerticalAlignment="Center"
|
||||
ToolTip="Enable verbose logging of tasks"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
|
||||
IsChecked="{Binding Path=VerboseLogging}"
|
||||
/>
|
||||
<CheckBox Content="Open at startup" Margin="10 0 0 10" Grid.Column="1" Grid.ColumnSpan="2" VerticalAlignment="Center"
|
||||
ToolTip="Open this window at startup"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
|
||||
IsChecked="{Binding Path=OpenLogWindowAtStartup}"
|
||||
/>
|
||||
<Button Margin="0 0 10 10" Grid.Column="3" Height="22" Width="60" Content="Clear" HorizontalAlignment="Right" Click="OnClearButton" />
|
||||
<Button Margin="0 0 10 10" Grid.Column="4" Height="22" Width="60" Content="Hide" HorizontalAlignment="Right" Click="OnHideButton" />
|
||||
<Button Visibility="Hidden" Name="AbortButton" Margin="0 0 10 10" Grid.Column="2" Height="22" Width="80" Content="Abort" HorizontalAlignment="Right" Click="OnAbortButton" />
|
||||
</Grid>
|
||||
|
||||
|
||||
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,385 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace DICUI.Windows
|
||||
{
|
||||
public partial class LogWindow : Window
|
||||
{
|
||||
private const int GWL_STYLE = -16;
|
||||
private const int WS_SYSMENU = 0x80000;
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
|
||||
[DllImport("user32.dll")]
|
||||
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
|
||||
|
||||
private MainWindow _mainWindow;
|
||||
|
||||
private FlowDocument _document;
|
||||
private Paragraph _paragraph;
|
||||
private List<Matcher> _matchers;
|
||||
|
||||
volatile Process _process;
|
||||
|
||||
public LogWindow(MainWindow mainWindow)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
this._mainWindow = mainWindow;
|
||||
|
||||
_document = new FlowDocument();
|
||||
_paragraph = new Paragraph();
|
||||
_document.Blocks.Add(_paragraph);
|
||||
output.Document = _document;
|
||||
|
||||
_matchers = new List<Matcher>();
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Descrambling data sector of img (LBA)",
|
||||
@"\s*(\d+)\/\s*(\d+)$",
|
||||
match => {
|
||||
if (UInt32.TryParse(match.Groups[1].Value, out uint current) && UInt32.TryParse(match.Groups[2].Value, out uint total))
|
||||
{
|
||||
float percentProgress = (current / (float)total) * 100;
|
||||
progressBar.Value = percentProgress;
|
||||
progressLabel.Text = string.Format("Descrambling image.. ({0:##.##}%)", percentProgress);
|
||||
}
|
||||
}));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
@"Creating .scm (LBA)",
|
||||
@"\s*(\d+)\/\s*(\d+)$",
|
||||
match => {
|
||||
if (UInt32.TryParse(match.Groups[1].Value, out uint current) && UInt32.TryParse(match.Groups[2].Value, out uint total))
|
||||
{
|
||||
float percentProgress = (current / (float)total) * 100;
|
||||
progressBar.Value = percentProgress;
|
||||
progressLabel.Text = string.Format("Creating scrambled image.. ({0:##.##}%)", percentProgress);
|
||||
}
|
||||
}));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Checking sectors (LBA)",
|
||||
@"\s*(\d+)\/\s*(\d+)$",
|
||||
match => {
|
||||
if (UInt32.TryParse(match.Groups[1].Value, out uint current) && UInt32.TryParse(match.Groups[2].Value, out uint total))
|
||||
{
|
||||
float percentProgress = (current / (float)total) * 100;
|
||||
progressBar.Value = percentProgress;
|
||||
progressLabel.Text = string.Format("Checking for errors.. ({0:##.##}%)", percentProgress);
|
||||
}
|
||||
}));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Scanning sector (LBA)",
|
||||
@"\s*(\d+)\/\s*(\d+)$",
|
||||
match => {
|
||||
if (UInt32.TryParse(match.Groups[1].Value, out uint current) && UInt32.TryParse(match.Groups[2].Value, out uint total))
|
||||
{
|
||||
float percentProgress = (current / (float)total) * 100;
|
||||
progressBar.Value = percentProgress;
|
||||
progressLabel.Text = string.Format("Scanning sectors for protection.. ({0:##.##}%)", percentProgress);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public void StartDump(string args)
|
||||
{
|
||||
AppendToTextBox(string.Format("Launching DIC with args: {0}\r\n", args), Brushes.Orange);
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
_process = new Process()
|
||||
{
|
||||
StartInfo = new ProcessStartInfo()
|
||||
{
|
||||
FileName = @"Programs/DiscImageCreator.exe",
|
||||
Arguments = args,
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
},
|
||||
};
|
||||
|
||||
StreamState stdoutState = new StreamState(false);
|
||||
StreamState stderrState = new StreamState(true);
|
||||
|
||||
//_cmd.ErrorDataReceived += (process, text) => Dispatcher.Invoke(() => UpdateConsole(text.Data, Brushes.Red));
|
||||
_process.Start();
|
||||
|
||||
var _1 = ConsumeOutput(_process.StandardOutput, s => Dispatcher.Invoke(() => UpdateConsole(s, stdoutState)));
|
||||
var _2 = ConsumeOutput(_process.StandardError, s => Dispatcher.Invoke(() => UpdateConsole(s, stderrState)));
|
||||
|
||||
_process.EnableRaisingEvents = true;
|
||||
_process.Exited += OnProcessExit;
|
||||
});
|
||||
}
|
||||
|
||||
public void AdjustPositionToMainWindow()
|
||||
{
|
||||
this.Left = _mainWindow.Left;
|
||||
this.Top = _mainWindow.Top + _mainWindow.Height + Constants.LogWindowMarginFromMainWindow;
|
||||
}
|
||||
|
||||
private void GracefullyTerminateProcess()
|
||||
{
|
||||
if (_process != null)
|
||||
{
|
||||
_process.Exited -= OnProcessExit;
|
||||
bool isForced = !_process.HasExited;
|
||||
|
||||
if (isForced)
|
||||
{
|
||||
AppendToTextBox("\r\nForcefully Killing the process\r\n", Brushes.Red);
|
||||
_process.Kill();
|
||||
_process.WaitForExit();
|
||||
}
|
||||
|
||||
AppendToTextBox(string.Format("\r\nExit Code: {0}\r\n", _process.ExitCode), _process.ExitCode == 0 ? Brushes.Green : Brushes.Red);
|
||||
|
||||
if (_process.ExitCode == 0)
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
progressLabel.Text = "Done!";
|
||||
progressBar.Value = 100;
|
||||
progressBar.Foreground = Brushes.Green;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
progressLabel.Text = isForced ? "Aborted by user" : "Error, please check log!";
|
||||
progressBar.Value = 100;
|
||||
progressBar.Foreground = Brushes.Red;
|
||||
});
|
||||
}
|
||||
|
||||
_process.Close();
|
||||
}
|
||||
|
||||
_process = null;
|
||||
}
|
||||
|
||||
private void ScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
outputViewer.ScrollToBottom();
|
||||
}
|
||||
|
||||
async Task ConsumeOutput(TextReader reader, Action<string> callback)
|
||||
{
|
||||
char[] buffer = new char[256];
|
||||
int cch;
|
||||
|
||||
while ((cch = await reader.ReadAsync(buffer, 0, buffer.Length)) > 0)
|
||||
{
|
||||
callback(new string(buffer, 0, cch));
|
||||
}
|
||||
}
|
||||
|
||||
// this is used to optimize the work since we need to process A LOT of text
|
||||
struct Matcher
|
||||
{
|
||||
private readonly String prefix;
|
||||
private readonly Regex regex;
|
||||
private readonly int start;
|
||||
private readonly Action<Match> lambda;
|
||||
|
||||
public Matcher(String prefix, String regex, Action<Match> lambda)
|
||||
{
|
||||
this.prefix = prefix;
|
||||
this.regex = new Regex(regex);
|
||||
this.start = prefix.Length;
|
||||
this.lambda = lambda;
|
||||
}
|
||||
|
||||
public bool Matches(ref string text) => text.StartsWith(prefix);
|
||||
|
||||
public void Apply(ref string text)
|
||||
{
|
||||
Match match = regex.Match(text, start);
|
||||
lambda.Invoke(match);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessStringForProgressBar(string text)
|
||||
{
|
||||
foreach (Matcher matcher in _matchers)
|
||||
{
|
||||
if (matcher.Matches(ref text))
|
||||
{
|
||||
matcher.Apply(ref text);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class StreamState
|
||||
{
|
||||
public enum State
|
||||
{
|
||||
BEGIN,
|
||||
READ_CARRIAGE,
|
||||
};
|
||||
|
||||
public State state;
|
||||
public readonly StringBuilder buffer;
|
||||
public readonly bool isError;
|
||||
|
||||
public StreamState(bool isError)
|
||||
{
|
||||
this.state = State.BEGIN;
|
||||
this.buffer = new StringBuilder();
|
||||
this.isError = isError;
|
||||
}
|
||||
|
||||
public bool HasData() => buffer.Length > 0;
|
||||
public string Fetch() => buffer.ToString();
|
||||
public void Clear() => buffer.Clear();
|
||||
public void Append(char c) => buffer.Append(c);
|
||||
|
||||
public bool Is(State state) => this.state == state;
|
||||
public void Set(State state) => this.state = state;
|
||||
}
|
||||
|
||||
public void AppendToTextBox(string text, Brush color)
|
||||
{
|
||||
if (Application.Current.Dispatcher.CheckAccess())
|
||||
{
|
||||
Run run = new Run(text) { Foreground = color };
|
||||
_paragraph.Inlines.Add(run);
|
||||
}
|
||||
else
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
Run run = new Run(text) { Foreground = color };
|
||||
_paragraph.Inlines.Add(run);
|
||||
});
|
||||
}
|
||||
|
||||
private void UpdateConsole(string text, StreamState state)
|
||||
{
|
||||
/*if (c == '\r') { output.Inlines.Add(@"\r"); file.Write("\\r"); }
|
||||
else if (c == '\n') { output.Inlines.Add(@"\n"); file.Write("\\n\n"); }
|
||||
output.Inlines.Add(""+c);
|
||||
file.Write(c);
|
||||
file.Flush();
|
||||
continue;*/
|
||||
|
||||
if (text != null)
|
||||
{
|
||||
foreach (char c in text)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '\r' when (state.Is(StreamState.State.BEGIN)):
|
||||
{
|
||||
state.Set(StreamState.State.READ_CARRIAGE);
|
||||
break;
|
||||
}
|
||||
|
||||
case '\n' when (state.Is(StreamState.State.READ_CARRIAGE)):
|
||||
{
|
||||
if (state.buffer.Length > 0)
|
||||
{
|
||||
string buffer = state.Fetch();
|
||||
|
||||
AppendToTextBox(buffer, state.isError ? Brushes.Red : Brushes.White);
|
||||
|
||||
if (!state.isError)
|
||||
ProcessStringForProgressBar(buffer);
|
||||
}
|
||||
_paragraph.Inlines.Add(new LineBreak());
|
||||
state.Clear();
|
||||
state.Set(StreamState.State.BEGIN);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (state.Is(StreamState.State.READ_CARRIAGE) && state.HasData())
|
||||
{
|
||||
if (!(_paragraph.Inlines.LastInline is LineBreak))
|
||||
_paragraph.Inlines.Remove(_paragraph.Inlines.LastInline);
|
||||
|
||||
string buffer = state.Fetch();
|
||||
|
||||
AppendToTextBox(buffer, state.isError ? Brushes.Red : Brushes.White);
|
||||
|
||||
if (!state.isError)
|
||||
ProcessStringForProgressBar(buffer);
|
||||
|
||||
state.Clear();
|
||||
}
|
||||
|
||||
state.Set(StreamState.State.BEGIN);
|
||||
state.Append(c);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region EventHandlers
|
||||
|
||||
private void OnWindowClosed(object sender, EventArgs e)
|
||||
{
|
||||
GracefullyTerminateProcess();
|
||||
}
|
||||
|
||||
private void OnWindowLoaded(object sender, EventArgs e)
|
||||
{
|
||||
var hwnd = new WindowInteropHelper(this).Handle;
|
||||
SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
|
||||
}
|
||||
|
||||
void OnProcessExit(object sender, EventArgs e)
|
||||
{
|
||||
Dispatcher.Invoke(() => AbortButton.IsEnabled = false);
|
||||
GracefullyTerminateProcess();
|
||||
}
|
||||
|
||||
private void OnHideButton(object sender, EventArgs e)
|
||||
{
|
||||
ViewModels.LoggerViewModel.WindowVisible = false;
|
||||
//TODO: this should be bound directly to WindowVisible property in two way fashion
|
||||
// we need to study how to properly do it in XAML
|
||||
_mainWindow.ShowLogMenuItem.IsChecked = false;
|
||||
}
|
||||
|
||||
private void OnClearButton(object sender, EventArgs e)
|
||||
{
|
||||
output.Document.Blocks.Clear();
|
||||
}
|
||||
|
||||
private void OnAbortButton(object sender, EventArgs args)
|
||||
{
|
||||
GracefullyTerminateProcess();
|
||||
}
|
||||
|
||||
private void OnStartButton(object sender, EventArgs args)
|
||||
{
|
||||
StartDump("cd e Gam.iso 16");
|
||||
}
|
||||
|
||||
private void OnTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
outputViewer.ScrollToBottom();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
<Window x:Class="DICUI.Windows.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:DICUI"
|
||||
mc:Ignorable="d"
|
||||
Title="Disc Image Creator GUI" Height="450" Width="600" WindowStartupLocation="CenterScreen" ResizeMode="CanMinimize"
|
||||
LocationChanged="MainWindowLocationChanged" Activated="MainWindowActivated" Closing="MainWindowClosing">
|
||||
|
||||
<Window.Resources>
|
||||
<local:EnumDescriptionConverter x:Key="enumConverter" />
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="4*"/>
|
||||
<ColumnDefinition Width="13*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="4*"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel VerticalAlignment="Top" Grid.ColumnSpan="4">
|
||||
<Menu Width="Auto" Height="20" >
|
||||
<MenuItem Header="_File">
|
||||
<MenuItem x:Name="AppExit" Header="E_xit" HorizontalAlignment="Left" Width="140" Click="AppExitClick" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="_Tools">
|
||||
<MenuItem x:Name="OptionsMenuItem" Header="_Options" HorizontalAlignment="Left" Width="140" Click="OptionsClick"/>
|
||||
<MenuItem x:Name="ShowLogMenuItem" Header="Show _Log Window" IsCheckable="true" HorizontalAlignment="Left"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.LoggerViewModel}}"
|
||||
IsChecked="{Binding Path=WindowVisible}"
|
||||
/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="_Help">
|
||||
<MenuItem x:Name="About" Header="_About" HorizontalAlignment="Left" Width="140" Click="AboutClick"/>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</StackPanel>
|
||||
<GroupBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="5,5,5.2,5.4" HorizontalAlignment="Stretch" Header="Settings"/>
|
||||
<GroupBox Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="5,4.6,5.2,4.8" HorizontalAlignment="Stretch" Header="Controls"/>
|
||||
<GroupBox Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Margin="5,5.2,5.2,4.8" HorizontalAlignment="Stretch" Header="Status"/>
|
||||
|
||||
<Grid Grid.Row="1" Grid.Column="0" Margin="15,25,15.2,10.4" Grid.ColumnSpan="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="2.5*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Content="System/Media Type" />
|
||||
<ComboBox x:Name="SystemTypeComboBox" Grid.Row="0" Grid.Column="1" Height="22" Width="250" HorizontalAlignment="Left" SelectionChanged="SystemTypeComboBoxSelectionChanged">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Path=Name}" Foreground="{Binding Path=Foreground}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
<ComboBox x:Name="MediaTypeComboBox" Grid.Row="0" Grid.Column="1" Height="22" Width="140" HorizontalAlignment="Right" SelectionChanged="MediaTypeComboBoxSelectionChanged">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Converter={StaticResource enumConverter}}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" VerticalAlignment="Center">Output Filename</Label>
|
||||
<TextBox x:Name="OutputFilenameTextBox" Grid.Row="1" Grid.Column="1" Height="22" TextChanged="OutputFilenameTextBoxTextChanged" />
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" VerticalAlignment="Center">Output Directory</Label>
|
||||
<TextBox x:Name="OutputDirectoryTextBox" Grid.Row="2" Grid.Column="1" Height="22" Width="345" HorizontalAlignment="Left" TextChanged="OutputDirectoryTextBoxTextChanged" />
|
||||
<Button x:Name="OutputDirectoryBrowseButton" Grid.Row="2" Grid.Column="1" Height="22" Width="50" HorizontalAlignment="Right" Content="Browse" Click="OutputDirectoryBrowseButtonClick"/>
|
||||
|
||||
<Label Grid.Row="3" Grid.Column="0" VerticalAlignment="Center">Drive Letter</Label>
|
||||
<ComboBox x:Name="DriveLetterComboBox" Grid.Row="3" Grid.Column="1" Height="22" Width="60" HorizontalAlignment="Left" SelectionChanged="DriveLetterComboBoxSelectionChanged">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Path=Letter}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<Label Grid.Row="4" Grid.Column="0" VerticalAlignment="Center">Drive Speed</Label>
|
||||
<ComboBox x:Name="DriveSpeedComboBox" Grid.Row="4" Grid.Column="1" Height="22" Width="60" HorizontalAlignment="Left" SelectionChanged="DriveSpeedComboBoxSelectionChanged" />
|
||||
|
||||
<Label Grid.Row="5" Grid.Column="0" VerticalAlignment="Center">Parameters</Label>
|
||||
<TextBox x:Name="ParametersTextBox" Grid.Row="5" Grid.Column="1" Height="22" Width="370" HorizontalAlignment="Left" IsEnabled="False" />
|
||||
<CheckBox x:Name="EnableParametersCheckBox" Grid.Row="5" Grid.Column="1" Height="22" HorizontalAlignment="Right" IsChecked="False" Click="EnableParametersCheckBoxClick" />
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="2" Grid.Column="0" Margin="15,19.6,15.2,9.8" Grid.ColumnSpan="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Button x:Name="StartStopButton" Grid.Row="0" Grid.Column="0" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Start Dumping" Click="StartStopButtonClick" IsEnabled="False" />
|
||||
<Button x:Name="DiskScanButton" Grid.Row="0" Grid.Column="1" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Scan for disks" Click="DiskScanButtonClick" />
|
||||
<Button x:Name="CopyProtectScanButton" Grid.Row="0" Grid.Column="2" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Scan for protection" Click="CopyProtectScanButtonClick" />
|
||||
<CheckBox x:Name="EjectWhenDoneCheckBox" Grid.Row="0" Grid.Column="3" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Eject When Done" IsChecked="False" />
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="3" Grid.Column="0" Margin="15,20.2,15.2,9.8" Grid.ColumnSpan="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label x:Name="StatusLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Waiting for media..." />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,740 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using WinForms = System.Windows.Forms;
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
|
||||
namespace DICUI.Windows
|
||||
{
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
// Private UI-related variables
|
||||
private List<Drive> _drives;
|
||||
private MediaType? _currentMediaType;
|
||||
private List<KnownSystemComboBoxItem> _systems;
|
||||
private List<MediaType?> _mediaTypes;
|
||||
private bool _alreadyShown;
|
||||
|
||||
private DumpEnvironment _env;
|
||||
|
||||
// Option related
|
||||
private Options _options;
|
||||
private OptionsWindow _optionsWindow;
|
||||
|
||||
private LogWindow _logWindow;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// Initializes and load Options object
|
||||
_options = new Options();
|
||||
_options.Load();
|
||||
ViewModels.OptionsViewModel = new OptionsViewModel(_options);
|
||||
|
||||
_logWindow = new LogWindow(this);
|
||||
ViewModels.LoggerViewModel.SetWindow(_logWindow);
|
||||
|
||||
// Disable buttons until we load fully
|
||||
StartStopButton.IsEnabled = false;
|
||||
DiskScanButton.IsEnabled = false;
|
||||
CopyProtectScanButton.IsEnabled = false;
|
||||
|
||||
if (_options.OpenLogWindowAtStartup)
|
||||
{
|
||||
this.WindowStartupLocation = WindowStartupLocation.Manual;
|
||||
double combinedHeight = this.Height + _logWindow.Height + Constants.LogWindowMarginFromMainWindow;
|
||||
Rectangle bounds = GetScaledCoordinates(WinForms.Screen.PrimaryScreen.WorkingArea);
|
||||
|
||||
this.Left = bounds.Left + (bounds.Width - this.Width) / 2;
|
||||
this.Top = bounds.Top + (bounds.Height - combinedHeight) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
#region Events
|
||||
|
||||
protected override void OnContentRendered(EventArgs e)
|
||||
{
|
||||
base.OnContentRendered(e);
|
||||
|
||||
if (_alreadyShown)
|
||||
return;
|
||||
|
||||
_alreadyShown = true;
|
||||
|
||||
if (_options.OpenLogWindowAtStartup)
|
||||
{
|
||||
//TODO: this should be bound directly to WindowVisible property in two way fashion
|
||||
// we need to study how to properly do it in XAML
|
||||
ShowLogMenuItem.IsChecked = true;
|
||||
ViewModels.LoggerViewModel.WindowVisible = true;
|
||||
}
|
||||
|
||||
// Populate the list of systems
|
||||
StatusLabel.Content = "Creating system list, please wait!";
|
||||
PopulateSystems();
|
||||
|
||||
// Populate the list of drives
|
||||
StatusLabel.Content = "Creating drive list, please wait!";
|
||||
PopulateDrives();
|
||||
}
|
||||
|
||||
private void StartStopButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Dump or stop the dump
|
||||
if ((string)StartStopButton.Content == Constants.StartDumping)
|
||||
{
|
||||
StartDumping();
|
||||
}
|
||||
else if ((string)StartStopButton.Content == Constants.StopDumping)
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Canceling dumping process...");
|
||||
_env.CancelDumping();
|
||||
CopyProtectScanButton.IsEnabled = true;
|
||||
|
||||
if (EjectWhenDoneCheckBox.IsChecked == true)
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLogLn($"Ejecting disc in drive {_env.Drive.Letter}");
|
||||
_env.EjectDisc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OutputDirectoryBrowseButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
BrowseFolder();
|
||||
EnsureDiscInformation();
|
||||
}
|
||||
|
||||
private void DiskScanButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
PopulateDrives();
|
||||
}
|
||||
|
||||
private void CopyProtectScanButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ScanAndShowProtection();
|
||||
}
|
||||
|
||||
private void SystemTypeComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
// If we're on a separator, go to the next item and return
|
||||
if ((SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem).IsHeader())
|
||||
{
|
||||
SystemTypeComboBox.SelectedIndex++;
|
||||
return;
|
||||
}
|
||||
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Changed system to: {0}", (SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem).Name);
|
||||
PopulateMediaType();
|
||||
EnsureDiscInformation();
|
||||
}
|
||||
|
||||
private void MediaTypeComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
// Only change the media type if the selection and not the list has changed
|
||||
if (e.RemovedItems.Count == 1 && e.AddedItems.Count == 1)
|
||||
{
|
||||
_currentMediaType = MediaTypeComboBox.SelectedItem as MediaType?;
|
||||
SetSupportedDriveSpeed();
|
||||
}
|
||||
|
||||
GetOutputNames();
|
||||
EnsureDiscInformation();
|
||||
}
|
||||
|
||||
private void DriveLetterComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
CacheCurrentDiscType();
|
||||
SetCurrentDiscType();
|
||||
GetOutputNames();
|
||||
SetSupportedDriveSpeed();
|
||||
}
|
||||
|
||||
private void DriveSpeedComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
EnsureDiscInformation();
|
||||
}
|
||||
|
||||
private void OutputFilenameTextBoxTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
EnsureDiscInformation();
|
||||
}
|
||||
|
||||
private void OutputDirectoryTextBoxTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
EnsureDiscInformation();
|
||||
}
|
||||
|
||||
private void ProgressUpdated(object sender, Result value)
|
||||
{
|
||||
StatusLabel.Content = value.Message;
|
||||
ViewModels.LoggerViewModel.VerboseLogLn(value.Message);
|
||||
}
|
||||
|
||||
private void MainWindowLocationChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (_logWindow.IsVisible)
|
||||
_logWindow.AdjustPositionToMainWindow();
|
||||
}
|
||||
|
||||
private void MainWindowActivated(object sender, EventArgs e)
|
||||
{
|
||||
if (_logWindow.IsVisible && !this.Topmost)
|
||||
{
|
||||
_logWindow.Topmost = true;
|
||||
_logWindow.Topmost = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void MainWindowClosing(object sender, System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
if (_logWindow.IsVisible)
|
||||
_logWindow.Close();
|
||||
}
|
||||
|
||||
private void EnableParametersCheckBoxClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (EnableParametersCheckBox.IsChecked == true)
|
||||
ParametersTextBox.IsEnabled = true;
|
||||
else
|
||||
{
|
||||
ParametersTextBox.IsEnabled = false;
|
||||
ProcessCustomParameters();
|
||||
}
|
||||
}
|
||||
|
||||
// Toolbar Events
|
||||
|
||||
private void AppExitClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
|
||||
private void AboutClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
MessageBox.Show($"ReignStumble - Project Lead / UI Design{Environment.NewLine}" +
|
||||
$"darksabre76 - Project Co-Lead / Backend Design{Environment.NewLine}" +
|
||||
$"Jakz - Feature Contributor{Environment.NewLine}" +
|
||||
$"NHellFire - Feature Contributor{Environment.NewLine}" +
|
||||
$"Dizzzy - Concept/Ideas/Beta tester{Environment.NewLine}", "About", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
|
||||
private void OptionsClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// lazy initialization
|
||||
if (_optionsWindow == null)
|
||||
{
|
||||
_optionsWindow = new OptionsWindow(this, _options);
|
||||
_optionsWindow.Closed += delegate
|
||||
{
|
||||
_optionsWindow = null;
|
||||
};
|
||||
}
|
||||
|
||||
_optionsWindow.Owner = this;
|
||||
_optionsWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||
_optionsWindow.Refresh();
|
||||
_optionsWindow.Show();
|
||||
}
|
||||
|
||||
public void OnOptionsUpdated()
|
||||
{
|
||||
GetOutputNames();
|
||||
SetSupportedDriveSpeed();
|
||||
EnsureDiscInformation();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Populate media type according to system type
|
||||
/// </summary>
|
||||
private void PopulateMediaType()
|
||||
{
|
||||
KnownSystem? currentSystem = SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem;
|
||||
|
||||
if (currentSystem != null)
|
||||
{
|
||||
_mediaTypes = Validators.GetValidMediaTypes(currentSystem);
|
||||
MediaTypeComboBox.ItemsSource = _mediaTypes;
|
||||
|
||||
MediaTypeComboBox.IsEnabled = _mediaTypes.Count > 1;
|
||||
MediaTypeComboBox.SelectedIndex = (_mediaTypes.IndexOf(_currentMediaType) >= 0 ? _mediaTypes.IndexOf(_currentMediaType) : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
MediaTypeComboBox.IsEnabled = false;
|
||||
MediaTypeComboBox.ItemsSource = null;
|
||||
MediaTypeComboBox.SelectedIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a complete list of supported systems and fill the combo box
|
||||
/// </summary>
|
||||
private void PopulateSystems()
|
||||
{
|
||||
var knownSystems = Validators.CreateListOfSystems();
|
||||
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Populating systems, {0} systems found.", knownSystems.Count);
|
||||
|
||||
Dictionary<KnownSystemCategory, List<KnownSystem?>> mapping = knownSystems
|
||||
.GroupBy(s => s.Category())
|
||||
.ToDictionary(
|
||||
k => k.Key,
|
||||
v => v
|
||||
.OrderBy(s => s.LongName())
|
||||
.ToList()
|
||||
);
|
||||
|
||||
_systems = new List<KnownSystemComboBoxItem>();
|
||||
_systems.Add(new KnownSystemComboBoxItem(KnownSystem.NONE));
|
||||
|
||||
foreach (var group in mapping)
|
||||
{
|
||||
_systems.Add(new KnownSystemComboBoxItem(group.Key));
|
||||
group.Value.ForEach(system => _systems.Add(new KnownSystemComboBoxItem(system)));
|
||||
}
|
||||
|
||||
SystemTypeComboBox.ItemsSource = _systems;
|
||||
SystemTypeComboBox.SelectedIndex = 0;
|
||||
|
||||
StartStopButton.IsEnabled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a complete list of active disc drives and fill the combo box
|
||||
/// </summary>
|
||||
/// <remarks>TODO: Find a way for this to periodically run, or have it hook to a "drive change" event</remarks>
|
||||
private void PopulateDrives()
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Scanning for drives..");
|
||||
|
||||
// Always enable the disk scan
|
||||
DiskScanButton.IsEnabled = true;
|
||||
|
||||
// Populate the list of drives and add it to the combo box
|
||||
_drives = Validators.CreateListOfDrives();
|
||||
DriveLetterComboBox.ItemsSource = _drives;
|
||||
|
||||
if (DriveLetterComboBox.Items.Count > 0)
|
||||
{
|
||||
int index = _drives.FindIndex(d => d.MarkedActive);
|
||||
DriveLetterComboBox.SelectedIndex = (index != -1 ? index : 0);
|
||||
StatusLabel.Content = "Valid drive found! Choose your Media Type";
|
||||
CopyProtectScanButton.IsEnabled = true;
|
||||
|
||||
// Get the current optical disc type
|
||||
if (!_options.SkipSystemDetection && index != -1)
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLog("Trying to detect system for drive {0}.. ", _drives[index].Letter);
|
||||
var currentSystem = Validators.GetKnownSystem(_drives[index].Letter);
|
||||
ViewModels.LoggerViewModel.VerboseLogLn(currentSystem == null || currentSystem == KnownSystem.NONE ? "unable to detect." : ("detected " + currentSystem.LongName() + "."));
|
||||
|
||||
if (currentSystem != null && currentSystem != KnownSystem.NONE)
|
||||
{
|
||||
int sysIndex = _systems.FindIndex(s => s == currentSystem);
|
||||
SystemTypeComboBox.SelectedIndex = sysIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// Only enable the start/stop if we don't have the default selected
|
||||
StartStopButton.IsEnabled = (SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem) != KnownSystem.NONE;
|
||||
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Found {0} drives: {1}", _drives.Count, String.Join(", ", _drives.Select(d => d.Letter)));
|
||||
}
|
||||
else
|
||||
{
|
||||
DriveLetterComboBox.SelectedIndex = -1;
|
||||
StatusLabel.Content = "No valid drive found!";
|
||||
StartStopButton.IsEnabled = false;
|
||||
CopyProtectScanButton.IsEnabled = false;
|
||||
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Found no drives");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Browse for an output folder
|
||||
/// </summary>
|
||||
private void BrowseFolder()
|
||||
{
|
||||
WinForms.FolderBrowserDialog folderDialog = new WinForms.FolderBrowserDialog { ShowNewFolderButton = false, SelectedPath = System.AppDomain.CurrentDomain.BaseDirectory };
|
||||
WinForms.DialogResult result = folderDialog.ShowDialog();
|
||||
|
||||
if (result == WinForms.DialogResult.OK)
|
||||
{
|
||||
OutputDirectoryTextBox.Text = folderDialog.SelectedPath;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a DumpEnvironment with all current settings
|
||||
/// </summary>
|
||||
/// <returns>Filled DumpEnvironment instance</returns>
|
||||
private DumpEnvironment DetermineEnvironment()
|
||||
{
|
||||
// Populate the new environment
|
||||
var env = new DumpEnvironment()
|
||||
{
|
||||
// Paths to tools
|
||||
SubdumpPath = _options.SubDumpPath,
|
||||
DICPath = _options.DICPath,
|
||||
|
||||
OutputDirectory = OutputDirectoryTextBox.Text,
|
||||
OutputFilename = OutputFilenameTextBox.Text,
|
||||
|
||||
// Get the currently selected options
|
||||
Drive = DriveLetterComboBox.SelectedItem as Drive,
|
||||
|
||||
DICParameters = new Parameters(ParametersTextBox.Text),
|
||||
|
||||
QuietMode = _options.QuietMode,
|
||||
ParanoidMode = _options.ParanoidMode,
|
||||
ScanForProtection = _options.ScanForProtection,
|
||||
RereadAmountC2 = _options.RereadAmountForC2,
|
||||
AddPlaceholders = _options.AddPlaceholders,
|
||||
|
||||
Username = _options.Username,
|
||||
Password = _options.Password,
|
||||
|
||||
System = SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem,
|
||||
Type = MediaTypeComboBox.SelectedItem as MediaType?,
|
||||
};
|
||||
|
||||
// Fix the output paths
|
||||
env.FixOutputPaths();
|
||||
|
||||
// Disable automatic reprocessing of the textboxes until we're done
|
||||
OutputDirectoryTextBox.TextChanged -= OutputDirectoryTextBoxTextChanged;
|
||||
OutputFilenameTextBox.TextChanged -= OutputFilenameTextBoxTextChanged;
|
||||
|
||||
OutputDirectoryTextBox.Text = env.OutputDirectory;
|
||||
OutputFilenameTextBox.Text = env.OutputFilename;
|
||||
|
||||
OutputDirectoryTextBox.TextChanged += OutputDirectoryTextBoxTextChanged;
|
||||
OutputFilenameTextBox.TextChanged += OutputFilenameTextBoxTextChanged;
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Begin the dumping process using the given inputs
|
||||
/// </summary>
|
||||
private async void StartDumping()
|
||||
{
|
||||
if (_env == null)
|
||||
_env = DetermineEnvironment();
|
||||
|
||||
// If still in custom parameter mode, check that users meant to continue or not
|
||||
if (EnableParametersCheckBox.IsChecked == true)
|
||||
{
|
||||
MessageBoxResult result = MessageBox.Show("It looks like you have custom parameters that have not been saved. Would you like to apply those changes before starting to dump?", "Custom Changes", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
EnableParametersCheckBox.IsChecked = false;
|
||||
ParametersTextBox.IsEnabled = false;
|
||||
ProcessCustomParameters();
|
||||
}
|
||||
else if (result == MessageBoxResult.Cancel)
|
||||
return;
|
||||
// If "No", then we continue with the current known environment
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Check for the firmware first
|
||||
// TODO: Remove this (and method) once DIC end-to-end logging becomes a thing
|
||||
if (!await _env.DriveHasLatestFimrware())
|
||||
{
|
||||
MessageBox.Show($"DiscImageCreator has reported that drive {_env.Drive.Letter} is not updated to the most recent firmware. Please update the firmware for your drive and try again.", "Outdated Firmware", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate that the user explicitly wants an inactive drive to be considered for dumping
|
||||
if (!_env.Drive.MarkedActive)
|
||||
{
|
||||
MessageBoxResult mbresult = MessageBox.Show("The currently selected drive does not appear to contain a disc! Are you sure you want to continue?", "Missing Disc", MessageBoxButton.YesNo, MessageBoxImage.Exclamation);
|
||||
if (mbresult == MessageBoxResult.No || mbresult == MessageBoxResult.Cancel || mbresult == MessageBoxResult.None)
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Dumping aborted!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If a complete dump already exists
|
||||
if (_env.FoundAllFiles())
|
||||
{
|
||||
MessageBoxResult mbresult = MessageBox.Show("A complete dump already exists! Are you sure you want to overwrite?", "Overwrite?", MessageBoxButton.YesNo, MessageBoxImage.Exclamation);
|
||||
if (mbresult == MessageBoxResult.No || mbresult == MessageBoxResult.Cancel || mbresult == MessageBoxResult.None)
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Dumping aborted!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
StartStopButton.Content = Constants.StopDumping;
|
||||
CopyProtectScanButton.IsEnabled = false;
|
||||
StatusLabel.Content = "Beginning dumping process";
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Starting dumping process..");
|
||||
|
||||
var progress = new Progress<Result>();
|
||||
progress.ProgressChanged += ProgressUpdated;
|
||||
Result result = await _env.StartDumping(progress);
|
||||
|
||||
StatusLabel.Content = result ? "Dumping complete!" : result.Message;
|
||||
ViewModels.LoggerViewModel.VerboseLogLn(result ? "Dumping complete!" : result.Message);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// No-op, we don't care what it was
|
||||
}
|
||||
finally
|
||||
{
|
||||
StartStopButton.Content = Constants.StartDumping;
|
||||
CopyProtectScanButton.IsEnabled = true;
|
||||
}
|
||||
|
||||
if (EjectWhenDoneCheckBox.IsChecked == true)
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLogLn($"Ejecting disc in drive {_env.Drive.Letter}");
|
||||
_env.EjectDisc();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure information is consistent with the currently selected disc type
|
||||
/// </summary>
|
||||
private void EnsureDiscInformation()
|
||||
{
|
||||
// Get the current environment information
|
||||
_env = DetermineEnvironment();
|
||||
|
||||
// Take care of null cases
|
||||
if (_env.System == null)
|
||||
_env.System = KnownSystem.NONE;
|
||||
if (_env.Type == null)
|
||||
_env.Type = MediaType.NONE;
|
||||
|
||||
// Get the status to write out
|
||||
Result result = Validators.GetSupportStatus(_env.System, _env.Type);
|
||||
StatusLabel.Content = result.Message;
|
||||
|
||||
// Set the index for the current disc type
|
||||
SetCurrentDiscType();
|
||||
|
||||
StartStopButton.IsEnabled = result && (_drives != null && _drives.Count > 0 ? true : false);
|
||||
|
||||
// If we're in a type that doesn't support drive speeds
|
||||
DriveSpeedComboBox.IsEnabled = _env.Type.DoesSupportDriveSpeed();
|
||||
|
||||
// If input params are not enabled, generate the full parameters from the environment
|
||||
if (!ParametersTextBox.IsEnabled)
|
||||
{
|
||||
string generated = _env.GetFullParameters((int?)DriveSpeedComboBox.SelectedItem);
|
||||
if (generated != null)
|
||||
ParametersTextBox.Text = generated;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the default output directory name from the currently selected drive
|
||||
/// </summary>
|
||||
private void GetOutputNames()
|
||||
{
|
||||
Drive drive = DriveLetterComboBox.SelectedItem as Drive;
|
||||
KnownSystem? systemType = SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem;
|
||||
MediaType? mediaType = MediaTypeComboBox.SelectedItem as MediaType?;
|
||||
|
||||
OutputDirectoryTextBox.Text = Path.Combine(_options.DefaultOutputPath, drive?.VolumeLabel ?? string.Empty);
|
||||
OutputFilenameTextBox.Text = (drive?.VolumeLabel ?? "disc") + (mediaType.Extension() ?? ".bin");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scan and show copy protection for the current disc
|
||||
/// </summary>
|
||||
private async void ScanAndShowProtection()
|
||||
{
|
||||
if (_env == null)
|
||||
_env = DetermineEnvironment();
|
||||
|
||||
if (_env.Drive.Letter != default(char))
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Scanning for copy protection in {0}", _env.Drive.Letter);
|
||||
|
||||
var tempContent = StatusLabel.Content;
|
||||
StatusLabel.Content = "Scanning for copy protection... this might take a while!";
|
||||
StartStopButton.IsEnabled = false;
|
||||
DiskScanButton.IsEnabled = false;
|
||||
CopyProtectScanButton.IsEnabled = false;
|
||||
|
||||
string protections = await Validators.RunProtectionScanOnPath(_env.Drive.Letter + ":\\");
|
||||
if (!ViewModels.LoggerViewModel.WindowVisible)
|
||||
MessageBox.Show(protections, "Detected Protection", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
ViewModels.LoggerViewModel.VerboseLog("Detected the following protections in {0}:\r\n\r\n{1}", _env.Drive.Letter, protections);
|
||||
|
||||
StatusLabel.Content = tempContent;
|
||||
StartStopButton.IsEnabled = true;
|
||||
DiskScanButton.IsEnabled = true;
|
||||
CopyProtectScanButton.IsEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the drive speed based on reported maximum and user-defined option
|
||||
/// </summary>
|
||||
private void SetSupportedDriveSpeed()
|
||||
{
|
||||
// Set the drive speed list that's appropriate
|
||||
var values = Constants.GetSpeedsForMediaType(_currentMediaType);
|
||||
DriveSpeedComboBox.ItemsSource = values;
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Supported media speeds: {0}", string.Join(",", values));
|
||||
|
||||
// Find the minimum set to compare against
|
||||
int preferred = 100;
|
||||
switch (_currentMediaType)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
case MediaType.GDROM:
|
||||
preferred = _options.PreferredDumpSpeedCD;
|
||||
break;
|
||||
case MediaType.DVD:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
preferred = _options.PreferredDumpSpeedDVD;
|
||||
break;
|
||||
case MediaType.BluRay:
|
||||
preferred = _options.PreferredDumpSpeedBD;
|
||||
break;
|
||||
default:
|
||||
preferred = _options.PreferredDumpSpeedCD;
|
||||
break;
|
||||
}
|
||||
|
||||
// Choose the lower of the two speeds between the allowed speeds and the user-defined one
|
||||
// TODO: Inform more users about setting preferences in the settings so this comparison doesn't need to happen
|
||||
int chosenSpeed = Math.Min(
|
||||
values.Where(s => s <= values[values.Count / 2]).Last(),
|
||||
preferred
|
||||
);
|
||||
|
||||
// Set the selected speed
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Setting drive speed to: {0}", chosenSpeed);
|
||||
DriveSpeedComboBox.SelectedValue = chosenSpeed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cache the current disc type to internal variable
|
||||
/// </summary>
|
||||
private void CacheCurrentDiscType()
|
||||
{
|
||||
// Get the drive letter from the selected item
|
||||
Drive drive = DriveLetterComboBox.SelectedItem as Drive;
|
||||
if (drive == null || drive.IsFloppy)
|
||||
return;
|
||||
|
||||
// Get the current optical disc type
|
||||
if (!_options.SkipMediaTypeDetection)
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLog("Trying to detect media type for drive {0}.. ", drive.Letter);
|
||||
_currentMediaType = Validators.GetMediaType(drive.Letter);
|
||||
ViewModels.LoggerViewModel.VerboseLogLn(_currentMediaType == null ? "unable to detect." : ("detected " + _currentMediaType.LongName() + "."));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the current disc type in the combo box
|
||||
/// </summary>
|
||||
private void SetCurrentDiscType()
|
||||
{
|
||||
// If we have an invalid current type, we don't care and return
|
||||
if (_currentMediaType == null || _currentMediaType == MediaType.NONE)
|
||||
return;
|
||||
|
||||
// Now set the selected item, if possible
|
||||
int index = _mediaTypes.FindIndex(kvp => kvp.Value == _currentMediaType);
|
||||
if (index != -1)
|
||||
MediaTypeComboBox.SelectedIndex = index;
|
||||
else
|
||||
StatusLabel.Content = $"Disc of type '{Converters.LongName(_currentMediaType)}' found, but the current system does not support it!";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process the current custom parameters back into UI values
|
||||
/// </summary>
|
||||
private void ProcessCustomParameters()
|
||||
{
|
||||
_env.DICParameters = new Parameters(ParametersTextBox.Text);
|
||||
|
||||
int driveIndex = _drives.Select(d => d.Letter).ToList().IndexOf(_env.DICParameters.DriveLetter[0]);
|
||||
if (driveIndex > -1)
|
||||
DriveLetterComboBox.SelectedIndex = driveIndex;
|
||||
|
||||
int driveSpeed = _env.DICParameters.DriveSpeed ?? -1;
|
||||
if (driveSpeed > 0)
|
||||
DriveSpeedComboBox.SelectedValue = driveSpeed;
|
||||
else
|
||||
_env.DICParameters.DriveSpeed = (int?)DriveSpeedComboBox.SelectedValue;
|
||||
|
||||
string trimmedPath = _env.DICParameters.Filename?.Trim('"') ?? string.Empty;
|
||||
string outputDirectory = Path.GetDirectoryName(trimmedPath);
|
||||
string outputFilename = Path.GetFileName(trimmedPath);
|
||||
if (!String.IsNullOrWhiteSpace(outputDirectory))
|
||||
OutputDirectoryTextBox.Text = outputDirectory;
|
||||
else
|
||||
outputDirectory = OutputDirectoryTextBox.Text;
|
||||
if (!String.IsNullOrWhiteSpace(outputFilename))
|
||||
OutputFilenameTextBox.Text = outputFilename;
|
||||
else
|
||||
outputFilename = OutputFilenameTextBox.Text;
|
||||
|
||||
MediaType? mediaType = _env.DICParameters.Command.ToMediaType();
|
||||
int mediaTypeIndex = _mediaTypes.IndexOf(mediaType);
|
||||
if (mediaTypeIndex > -1)
|
||||
MediaTypeComboBox.SelectedIndex = mediaTypeIndex;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Get pixel coordinates based on DPI scaling
|
||||
/// </summary>
|
||||
/// <param name="bounds">Rectangle representing the bounds to transform</param>
|
||||
/// <returns>Rectangle representing the scaled bounds</returns>
|
||||
private Rectangle GetScaledCoordinates(Rectangle bounds)
|
||||
{
|
||||
using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
|
||||
{
|
||||
return new Rectangle(
|
||||
TransformCoordinate(bounds.Left, g.DpiX),
|
||||
TransformCoordinate(bounds.Top, g.DpiY),
|
||||
TransformCoordinate(bounds.Width, g.DpiX),
|
||||
TransformCoordinate(bounds.Height, g.DpiY));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transform an individual coordinate using DPI scaling
|
||||
/// </summary>
|
||||
/// <param name="coord">Current integer coordinate</param>
|
||||
/// <param name="dpi">DPI scaling factor</param>
|
||||
/// <returns>Scaled integer coordinate</returns>
|
||||
private int TransformCoordinate(int coord, float dpi)
|
||||
{
|
||||
return (int)(coord / ((double)dpi / 96));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
<Window x:Class="DICUI.Windows.OptionsWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:DICUI"
|
||||
mc:Ignorable="d"
|
||||
Title="Options" Height="580" Width="515.132">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="150"/>
|
||||
<RowDefinition Height="100"/>
|
||||
<RowDefinition Height="80"/>
|
||||
<RowDefinition Height="40"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<GroupBox Grid.Column="0" Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Paths" />
|
||||
|
||||
<Grid Margin="10,15,10,10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="2.0*" />
|
||||
<ColumnDefinition Width="0.2*" />
|
||||
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="DiscImageCreator Path" />
|
||||
<TextBox x:Name="DICPathTextBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
<Button x:Name="DICPathButton" Grid.Row="0" Grid.Column="2" Height="22" Width="22" Content="..." Click="BrowseForPathClick" />
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="subdump Path" />
|
||||
<TextBox x:Name="SubDumpPathTextBox" Grid.Row="1" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
<Button x:Name="SubDumpPathButton" Grid.Row="1" Grid.Column="2" Height="22" Width="22" Content="..." Click="BrowseForPathClick"/>
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Default Output Path" />
|
||||
<TextBox x:Name="DefaultOutputPathTextBox" Grid.Row="2" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
<Button x:Name="DefaultOutputPathButton" Grid.Row="2" Grid.Column="2" Height="22" Width="22" Content="..." Click="BrowseForPathClick" />
|
||||
</Grid>
|
||||
|
||||
<GroupBox Grid.Row="1" Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Preferred Dump Speed">
|
||||
<Grid Height="100">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="80"/>
|
||||
<ColumnDefinition Width="2.0*"/>
|
||||
<ColumnDefinition Width="40"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" Content="CD-ROM" />
|
||||
<Slider x:Name="DumpSpeedCDSlider" Grid.Row="0" Grid.Column="1" Minimum="1" Maximum="72" IsSnapToTickEnabled="True" TickPlacement="BottomRight" Ticks="{Binding Source={x:Static local:Constants.SpeedsForCDAsCollection}}" />
|
||||
<TextBox x:Name="DumpSpeedCDTextBox" Grid.Row="0" Grid.Column="2" Width="22" Height="22" TextAlignment="Center" IsReadOnly="True" IsReadOnlyCaretVisible="False" VerticalAlignment="Center" Text="{Binding ElementName=DumpSpeedCDSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}" Background="LightGray" Foreground="Gray"/>
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="DVD-ROM" />
|
||||
<Slider x:Name="DumpSpeedDVDSlider" Grid.Row="1" Grid.Column="1" Minimum="1" Maximum="24" IsSnapToTickEnabled="True" TickPlacement="BottomRight" Ticks="{Binding Source={x:Static local:Constants.SpeedsForDVDAsCollection}}" />
|
||||
<TextBox x:Name="DumpSpeedDVDTextBox" Grid.Row="1" Grid.Column="2" Width="22" Height="22" TextAlignment="Center" IsReadOnly="True" IsReadOnlyCaretVisible="False" VerticalAlignment="Center" Text="{Binding ElementName=DumpSpeedDVDSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}" Background="LightGray" Foreground="Gray"/>
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" Content="BD-ROM" />
|
||||
<Slider x:Name="DumpSpeedBDSlider" Grid.Row="2" Grid.Column="1" Minimum="1" Maximum="16" IsSnapToTickEnabled="True" TickPlacement="BottomRight" Ticks="{Binding Source={x:Static local:Constants.SpeedsForBDAsCollection}}" />
|
||||
<TextBox x:Name="DumpSpeedBDTextBox" Grid.Row="2" Grid.Column="2" Width="22" Height="22" TextAlignment="Center" IsReadOnly="True" IsReadOnlyCaretVisible="False" VerticalAlignment="Center" Text="{Binding ElementName=DumpSpeedBDSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}" Background="LightGray" Foreground="Gray"/>
|
||||
|
||||
</Grid>
|
||||
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="2" Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Options" Padding="10">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
|
||||
<CheckBox Grid.Column="0" VerticalAlignment="Center" Content="Quiet Mode"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
|
||||
IsChecked="{Binding Path=QuietMode}"
|
||||
ToolTip="Disable DiscImageCreator sounds"
|
||||
/>
|
||||
<CheckBox Grid.Column="1" VerticalAlignment="Center" Content="Paranoid Mode"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
|
||||
IsChecked="{Binding Path=ParanoidMode}"
|
||||
ToolTip="Enable pedantic and super-safe flags"
|
||||
/>
|
||||
<Grid Grid.Column="2" Grid.ColumnSpan="2" Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Column="0" Content="C2 Reread Tries:" />
|
||||
<TextBox Grid.Column="1" VerticalAlignment="Center"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
|
||||
Text="{Binding Path=RereadAmountForC2}"
|
||||
ToolTip="Specifies how many rereads are attempted on C2 error"
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<CheckBox Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" VerticalAlignment="Top" Content="Protection Scan"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
|
||||
IsChecked="{Binding Path=ScanForProtection}"
|
||||
ToolTip="Enable automatic checking for copy protection on dumped media" Margin="0,4,0,0"
|
||||
/>
|
||||
|
||||
<CheckBox Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="2" VerticalAlignment="Center" Content="Skip Media Type Detection"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
|
||||
IsChecked="{Binding Path=SkipMediaTypeDetection}"
|
||||
ToolTip="Disable trying to guess media type inserted (may improve performance at startup)"
|
||||
/>
|
||||
|
||||
<CheckBox Grid.Column="3" Grid.Row="1" VerticalAlignment="Center" Content="Add Placeholders"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
|
||||
IsChecked="{Binding Path=AddPlaceholders}"
|
||||
ToolTip="Enable adding placeholder text in the submissioninfo output for required and optional fields"
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="3" Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Redump Login" Padding="10">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Username" />
|
||||
<TextBox x:Name="RedumpUsernameTextBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Password" />
|
||||
<TextBox x:Name="RedumpPasswordTextBox" Grid.Row="0" Grid.Column="3" Height="22" HorizontalAlignment="Stretch" />
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<Grid Height="22" Grid.Row="4" Grid.Column="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button x:Name="AcceptButton" Grid.Row="0" Grid.Column="1" Height="22" Width="80" Content="Accept" Click="OnAcceptClick" />
|
||||
<Button x:Name="CancelButton" Grid.Row="0" Grid.Column="2" Height="22" Width="80" Content="Cancel" Click="OnCancelClick" />
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,138 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using Button = System.Windows.Controls.Button;
|
||||
using TextBox = System.Windows.Controls.TextBox;
|
||||
|
||||
namespace DICUI.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for OptionsWindow.xaml
|
||||
/// </summary>
|
||||
public partial class OptionsWindow : Window
|
||||
{
|
||||
private readonly MainWindow _mainWindow;
|
||||
private readonly Options _options;
|
||||
|
||||
public OptionsWindow(MainWindow mainWindow, Options options)
|
||||
{
|
||||
InitializeComponent();
|
||||
_mainWindow = mainWindow;
|
||||
_options = options;
|
||||
}
|
||||
|
||||
private OpenFileDialog CreateOpenFileDialog()
|
||||
{
|
||||
OpenFileDialog dialog = new OpenFileDialog();
|
||||
|
||||
dialog.InitialDirectory = AppDomain.CurrentDomain.BaseDirectory;
|
||||
dialog.Filter = "Executables (*.exe)|*.exe";
|
||||
dialog.FilterIndex = 0;
|
||||
dialog.RestoreDirectory = true;
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private FolderBrowserDialog CreateFolderBrowserDialog()
|
||||
{
|
||||
FolderBrowserDialog dialog = new FolderBrowserDialog();
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private string[] PathSettings()
|
||||
{
|
||||
string[] pathSettings = { "DefaultOutputPath", "DICPath", "SubDumpPath" };
|
||||
return pathSettings;
|
||||
}
|
||||
|
||||
private TextBox TextBoxForPathSetting(string name)
|
||||
{
|
||||
return FindName(name + "TextBox") as TextBox;
|
||||
}
|
||||
|
||||
private void BrowseForPathClick(object sender, EventArgs e)
|
||||
{
|
||||
Button button = sender as Button;
|
||||
// strips button prefix to obtain the setting name
|
||||
string pathSettingName = button.Name.Substring(0, button.Name.IndexOf("Button"));
|
||||
|
||||
// TODO: hack for now, then we'll see
|
||||
bool shouldBrowseForPath = pathSettingName == "DefaultOutputPath";
|
||||
|
||||
CommonDialog dialog = shouldBrowseForPath ? (CommonDialog)CreateFolderBrowserDialog() : CreateOpenFileDialog();
|
||||
using (dialog)
|
||||
{
|
||||
DialogResult result = dialog.ShowDialog();
|
||||
|
||||
if (result == System.Windows.Forms.DialogResult.OK)
|
||||
{
|
||||
string path;
|
||||
bool exists;
|
||||
|
||||
if (shouldBrowseForPath)
|
||||
{
|
||||
path = (dialog as FolderBrowserDialog).SelectedPath;
|
||||
exists = Directory.Exists(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
path = (dialog as OpenFileDialog).FileName;
|
||||
exists = File.Exists(path);
|
||||
}
|
||||
|
||||
if (exists)
|
||||
TextBoxForPathSetting(pathSettingName).Text = path;
|
||||
else
|
||||
{
|
||||
System.Windows.MessageBox.Show(
|
||||
"Specified path doesn't exists!",
|
||||
"Error",
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Error
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
Array.ForEach(PathSettings(), setting => TextBoxForPathSetting(setting).Text = _options.Get(setting));
|
||||
|
||||
DumpSpeedCDSlider.Value = _options.PreferredDumpSpeedCD;
|
||||
DumpSpeedDVDSlider.Value = _options.PreferredDumpSpeedDVD;
|
||||
DumpSpeedBDSlider.Value = _options.PreferredDumpSpeedBD;
|
||||
|
||||
RedumpUsernameTextBox.Text = _options.Username;
|
||||
RedumpPasswordTextBox.Text = _options.Password;
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
private void OnAcceptClick(object sender, EventArgs e)
|
||||
{
|
||||
Array.ForEach(PathSettings(), setting => _options.Set(setting, TextBoxForPathSetting(setting).Text));
|
||||
|
||||
_options.PreferredDumpSpeedCD = Convert.ToInt32(DumpSpeedCDSlider.Value);
|
||||
_options.PreferredDumpSpeedDVD = Convert.ToInt32(DumpSpeedDVDSlider.Value);
|
||||
_options.PreferredDumpSpeedBD = Convert.ToInt32(DumpSpeedBDSlider.Value);
|
||||
|
||||
_options.Username = RedumpUsernameTextBox.Text;
|
||||
_options.Password = RedumpPasswordTextBox.Text;
|
||||
|
||||
_options.Save();
|
||||
Hide();
|
||||
|
||||
_mainWindow.OnOptionsUpdated();
|
||||
}
|
||||
|
||||
private void OnCancelClick(object sender, EventArgs e)
|
||||
{
|
||||
// just hide the window and don't care
|
||||
Hide();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
2
LICENSE
2
LICENSE
@@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
DICUI Copyright (C) 2018 ReignStumble
|
||||
MPF Copyright (C) 2018 ReignStumble
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/>
|
||||
</startup>
|
||||
</configuration>
|
||||
</configuration>
|
||||
45
MPF.Check/MPF.Check.csproj
Normal file
45
MPF.Check/MPF.Check.csproj
Normal file
@@ -0,0 +1,45 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
|
||||
<OutputType>Exe</OutputType>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<VersionPrefix>3.1.3</VersionPrefix>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Title>MPF Check</Title>
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
<Description>Validator for various dumping programs</Description>
|
||||
<Copyright>Copyright (c) Matt Nadareski 2019-2024</Copyright>
|
||||
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BinaryObjectScanner" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="3.1.1" GeneratePathProperty="true">
|
||||
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="1.3.6" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="$(PkgBinaryObjectScanner)\content\**" PackagePath="contentFiles\any\any;content" CopyToOutputDirectory="Always" PackageCopyToOutput="true" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
116
MPF.Check/Program.cs
Normal file
116
MPF.Check/Program.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BinaryObjectScanner;
|
||||
using MPF.Core;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.Utilities;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
using SabreTools.RedumpLib.Web;
|
||||
|
||||
namespace MPF.Check
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// Try processing the standalone arguments
|
||||
bool? standaloneProcessed = OptionsLoader.ProcessStandaloneArguments(args);
|
||||
if (standaloneProcessed != false)
|
||||
{
|
||||
if (standaloneProcessed == null)
|
||||
DisplayHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
// Try processing the common arguments
|
||||
(bool success, MediaType mediaType, RedumpSystem? knownSystem, var error) = OptionsLoader.ProcessCommonArguments(args);
|
||||
if (!success)
|
||||
{
|
||||
DisplayHelp(error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop through and process options
|
||||
(var options, var seedInfo, var path, int startIndex) = OptionsLoader.LoadFromArguments(args, startIndex: 2);
|
||||
if (options.InternalProgram == InternalProgram.NONE)
|
||||
{
|
||||
DisplayHelp("A program name needs to be provided");
|
||||
return;
|
||||
}
|
||||
|
||||
// Make new Progress objects
|
||||
var resultProgress = new Progress<Result>();
|
||||
resultProgress.ProgressChanged += ConsoleLogger.ProgressUpdated;
|
||||
var protectionProgress = new Progress<ProtectionProgress>();
|
||||
protectionProgress.ProgressChanged += ConsoleLogger.ProgressUpdated;
|
||||
|
||||
// Validate the supplied credentials
|
||||
#if NETFRAMEWORK
|
||||
(bool? _, string? message) = RedumpWebClient.ValidateCredentials(options.RedumpUsername ?? string.Empty, options.RedumpPassword ?? string.Empty);
|
||||
#else
|
||||
(bool? _, string? message) = RedumpHttpClient.ValidateCredentials(options.RedumpUsername ?? string.Empty, options.RedumpPassword ?? string.Empty).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
#endif
|
||||
if (!string.IsNullOrEmpty(message))
|
||||
Console.WriteLine(message);
|
||||
|
||||
// Loop through all the rest of the args
|
||||
for (int i = startIndex; i < args.Length; i++)
|
||||
{
|
||||
// Check for a file
|
||||
if (!File.Exists(args[i].Trim('"')))
|
||||
{
|
||||
DisplayHelp($"{args[i].Trim('"')} does not exist");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the full file path
|
||||
string filepath = Path.GetFullPath(args[i].Trim('"'));
|
||||
|
||||
// Now populate an environment
|
||||
Drive? drive = null;
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
drive = Drive.Create(null, path!);
|
||||
|
||||
var env = new DumpEnvironment(options, filepath, drive, knownSystem, mediaType, internalProgram: null, parameters: null);
|
||||
|
||||
// Finally, attempt to do the output dance
|
||||
#if NET40
|
||||
var resultTask = env.VerifyAndSaveDumpOutput(resultProgress, protectionProgress);
|
||||
resultTask.Wait();
|
||||
var result = resultTask.Result;
|
||||
#else
|
||||
var result = env.VerifyAndSaveDumpOutput(resultProgress, protectionProgress).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
#endif
|
||||
Console.WriteLine(result.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display help for MPF.Check
|
||||
/// </summary>
|
||||
/// <param name="error">Error string to prefix the help text with</param>
|
||||
private static void DisplayHelp(string? error = null)
|
||||
{
|
||||
if (error != null)
|
||||
Console.WriteLine(error);
|
||||
|
||||
Console.WriteLine("Usage:");
|
||||
Console.WriteLine("MPF.Check.exe <mediatype> <system> [options] </path/to/output.cue/iso> ...");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Standalone Options:");
|
||||
Console.WriteLine("-h, -? Show this help text");
|
||||
Console.WriteLine("-lm, --listmedia List supported media types");
|
||||
Console.WriteLine("-ls, --listsystems List supported system types");
|
||||
Console.WriteLine("-lp, --listprograms List supported dumping program outputs");
|
||||
Console.WriteLine();
|
||||
|
||||
Console.WriteLine("Check Options:");
|
||||
var supportedArguments = OptionsLoader.PrintSupportedArguments();
|
||||
foreach (string argument in supportedArguments)
|
||||
{
|
||||
Console.WriteLine(argument);
|
||||
}
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
7
MPF.Check/launchSettings.json
Normal file
7
MPF.Check/launchSettings.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"profiles": {
|
||||
"MPF.Check": {
|
||||
"commandName": "Project"
|
||||
}
|
||||
}
|
||||
}
|
||||
25
MPF.Core/ConsoleLogger.cs
Normal file
25
MPF.Core/ConsoleLogger.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using BinaryObjectScanner;
|
||||
using MPF.Core.Data;
|
||||
|
||||
namespace MPF.Core
|
||||
{
|
||||
public static class ConsoleLogger
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple process counter to write to console
|
||||
/// </summary>
|
||||
public static void ProgressUpdated(object? sender, Result value)
|
||||
{
|
||||
Console.WriteLine(value.Message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple process counter to write to console
|
||||
/// </summary>
|
||||
public static void ProgressUpdated(object? sender, ProtectionProgress value)
|
||||
{
|
||||
Console.WriteLine($"{value.Percentage * 100:N2}%: {value.Filename} - {value.Protection}");
|
||||
}
|
||||
}
|
||||
}
|
||||
304
MPF.Core/Converters/EnumConverter.cs
Normal file
304
MPF.Core/Converters/EnumConverter.cs
Normal file
@@ -0,0 +1,304 @@
|
||||
using System;
|
||||
#if NET20 || NET35
|
||||
using System.Collections.Generic;
|
||||
#else
|
||||
using System.Collections.Concurrent;
|
||||
#endif
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using MPF.Core.Data;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Converters
|
||||
{
|
||||
public static class EnumConverter
|
||||
{
|
||||
#region Cross-enumeration conversions
|
||||
|
||||
/// <summary>
|
||||
/// Convert drive type to internal version, if possible
|
||||
/// </summary>
|
||||
/// <param name="driveType">DriveType value to check</param>
|
||||
/// <returns>InternalDriveType, if possible, null on error</returns>
|
||||
public static InternalDriveType? ToInternalDriveType(this DriveType driveType)
|
||||
{
|
||||
return driveType switch
|
||||
{
|
||||
DriveType.CDRom => (InternalDriveType?)InternalDriveType.Optical,
|
||||
DriveType.Fixed => (InternalDriveType?)InternalDriveType.HardDisk,
|
||||
DriveType.Removable => (InternalDriveType?)InternalDriveType.Removable,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Convert to Long Name
|
||||
|
||||
/// <summary>
|
||||
/// Long name method cache
|
||||
/// </summary>
|
||||
#if NET20 || NET35
|
||||
private static readonly Dictionary<Type, MethodInfo?> LongNameMethods = [];
|
||||
#else
|
||||
private static readonly ConcurrentDictionary<Type, MethodInfo?> LongNameMethods = [];
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Get the string representation of a generic enumerable value
|
||||
/// </summary>
|
||||
/// <param name="value">Enum value to convert</param>
|
||||
/// <returns>String representation of that value if possible, empty string on error</returns>
|
||||
public static string GetLongName(Enum value)
|
||||
{
|
||||
try
|
||||
{
|
||||
var sourceType = value.GetType();
|
||||
sourceType = Nullable.GetUnderlyingType(sourceType) ?? sourceType;
|
||||
|
||||
if (!LongNameMethods.TryGetValue(sourceType, out var method))
|
||||
{
|
||||
method = typeof(Extensions).GetMethod("LongName", [typeof(Nullable<>).MakeGenericType(sourceType)]);
|
||||
method ??= typeof(EnumConverter).GetMethod("LongName", [typeof(Nullable<>).MakeGenericType(sourceType)]);
|
||||
|
||||
#if NET20 || NET35
|
||||
LongNameMethods[sourceType] = method;
|
||||
#else
|
||||
LongNameMethods.TryAdd(sourceType, method);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (method != null)
|
||||
return method.Invoke(null, new[] { value }) as string ?? string.Empty;
|
||||
else
|
||||
return string.Empty;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Converter is not implemented for the given type
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string representation of the InternalProgram enum values
|
||||
/// </summary>
|
||||
/// <param name="prog">InternalProgram value to convert</param>
|
||||
/// <returns>String representing the value, if possible</returns>
|
||||
public static string LongName(this InternalProgram? prog)
|
||||
{
|
||||
return (prog) switch
|
||||
{
|
||||
#region Dumping support
|
||||
|
||||
InternalProgram.Aaru => "Aaru",
|
||||
InternalProgram.DiscImageCreator => "DiscImageCreator",
|
||||
InternalProgram.Redumper => "Redumper",
|
||||
|
||||
#endregion
|
||||
|
||||
#region Verification support only
|
||||
|
||||
InternalProgram.CleanRip => "CleanRip",
|
||||
InternalProgram.DCDumper => "DCDumper",
|
||||
InternalProgram.PS3CFW => "PS3 CFW",
|
||||
InternalProgram.UmdImageCreator => "UmdImageCreator",
|
||||
|
||||
#endregion
|
||||
|
||||
InternalProgram.NONE => "Unknown",
|
||||
_ => "Unknown",
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Convert From String
|
||||
|
||||
/// <summary>
|
||||
/// Get the InternalProgram enum value for a given string
|
||||
/// </summary>
|
||||
/// <param name="internalProgram">String value to convert</param>
|
||||
/// <returns>InternalProgram represented by the string, if possible</returns>
|
||||
public static InternalProgram ToInternalProgram(string? internalProgram)
|
||||
{
|
||||
return (internalProgram?.ToLowerInvariant()) switch
|
||||
{
|
||||
// Dumping support
|
||||
"aaru"
|
||||
or "chef"
|
||||
or "dichef"
|
||||
or "discimagechef" => InternalProgram.Aaru,
|
||||
"creator"
|
||||
or "dic"
|
||||
or "dicreator"
|
||||
or "discimagecreator" => InternalProgram.DiscImageCreator,
|
||||
"rd"
|
||||
or "redumper" => InternalProgram.Redumper,
|
||||
|
||||
// Verification support only
|
||||
"cleanrip"
|
||||
or "cr" => InternalProgram.CleanRip,
|
||||
"dc"
|
||||
or "dcd"
|
||||
or "dcdumper" => InternalProgram.DCDumper,
|
||||
"ps3cfw"
|
||||
or "ps3"
|
||||
or "getkey"
|
||||
or "managunz"
|
||||
or "multiman" => InternalProgram.PS3CFW,
|
||||
"uic"
|
||||
or "umd"
|
||||
or "umdcreator"
|
||||
or "umdimagecreator" => InternalProgram.UmdImageCreator,
|
||||
|
||||
_ => InternalProgram.NONE,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the MediaType enum value for a given string
|
||||
/// </summary>
|
||||
/// <param name="type">String value to convert</param>
|
||||
/// <returns>MediaType represented by the string, if possible</returns>
|
||||
public static MediaType ToMediaType(string type)
|
||||
{
|
||||
return (type.ToLowerInvariant()) switch
|
||||
{
|
||||
#region Punched Media
|
||||
|
||||
"aperture"
|
||||
or "aperturecard"
|
||||
or "aperture card" => MediaType.ApertureCard,
|
||||
"jacquardloom"
|
||||
or "jacquardloomcard"
|
||||
or "jacquard loom card" => MediaType.JacquardLoomCard,
|
||||
"magneticstripe"
|
||||
or "magneticstripecard"
|
||||
or "magnetic stripe card" => MediaType.MagneticStripeCard,
|
||||
"opticalphone"
|
||||
or "opticalphonecard"
|
||||
or "optical phonecard" => MediaType.OpticalPhonecard,
|
||||
"punchcard"
|
||||
or "punchedcard"
|
||||
or "punched card" => MediaType.PunchedCard,
|
||||
"punchtape"
|
||||
or "punchedtape"
|
||||
or "punched tape" => MediaType.PunchedTape,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tape
|
||||
|
||||
"openreel"
|
||||
or "openreeltape"
|
||||
or "open reel tape" => MediaType.OpenReel,
|
||||
"datacart"
|
||||
or "datacartridge"
|
||||
or "datatapecartridge"
|
||||
or "data tape cartridge" => MediaType.DataCartridge,
|
||||
"cassette"
|
||||
or "cassettetape"
|
||||
or "cassette tape" => MediaType.Cassette,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Disc / Disc
|
||||
|
||||
"bd"
|
||||
or "bdrom"
|
||||
or "bd-rom"
|
||||
or "bluray" => MediaType.BluRay,
|
||||
"cd"
|
||||
or "cdrom"
|
||||
or "cd-rom" => MediaType.CDROM,
|
||||
"dvd"
|
||||
or "dvd5"
|
||||
or "dvd-5"
|
||||
or "dvd9"
|
||||
or "dvd-9"
|
||||
or "dvdrom"
|
||||
or "dvd-rom" => MediaType.DVD,
|
||||
"fd"
|
||||
or "floppy"
|
||||
or "floppydisk"
|
||||
or "floppy disk"
|
||||
or "floppy diskette" => MediaType.FloppyDisk,
|
||||
"floptical" => MediaType.Floptical,
|
||||
"gd"
|
||||
or "gdrom"
|
||||
or "gd-rom" => MediaType.GDROM,
|
||||
"hddvd"
|
||||
or "hd-dvd"
|
||||
or "hddvdrom"
|
||||
or "hd-dvd-rom" => MediaType.HDDVD,
|
||||
"hdd"
|
||||
or "harddisk"
|
||||
or "hard disk" => MediaType.HardDisk,
|
||||
"bernoullidisk"
|
||||
or "iomegabernoullidisk"
|
||||
or "bernoulli disk"
|
||||
or "iomega bernoulli disk" => MediaType.IomegaBernoulliDisk,
|
||||
"jaz"
|
||||
or "iomegajaz"
|
||||
or "iomega jaz" => MediaType.IomegaJaz,
|
||||
"zip"
|
||||
or "zipdisk"
|
||||
or "iomegazip"
|
||||
or "iomega zip" => MediaType.IomegaZip,
|
||||
"ldrom"
|
||||
or "lvrom"
|
||||
or "ld-rom"
|
||||
or "lv-rom"
|
||||
or "laserdisc"
|
||||
or "laservision"
|
||||
or "ld-rom / lv-rom" => MediaType.LaserDisc,
|
||||
"64dd"
|
||||
or "n64dd"
|
||||
or "64dddisk"
|
||||
or "n64dddisk"
|
||||
or "64dd disk"
|
||||
or "n64dd disk" => MediaType.Nintendo64DD,
|
||||
"fds"
|
||||
or "famicom"
|
||||
or "nfds"
|
||||
or "nintendofamicom"
|
||||
or "famicomdisksystem"
|
||||
or "famicom disk system"
|
||||
or "famicom disk system disk" => MediaType.NintendoFamicomDiskSystem,
|
||||
"gc"
|
||||
or "gamecube"
|
||||
or "nintendogamecube"
|
||||
or "nintendo gamecube"
|
||||
or "gamecube disc"
|
||||
or "gamecube game disc" => MediaType.NintendoGameCubeGameDisc,
|
||||
"wii"
|
||||
or "nintendowii"
|
||||
or "nintendo wii"
|
||||
or "nintendo wii disc"
|
||||
or "wii optical disc" => MediaType.NintendoWiiOpticalDisc,
|
||||
"wiiu"
|
||||
or "nintendowiiu"
|
||||
or "nintendo wiiu"
|
||||
or "nintendo wiiu disc"
|
||||
or "wiiu optical disc"
|
||||
or "wii u optical disc" => MediaType.NintendoWiiUOpticalDisc,
|
||||
"umd" => MediaType.UMD,
|
||||
|
||||
#endregion
|
||||
|
||||
// Unsorted Formats
|
||||
"cartridge" => MediaType.Cartridge,
|
||||
"ced"
|
||||
or "rcaced"
|
||||
or "rca ced"
|
||||
or "videodisc"
|
||||
or "rca videodisc" => MediaType.CED,
|
||||
|
||||
_ => MediaType.NONE,
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
69
MPF.Core/Data/Constants.cs
Normal file
69
MPF.Core/Data/Constants.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Constant values for UI
|
||||
/// </summary>
|
||||
public static class Interface
|
||||
{
|
||||
// Button values
|
||||
public const string StartDumping = "Start Dumping";
|
||||
public const string StopDumping = "Stop Dumping";
|
||||
|
||||
// Byte arrays for signatures
|
||||
public static readonly byte[] SaturnSectorZeroStart = [0x53, 0x45, 0x47, 0x41, 0x20, 0x53, 0x45, 0x47, 0x41, 0x53, 0x41, 0x54, 0x55, 0x52, 0x4E, 0x20];
|
||||
|
||||
// Lists of known drive speed ranges
|
||||
#if NET20 || NET35 || NET40
|
||||
public static IList<int> CD { get; } = new List<int> { 1, 2, 3, 4, 6, 8, 12, 16, 20, 24, 32, 40, 44, 48, 52, 56, 72 };
|
||||
public static IList<int> DVD { get; } = CD.Where(s => s <= 24).ToList();
|
||||
public static IList<int> HDDVD { get; } = CD.Where(s => s <= 24).ToList();
|
||||
public static IList<int> BD { get; } = CD.Where(s => s <= 16).ToList();
|
||||
public static IList<int> Unknown { get; } = new List<int> { 1 };
|
||||
#else
|
||||
public static IReadOnlyList<int> CD { get; } = new List<int> { 1, 2, 3, 4, 6, 8, 12, 16, 20, 24, 32, 40, 44, 48, 52, 56, 72 };
|
||||
public static IReadOnlyList<int> DVD { get; } = CD.Where(s => s <= 24).ToList();
|
||||
public static IReadOnlyList<int> HDDVD { get; } = CD.Where(s => s <= 24).ToList();
|
||||
public static IReadOnlyList<int> BD { get; } = CD.Where(s => s <= 16).ToList();
|
||||
public static IReadOnlyList<int> Unknown { get; } = new List<int> { 1 };
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Get list of all drive speeds for a given MediaType
|
||||
/// </summary>
|
||||
/// <param name="type">MediaType? that represents the current item</param>
|
||||
/// <returns>Read-only list of drive speeds</returns>
|
||||
#if NET20 || NET35 || NET40
|
||||
public static IList<int> GetSpeedsForMediaType(MediaType? type)
|
||||
#else
|
||||
public static IReadOnlyList<int> GetSpeedsForMediaType(MediaType? type)
|
||||
#endif
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
MediaType.CDROM
|
||||
or MediaType.GDROM => CD,
|
||||
MediaType.DVD
|
||||
or MediaType.NintendoGameCubeGameDisc
|
||||
or MediaType.NintendoWiiOpticalDisc => DVD,
|
||||
MediaType.HDDVD => HDDVD,
|
||||
MediaType.BluRay => BD,
|
||||
_ => Unknown,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Template field values for submission info
|
||||
/// </summary>
|
||||
public static class Template
|
||||
{
|
||||
public const string RequiredValue = "(REQUIRED)";
|
||||
public const string RequiredIfExistsValue = "(REQUIRED, IF EXISTS)";
|
||||
public const string OptionalValue = "(OPTIONAL)";
|
||||
public const string DiscNotDetected = "Disc Not Detected";
|
||||
}
|
||||
}
|
||||
686
MPF.Core/Data/Drive.cs
Normal file
686
MPF.Core/Data/Drive.cs
Normal file
@@ -0,0 +1,686 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
using Microsoft.Management.Infrastructure;
|
||||
using Microsoft.Management.Infrastructure.Generic;
|
||||
#endif
|
||||
using MPF.Core.Converters;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents information for a single drive
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// TODO: Can the Aaru models be used instead of the ones I've created here?
|
||||
/// </remarks>
|
||||
public class Drive
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Represents drive type
|
||||
/// </summary>
|
||||
public InternalDriveType? InternalDriveType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Drive partition format
|
||||
/// </summary>
|
||||
public string? DriveFormat { get; private set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Windows drive path
|
||||
/// </summary>
|
||||
public string? Name { get; private set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Represents if Windows has marked the drive as active
|
||||
/// </summary>
|
||||
public bool MarkedActive { get; private set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the total size of the drive
|
||||
/// </summary>
|
||||
public long TotalSize { get; private set; } = default;
|
||||
|
||||
/// <summary>
|
||||
/// Media label as read by Windows
|
||||
/// </summary>
|
||||
/// <remarks>The try/catch is needed because Windows will throw an exception if the drive is not marked as active</remarks>
|
||||
public string? VolumeLabel { get; private set; } = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Derived Fields
|
||||
|
||||
/// <summary>
|
||||
/// Media label as read by Windows, formatted to avoid odd outputs
|
||||
/// If no volume label present, use PSX or PS2 serial if valid
|
||||
/// Otherwise, use "track" as volume label
|
||||
/// </summary>
|
||||
public string? FormattedVolumeLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
string? volumeLabel = Template.DiscNotDetected;
|
||||
if (!this.MarkedActive)
|
||||
return volumeLabel;
|
||||
|
||||
if (!string.IsNullOrEmpty(this.VolumeLabel))
|
||||
{
|
||||
volumeLabel = this.VolumeLabel;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No Volume Label found, fallback to something sensible
|
||||
switch (this.GetRedumpSystem(null))
|
||||
{
|
||||
case RedumpSystem.SonyPlayStation:
|
||||
case RedumpSystem.SonyPlayStation2:
|
||||
InfoTool.GetPlayStationExecutableInfo(this.Name, out string? serial, out _, out _);
|
||||
volumeLabel = serial ?? "track";
|
||||
break;
|
||||
|
||||
default:
|
||||
volumeLabel = "track";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (char c in Path.GetInvalidFileNameChars())
|
||||
volumeLabel = volumeLabel?.Replace(c, '_');
|
||||
|
||||
return volumeLabel;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read-only access to the drive letter
|
||||
/// </summary>
|
||||
/// <remarks>Should only be used in UI applications</remarks>
|
||||
public char? Letter => this.Name?[0] ?? '\0';
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Protected constructor
|
||||
/// </summary>
|
||||
protected Drive() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new Drive object from a drive type and device path
|
||||
/// </summary>
|
||||
/// <param name="driveType">InternalDriveType value representing the drive type</param>
|
||||
/// <param name="devicePath">Path to the device according to the local machine</param>
|
||||
public static Drive? Create(InternalDriveType? driveType, string devicePath)
|
||||
{
|
||||
// Create a new, empty drive object
|
||||
var drive = new Drive()
|
||||
{
|
||||
InternalDriveType = driveType,
|
||||
};
|
||||
|
||||
// If we have an invalid device path, return null
|
||||
if (string.IsNullOrEmpty(devicePath))
|
||||
return null;
|
||||
|
||||
// Sanitize a Windows-formatted long device path
|
||||
if (devicePath.StartsWith("\\\\.\\"))
|
||||
devicePath = devicePath.Substring("\\\\.\\".Length);
|
||||
|
||||
// Create and validate the drive info object
|
||||
var driveInfo = new DriveInfo(devicePath);
|
||||
if (driveInfo == null || driveInfo == default)
|
||||
return null;
|
||||
|
||||
// Fill in the rest of the data
|
||||
drive.PopulateFromDriveInfo(driveInfo);
|
||||
|
||||
return drive;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populate all fields from a DriveInfo object
|
||||
/// </summary>
|
||||
/// <param name="driveInfo">DriveInfo object to populate from</param>
|
||||
private void PopulateFromDriveInfo(DriveInfo? driveInfo)
|
||||
{
|
||||
// If we have an invalid DriveInfo, just return
|
||||
if (driveInfo == null || driveInfo == default)
|
||||
return;
|
||||
|
||||
// Populate the data fields
|
||||
this.Name = driveInfo.Name;
|
||||
this.MarkedActive = driveInfo.IsReady;
|
||||
if (this.MarkedActive)
|
||||
{
|
||||
this.DriveFormat = driveInfo.DriveFormat;
|
||||
this.TotalSize = driveInfo.TotalSize;
|
||||
this.VolumeLabel = driveInfo.VolumeLabel;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.DriveFormat = string.Empty;
|
||||
this.TotalSize = default;
|
||||
this.VolumeLabel = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
#region Public Functionality
|
||||
|
||||
/// <summary>
|
||||
/// Create a list of active drives matched to their volume labels
|
||||
/// </summary>
|
||||
/// <param name="ignoreFixedDrives">True to ignore fixed drives from population, false otherwise</param>
|
||||
/// <returns>Active drives, matched to labels, if possible</returns>
|
||||
public static List<Drive> CreateListOfDrives(bool ignoreFixedDrives)
|
||||
{
|
||||
var drives = GetDriveList(ignoreFixedDrives);
|
||||
drives = [.. drives.OrderBy(i => i == null ? "\0" : i.Name)];
|
||||
return drives;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current media type from drive letter
|
||||
/// </summary>
|
||||
/// <param name="system"></param>
|
||||
/// <returns></returns>
|
||||
public (MediaType?, string?) GetMediaType(RedumpSystem? system)
|
||||
{
|
||||
// Take care of the non-optical stuff first
|
||||
switch (this.InternalDriveType)
|
||||
{
|
||||
case Data.InternalDriveType.Floppy:
|
||||
return (MediaType.FloppyDisk, null);
|
||||
case Data.InternalDriveType.HardDisk:
|
||||
return (MediaType.HardDisk, null);
|
||||
case Data.InternalDriveType.Removable:
|
||||
return (MediaType.FlashDrive, null);
|
||||
}
|
||||
|
||||
// Some systems should default to certain media types
|
||||
switch (system)
|
||||
{
|
||||
// CD
|
||||
case RedumpSystem.Panasonic3DOInteractiveMultiplayer:
|
||||
case RedumpSystem.PhilipsCDi:
|
||||
case RedumpSystem.SegaDreamcast:
|
||||
case RedumpSystem.SegaSaturn:
|
||||
case RedumpSystem.SonyPlayStation:
|
||||
case RedumpSystem.VideoCD:
|
||||
return (MediaType.CDROM, null);
|
||||
|
||||
// DVD
|
||||
case RedumpSystem.DVDAudio:
|
||||
case RedumpSystem.DVDVideo:
|
||||
case RedumpSystem.MicrosoftXbox:
|
||||
case RedumpSystem.MicrosoftXbox360:
|
||||
return (MediaType.DVD, null);
|
||||
|
||||
// HD-DVD
|
||||
case RedumpSystem.HDDVDVideo:
|
||||
return (MediaType.HDDVD, null);
|
||||
|
||||
// Blu-ray
|
||||
case RedumpSystem.BDVideo:
|
||||
case RedumpSystem.MicrosoftXboxOne:
|
||||
case RedumpSystem.MicrosoftXboxSeriesXS:
|
||||
case RedumpSystem.SonyPlayStation3:
|
||||
case RedumpSystem.SonyPlayStation4:
|
||||
case RedumpSystem.SonyPlayStation5:
|
||||
return (MediaType.BluRay, null);
|
||||
|
||||
// GameCube
|
||||
case RedumpSystem.NintendoGameCube:
|
||||
return (MediaType.NintendoGameCubeGameDisc, null);
|
||||
|
||||
// Wii
|
||||
case RedumpSystem.NintendoWii:
|
||||
return (MediaType.NintendoWiiOpticalDisc, null);
|
||||
|
||||
// WiiU
|
||||
case RedumpSystem.NintendoWiiU:
|
||||
return (MediaType.NintendoWiiUOpticalDisc, null);
|
||||
|
||||
// PSP
|
||||
case RedumpSystem.SonyPlayStationPortable:
|
||||
return (MediaType.UMD, null);
|
||||
}
|
||||
|
||||
// Handle optical media by size and filesystem
|
||||
if (this.TotalSize >= 0 && this.TotalSize <= 800_000_000 && (this.DriveFormat == "CDFS" || this.DriveFormat == "UDF"))
|
||||
return (MediaType.CDROM, null);
|
||||
else if (this.TotalSize > 800_000_000 && this.TotalSize <= 8_540_000_000 && (this.DriveFormat == "CDFS" || this.DriveFormat == "UDF"))
|
||||
return (MediaType.DVD, null);
|
||||
else if (this.TotalSize > 8_540_000_000)
|
||||
return (MediaType.BluRay, null);
|
||||
|
||||
return (null, "Could not determine media type!");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current system from drive
|
||||
/// </summary>
|
||||
/// <param name="defaultValue"></param>
|
||||
/// <returns></returns>
|
||||
public RedumpSystem? GetRedumpSystem(RedumpSystem? defaultValue)
|
||||
{
|
||||
// If we can't read the media in that drive, we can't do anything
|
||||
if (string.IsNullOrEmpty(this.Name) || !Directory.Exists(this.Name))
|
||||
return defaultValue;
|
||||
|
||||
// We're going to assume for floppies, HDDs, and removable drives
|
||||
if (this.InternalDriveType != Data.InternalDriveType.Optical)
|
||||
return RedumpSystem.IBMPCcompatible;
|
||||
|
||||
// Check volume labels first
|
||||
RedumpSystem? systemFromLabel = GetRedumpSystemFromVolumeLabel(this.VolumeLabel);
|
||||
if (systemFromLabel != null)
|
||||
return systemFromLabel;
|
||||
|
||||
// Get a list of files for quicker checking
|
||||
#region Arcade
|
||||
|
||||
// funworld Photo Play
|
||||
if (File.Exists(Path.Combine(this.Name, "PP.INF"))
|
||||
&& Directory.Exists(Path.Combine(this.Name, "PPINC")))
|
||||
{
|
||||
return RedumpSystem.funworldPhotoPlay;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Consoles
|
||||
|
||||
// Bandai Playdia Quick Interactive System
|
||||
try
|
||||
{
|
||||
#if NET20 || NET35
|
||||
List<string> files = [.. Directory.GetFiles(this.Name, "*", SearchOption.TopDirectoryOnly)];
|
||||
#else
|
||||
List<string> files = Directory.EnumerateFiles(this.Name, "*", SearchOption.TopDirectoryOnly).ToList();
|
||||
#endif
|
||||
|
||||
if (files.Any(f => f.EndsWith(".AJS", StringComparison.OrdinalIgnoreCase))
|
||||
&& files.Any(f => f.EndsWith(".GLB", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return RedumpSystem.BandaiPlaydiaQuickInteractiveSystem;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Bandai Pippin
|
||||
if (File.Exists(Path.Combine(this.Name, "PippinAuthenticationFile")))
|
||||
{
|
||||
return RedumpSystem.BandaiPippin;
|
||||
}
|
||||
|
||||
// Commodore CDTV/CD32
|
||||
#if NET20 || NET35
|
||||
if (File.Exists(Path.Combine(Path.Combine(this.Name, "S"), "STARTUP-SEQUENCE")))
|
||||
#else
|
||||
if (File.Exists(Path.Combine(this.Name, "S", "STARTUP-SEQUENCE")))
|
||||
#endif
|
||||
{
|
||||
if (File.Exists(Path.Combine(this.Name, "CDTV.TM")))
|
||||
return RedumpSystem.CommodoreAmigaCDTV;
|
||||
else
|
||||
return RedumpSystem.CommodoreAmigaCD32;
|
||||
}
|
||||
|
||||
// Mattel HyperScan -- TODO: May need case-insensitivity added
|
||||
if (File.Exists(Path.Combine(this.Name, "hyper.exe")))
|
||||
{
|
||||
return RedumpSystem.MattelHyperScan;
|
||||
}
|
||||
|
||||
// Mattel Fisher-Price iXL
|
||||
#if NET20 || NET35
|
||||
if (File.Exists(Path.Combine(Path.Combine(this.Name, "iXL"), "iXLUpdater.exe")))
|
||||
#else
|
||||
if (File.Exists(Path.Combine(this.Name, "iXL", "iXLUpdater.exe")))
|
||||
#endif
|
||||
{
|
||||
return RedumpSystem.MattelFisherPriceiXL;
|
||||
}
|
||||
|
||||
// Microsoft Xbox 360
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(this.Name, "$SystemUpdate"))
|
||||
#if NET20 || NET35
|
||||
&& Directory.GetFiles(Path.Combine(this.Name, "$SystemUpdate")).Any()
|
||||
#else
|
||||
&& Directory.EnumerateFiles(Path.Combine(this.Name, "$SystemUpdate")).Any()
|
||||
#endif
|
||||
&& this.TotalSize <= 500_000_000)
|
||||
{
|
||||
return RedumpSystem.MicrosoftXbox360;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Microsoft Xbox One
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(this.Name, "MSXC"))
|
||||
#if NET20 || NET35
|
||||
&& Directory.GetFiles(Path.Combine(this.Name, "MSXC")).Any())
|
||||
#else
|
||||
&& Directory.EnumerateFiles(Path.Combine(this.Name, "MSXC")).Any())
|
||||
#endif
|
||||
{
|
||||
return RedumpSystem.MicrosoftXboxOne;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Sega Dreamcast
|
||||
if (File.Exists(Path.Combine(this.Name, "IP.BIN")))
|
||||
{
|
||||
return RedumpSystem.SegaDreamcast;
|
||||
}
|
||||
|
||||
// Sega Mega-CD / Sega-CD
|
||||
#if NET20 || NET35
|
||||
if (File.Exists(Path.Combine(Path.Combine(this.Name, "_BOOT"), "IP.BIN"))
|
||||
|| File.Exists(Path.Combine(Path.Combine(this.Name, "_BOOT"), "SP.BIN"))
|
||||
|| File.Exists(Path.Combine(Path.Combine(this.Name, "_BOOT"), "SP_AS.BIN"))
|
||||
|| File.Exists(Path.Combine(this.Name, "FILESYSTEM.BIN")))
|
||||
#else
|
||||
if (File.Exists(Path.Combine(this.Name, "_BOOT", "IP.BIN"))
|
||||
|| File.Exists(Path.Combine(this.Name, "_BOOT", "SP.BIN"))
|
||||
|| File.Exists(Path.Combine(this.Name, "_BOOT", "SP_AS.BIN"))
|
||||
|| File.Exists(Path.Combine(this.Name, "FILESYSTEM.BIN")))
|
||||
#endif
|
||||
{
|
||||
return RedumpSystem.SegaMegaCDSegaCD;
|
||||
}
|
||||
|
||||
// Sony PlayStation and Sony PlayStation 2
|
||||
string psxExePath = Path.Combine(this.Name, "PSX.EXE");
|
||||
string systemCnfPath = Path.Combine(this.Name, "SYSTEM.CNF");
|
||||
if (File.Exists(systemCnfPath))
|
||||
{
|
||||
// Check for either BOOT or BOOT2
|
||||
var systemCnf = new IniFile(systemCnfPath);
|
||||
if (systemCnf.ContainsKey("BOOT"))
|
||||
return RedumpSystem.SonyPlayStation;
|
||||
else if (systemCnf.ContainsKey("BOOT2"))
|
||||
return RedumpSystem.SonyPlayStation2;
|
||||
}
|
||||
else if (File.Exists(psxExePath))
|
||||
{
|
||||
return RedumpSystem.SonyPlayStation;
|
||||
}
|
||||
|
||||
// Sony PlayStation 3
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(this.Name, "PS3_GAME"))
|
||||
|| Directory.Exists(Path.Combine(this.Name, "PS3_UPDATE"))
|
||||
|| File.Exists(Path.Combine(this.Name, "PS3_DISC.SFB")))
|
||||
{
|
||||
return RedumpSystem.SonyPlayStation3;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Sony PlayStation 4
|
||||
// There are more possible paths that could be checked.
|
||||
// There are some entries that can be found on most PS4 discs:
|
||||
// "/app/GAME_SERIAL/app.pkg"
|
||||
// "/bd/param.sfo"
|
||||
// "/license/rif"
|
||||
// There are also extra files that can be found on some discs:
|
||||
// "/patch/GAME_SERIAL/patch.pkg" can be found in Redump entry 66816.
|
||||
// Originally on disc as "/patch/CUSA11302/patch.pkg".
|
||||
// Is used as an on-disc update for the base game app without needing to get update from the internet.
|
||||
// "/addcont/GAME_SERIAL/CONTENT_ID/ac.pkg" can be found in Redump entry 97619.
|
||||
// Originally on disc as "/addcont/CUSA00288/FFXIVEXPS400001A/ac.pkg".
|
||||
#if NET20 || NET35
|
||||
if (File.Exists(Path.Combine(Path.Combine(Path.Combine(this.Name, "PS4"), "UPDATE"), "PS4UPDATE.PUP")))
|
||||
#else
|
||||
if (File.Exists(Path.Combine(this.Name, "PS4", "UPDATE", "PS4UPDATE.PUP")))
|
||||
#endif
|
||||
{
|
||||
return RedumpSystem.SonyPlayStation4;
|
||||
}
|
||||
|
||||
// V.Tech V.Flash / V.Smile Pro
|
||||
if (File.Exists(Path.Combine(this.Name, "0SYSTEM")))
|
||||
{
|
||||
return RedumpSystem.VTechVFlashVSmilePro;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Computers
|
||||
|
||||
// Sharp X68000
|
||||
if (File.Exists(Path.Combine(this.Name, "COMMAND.X")))
|
||||
{
|
||||
return RedumpSystem.SharpX68000;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Video Formats
|
||||
|
||||
// BD-Video
|
||||
if (Directory.Exists(Path.Combine(this.Name, "BDMV")))
|
||||
{
|
||||
// Technically BD-Audio has this as well, but it's hard to split that out right now
|
||||
return RedumpSystem.BDVideo;
|
||||
}
|
||||
|
||||
// DVD-Audio and DVD-Video
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(this.Name, "AUDIO_TS"))
|
||||
#if NET20 || NET35
|
||||
&& Directory.GetFiles(Path.Combine(this.Name, "AUDIO_TS")).Any())
|
||||
#else
|
||||
&& Directory.EnumerateFiles(Path.Combine(this.Name, "AUDIO_TS")).Any())
|
||||
#endif
|
||||
{
|
||||
return RedumpSystem.DVDAudio;
|
||||
}
|
||||
|
||||
else if (Directory.Exists(Path.Combine(this.Name, "VIDEO_TS"))
|
||||
#if NET20 || NET35
|
||||
&& Directory.GetFiles(Path.Combine(this.Name, "VIDEO_TS")).Any())
|
||||
#else
|
||||
&& Directory.EnumerateFiles(Path.Combine(this.Name, "VIDEO_TS")).Any())
|
||||
#endif
|
||||
{
|
||||
return RedumpSystem.DVDVideo;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// HD-DVD-Video
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(this.Name, "HVDVD_TS"))
|
||||
#if NET20 || NET35
|
||||
&& Directory.GetFiles(Path.Combine(this.Name, "HVDVD_TS")).Any())
|
||||
#else
|
||||
&& Directory.EnumerateFiles(Path.Combine(this.Name, "HVDVD_TS")).Any())
|
||||
#endif
|
||||
{
|
||||
return RedumpSystem.HDDVDVideo;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Photo CD
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(this.Name, "PHOTO_CD"))
|
||||
#if NET20 || NET35
|
||||
&& Directory.GetFiles(Path.Combine(this.Name, "PHOTO_CD")).Any())
|
||||
#else
|
||||
&& Directory.EnumerateFiles(Path.Combine(this.Name, "PHOTO_CD")).Any())
|
||||
#endif
|
||||
{
|
||||
return RedumpSystem.PhotoCD;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// VCD
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(this.Name, "VCD"))
|
||||
#if NET20 || NET35
|
||||
&& Directory.GetFiles(Path.Combine(this.Name, "VCD")).Any())
|
||||
#else
|
||||
&& Directory.EnumerateFiles(Path.Combine(this.Name, "VCD")).Any())
|
||||
#endif
|
||||
{
|
||||
return RedumpSystem.VideoCD;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
#endregion
|
||||
|
||||
// Default return
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current system from the drive volume label
|
||||
/// </summary>
|
||||
/// <returns>The system based on volume label, null if none detected</returns>
|
||||
public static RedumpSystem? GetRedumpSystemFromVolumeLabel(string? volumeLabel)
|
||||
{
|
||||
// If the volume label is empty, we can't do anything
|
||||
if (string.IsNullOrEmpty(volumeLabel))
|
||||
return null;
|
||||
|
||||
// Audio CD
|
||||
if (volumeLabel!.Equals("Audio CD", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.AudioCD;
|
||||
|
||||
// Microsoft Xbox
|
||||
if (volumeLabel.Equals("SEP13011042", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.MicrosoftXbox;
|
||||
else if (volumeLabel.Equals("SEP13011042072", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.MicrosoftXbox;
|
||||
|
||||
// Microsoft Xbox 360
|
||||
if (volumeLabel.Equals("XBOX360", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.MicrosoftXbox360;
|
||||
else if (volumeLabel.Equals("XGD2DVD_NTSC", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.MicrosoftXbox360;
|
||||
|
||||
// Microsoft Xbox 360 - Too overly broad even if a lot of discs use this
|
||||
//if (volumeLabel.Equals("CD_ROM", StringComparison.OrdinalIgnoreCase))
|
||||
// return RedumpSystem.MicrosoftXbox360; // Also for Xbox One?
|
||||
//if (volumeLabel.Equals("DVD_ROM", StringComparison.OrdinalIgnoreCase))
|
||||
// return RedumpSystem.MicrosoftXbox360;
|
||||
|
||||
// Sega Mega-CD / Sega-CD
|
||||
if (volumeLabel.Equals("Sega_CD", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.SegaMegaCDSegaCD;
|
||||
|
||||
// Sony PlayStation 3
|
||||
if (volumeLabel.Equals("PS3VOLUME", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.SonyPlayStation3;
|
||||
|
||||
// Sony PlayStation 4
|
||||
if (volumeLabel.Equals("PS4VOLUME", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.SonyPlayStation4;
|
||||
|
||||
// Sony PlayStation 5
|
||||
if (volumeLabel.Equals("PS5VOLUME", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.SonyPlayStation5;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refresh the current drive information based on path
|
||||
/// </summary>
|
||||
public void RefreshDrive()
|
||||
{
|
||||
var driveInfo = DriveInfo.GetDrives().FirstOrDefault(d => d?.Name == this.Name);
|
||||
this.PopulateFromDriveInfo(driveInfo);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Get all current attached Drives
|
||||
/// </summary>
|
||||
/// <param name="ignoreFixedDrives">True to ignore fixed drives from population, false otherwise</param>
|
||||
/// <returns>List of drives, null on error</returns>
|
||||
/// <remarks>
|
||||
/// https://stackoverflow.com/questions/3060796/how-to-distinguish-between-usb-and-floppy-devices?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
|
||||
/// https://msdn.microsoft.com/en-us/library/aa394173(v=vs.85).aspx
|
||||
/// </remarks>
|
||||
private static List<Drive> GetDriveList(bool ignoreFixedDrives)
|
||||
{
|
||||
var desiredDriveTypes = new List<DriveType>() { DriveType.CDRom };
|
||||
if (!ignoreFixedDrives)
|
||||
{
|
||||
desiredDriveTypes.Add(DriveType.Fixed);
|
||||
desiredDriveTypes.Add(DriveType.Removable);
|
||||
}
|
||||
|
||||
// TODO: Reduce reliance on `DriveInfo`
|
||||
// https://github.com/aaru-dps/Aaru/blob/5164a154e2145941472f2ee0aeb2eff3338ecbb3/Aaru.Devices/Windows/ListDevices.cs#L66
|
||||
|
||||
// Create an output drive list
|
||||
var drives = new List<Drive>();
|
||||
|
||||
// Get all standard supported drive types
|
||||
try
|
||||
{
|
||||
drives = DriveInfo.GetDrives()
|
||||
.Where(d => desiredDriveTypes.Contains(d.DriveType))
|
||||
.Select(d => Create(EnumConverter.ToInternalDriveType(d.DriveType), d.Name) ?? new Drive())
|
||||
.ToList();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return drives;
|
||||
}
|
||||
|
||||
// Find and update all floppy drives
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
try
|
||||
{
|
||||
CimSession session = CimSession.Create(null);
|
||||
var collection = session.QueryInstances("root\\CIMV2", "WQL", "SELECT * FROM Win32_LogicalDisk");
|
||||
|
||||
foreach (CimInstance instance in collection)
|
||||
{
|
||||
CimKeyedCollection<CimProperty> properties = instance.CimInstanceProperties;
|
||||
uint? mediaType = properties["MediaType"]?.Value as uint?;
|
||||
if (mediaType != null && ((mediaType > 0 && mediaType < 11) || (mediaType > 12 && mediaType < 22)))
|
||||
{
|
||||
char devId = (properties["Caption"].Value as string ?? string.Empty)[0];
|
||||
drives.ForEach(d => { if (d?.Name != null && d.Name[0] == devId) { d.InternalDriveType = Data.InternalDriveType.Floppy; } });
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
#endif
|
||||
|
||||
return drives;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
63
MPF.Core/Data/Enumerations.cs
Normal file
63
MPF.Core/Data/Enumerations.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Available hashing types
|
||||
/// </summary>
|
||||
public enum Hash
|
||||
{
|
||||
CRC32,
|
||||
#if NET6_0_OR_GREATER
|
||||
CRC64,
|
||||
#endif
|
||||
MD5,
|
||||
SHA1,
|
||||
SHA256,
|
||||
SHA384,
|
||||
SHA512,
|
||||
#if NET6_0_OR_GREATER
|
||||
XxHash32,
|
||||
XxHash64,
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drive type for dumping
|
||||
/// </summary>
|
||||
public enum InternalDriveType
|
||||
{
|
||||
Optical,
|
||||
Floppy,
|
||||
HardDisk,
|
||||
Removable,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Program that is being used to dump media
|
||||
/// </summary>
|
||||
public enum InternalProgram
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
// Dumping support
|
||||
Aaru,
|
||||
DiscImageCreator,
|
||||
Redumper,
|
||||
|
||||
// Verification support only
|
||||
CleanRip,
|
||||
DCDumper,
|
||||
PS3CFW,
|
||||
UmdImageCreator,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log level for output
|
||||
/// </summary>
|
||||
public enum LogLevel
|
||||
{
|
||||
USER,
|
||||
VERBOSE,
|
||||
ERROR,
|
||||
SECRET,
|
||||
}
|
||||
}
|
||||
294
MPF.Core/Data/IniFile.cs
Normal file
294
MPF.Core/Data/IniFile.cs
Normal file
@@ -0,0 +1,294 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
public class IniFile : IDictionary<string, string>
|
||||
{
|
||||
private Dictionary<string, string> _keyValuePairs = [];
|
||||
|
||||
public string this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
_keyValuePairs ??= [];
|
||||
|
||||
key = key.ToLowerInvariant();
|
||||
if (_keyValuePairs.TryGetValue(key, out string? val))
|
||||
return val;
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
set
|
||||
{
|
||||
_keyValuePairs ??= [];
|
||||
|
||||
key = key.ToLowerInvariant();
|
||||
_keyValuePairs[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty INI file
|
||||
/// </summary>
|
||||
public IniFile()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populate an INI file from path
|
||||
/// </summary>
|
||||
public IniFile(string path)
|
||||
{
|
||||
this.Parse(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populate an INI file from stream
|
||||
/// </summary>
|
||||
public IniFile(Stream stream)
|
||||
{
|
||||
this.Parse(stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add or update a key and value to the INI file
|
||||
/// </summary>
|
||||
public void AddOrUpdate(string key, string value)
|
||||
{
|
||||
_keyValuePairs[key.ToLowerInvariant()] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a key from the INI file
|
||||
/// </summary>
|
||||
public void Remove(string key)
|
||||
{
|
||||
_keyValuePairs.Remove(key.ToLowerInvariant());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an INI file based on the path
|
||||
/// </summary>
|
||||
public bool Parse(string path)
|
||||
{
|
||||
// If we don't have a file, we can't read it
|
||||
if (!File.Exists(path))
|
||||
return false;
|
||||
|
||||
using var fileStream = File.OpenRead(path);
|
||||
return Parse(fileStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an INI file from a stream
|
||||
/// </summary>
|
||||
public bool Parse(Stream stream)
|
||||
{
|
||||
// If the stream is invalid or unreadable, we can't process it
|
||||
if (stream == null || !stream.CanRead || stream.Position >= stream.Length - 1)
|
||||
return false;
|
||||
|
||||
// Keys are case-insensitive by default
|
||||
try
|
||||
{
|
||||
using var sr = new StreamReader(stream);
|
||||
string section = string.Empty;
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
var line = sr.ReadLine()?.Trim();
|
||||
|
||||
// Empty lines are skipped
|
||||
if (string.IsNullOrEmpty(line))
|
||||
{
|
||||
// No-op, we don't process empty lines
|
||||
}
|
||||
|
||||
// Comments start with ';'
|
||||
else if (line!.StartsWith(";"))
|
||||
{
|
||||
// No-op, we don't process comments
|
||||
}
|
||||
|
||||
// Section titles are surrounded by square brackets
|
||||
else if (line.StartsWith("["))
|
||||
{
|
||||
section = line.TrimStart('[').TrimEnd(']');
|
||||
}
|
||||
|
||||
// Valid INI lines are in the format key=value
|
||||
else if (line.Contains('='))
|
||||
{
|
||||
// Split the line by '=' for key-value pairs
|
||||
string[] data = line.Split('=');
|
||||
|
||||
// If the value field contains an '=', we need to put them back in
|
||||
string key = data[0].Trim();
|
||||
string value = string.Join("=", data.Skip(1).ToArray()).Trim();
|
||||
|
||||
// Section names are prepended to the key with a '.' separating
|
||||
if (!string.IsNullOrEmpty(section))
|
||||
key = $"{section}.{key}";
|
||||
|
||||
// Set or overwrite keys in the returned dictionary
|
||||
_keyValuePairs[key.ToLowerInvariant()] = value;
|
||||
}
|
||||
|
||||
// All other lines are ignored
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error was, just catch and return
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an INI file to a path
|
||||
/// </summary>
|
||||
public bool Write(string path)
|
||||
{
|
||||
// If we don't have a valid dictionary with values, we can't write out
|
||||
if (_keyValuePairs == null || _keyValuePairs.Count == 0)
|
||||
return false;
|
||||
|
||||
using var fileStream = File.OpenWrite(path);
|
||||
return Write(fileStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an INI file to a stream
|
||||
/// </summary>
|
||||
public bool Write(Stream stream)
|
||||
{
|
||||
// If we don't have a valid dictionary with values, we can't write out
|
||||
if (_keyValuePairs == null || _keyValuePairs.Count == 0)
|
||||
return false;
|
||||
|
||||
// If the stream is invalid or unwritable, we can't output to it
|
||||
if (stream == null || !stream.CanWrite || stream.Position >= stream.Length - 1)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
// Order the dictionary by keys to link sections together
|
||||
using var sw = new StreamWriter(stream);
|
||||
var orderedKeyValuePairs = _keyValuePairs.OrderBy(kvp => kvp.Key);
|
||||
|
||||
string section = string.Empty;
|
||||
foreach (var keyValuePair in orderedKeyValuePairs)
|
||||
{
|
||||
// Extract the key and value
|
||||
string key = keyValuePair.Key;
|
||||
string value = keyValuePair.Value;
|
||||
|
||||
// We assume '.' is a section name separator
|
||||
if (key.Contains('.'))
|
||||
{
|
||||
// Split the key by '.'
|
||||
string[] data = keyValuePair.Key.Split('.');
|
||||
|
||||
// If the key contains an '.', we need to put them back in
|
||||
string newSection = data[0].Trim();
|
||||
key = string.Join(".", data.Skip(1).ToArray()).Trim();
|
||||
|
||||
// If we have a new section, write it out
|
||||
if (!string.Equals(newSection, section, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
sw.WriteLine($"[{newSection}]");
|
||||
section = newSection;
|
||||
}
|
||||
}
|
||||
|
||||
// Now write out the key and value in a standardized way
|
||||
sw.WriteLine($"{key}={value}");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error was, just catch and return
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#region IDictionary Impelementations
|
||||
|
||||
public ICollection<string> Keys => ((IDictionary<string, string>)_keyValuePairs).Keys;
|
||||
|
||||
public ICollection<string> Values => ((IDictionary<string, string>)_keyValuePairs).Values;
|
||||
|
||||
public int Count => ((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Count;
|
||||
|
||||
public bool IsReadOnly => ((ICollection<KeyValuePair<string, string>>)_keyValuePairs).IsReadOnly;
|
||||
|
||||
public void Add(string key, string value)
|
||||
{
|
||||
((IDictionary<string, string>)_keyValuePairs).Add(key.ToLowerInvariant(), value);
|
||||
}
|
||||
|
||||
bool IDictionary<string, string>.Remove(string key)
|
||||
{
|
||||
return ((IDictionary<string, string>)_keyValuePairs).Remove(key.ToLowerInvariant());
|
||||
}
|
||||
|
||||
public bool TryGetValue(string key, out string value)
|
||||
{
|
||||
bool result = ((IDictionary<string, string>)_keyValuePairs).TryGetValue(key.ToLowerInvariant(), out var temp);
|
||||
value = temp ?? string.Empty;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<string, string> item)
|
||||
{
|
||||
var newItem = new KeyValuePair<string, string>(item.Key.ToLowerInvariant(), item.Value);
|
||||
((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Add(newItem);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Clear();
|
||||
}
|
||||
|
||||
public bool Contains(KeyValuePair<string, string> item)
|
||||
{
|
||||
var newItem = new KeyValuePair<string, string>(item.Key.ToLowerInvariant(), item.Value);
|
||||
return ((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Contains(newItem);
|
||||
}
|
||||
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
return _keyValuePairs.ContainsKey(key.ToLowerInvariant());
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex)
|
||||
{
|
||||
((ICollection<KeyValuePair<string, string>>)_keyValuePairs).CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<string, string> item)
|
||||
{
|
||||
var newItem = new KeyValuePair<string, string>(item.Key.ToLowerInvariant(), item.Value);
|
||||
return ((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Remove(newItem);
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable<KeyValuePair<string, string>>)_keyValuePairs).GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable)_keyValuePairs).GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
713
MPF.Core/Data/Options.cs
Normal file
713
MPF.Core/Data/Options.cs
Normal file
@@ -0,0 +1,713 @@
|
||||
using System.Collections.Generic;
|
||||
using MPF.Core.Converters;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
public class Options
|
||||
{
|
||||
/// <summary>
|
||||
/// All settings in the form of a dictionary
|
||||
/// </summary>
|
||||
public Dictionary<string, string?> Settings { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicate if the program is being run with a clean configuration
|
||||
/// </summary>
|
||||
public bool FirstRun
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "FirstRun", true); }
|
||||
set { Settings["FirstRun"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#region Internal Program
|
||||
|
||||
/// <summary>
|
||||
/// Path to Aaru
|
||||
/// </summary>
|
||||
public string? AaruPath
|
||||
{
|
||||
get { return GetStringSetting(Settings, "AaruPath", "Programs\\Aaru\\Aaru.exe"); }
|
||||
set { Settings["AaruPath"] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Path to DiscImageCreator
|
||||
/// </summary>
|
||||
public string? DiscImageCreatorPath
|
||||
{
|
||||
get { return GetStringSetting(Settings, "DiscImageCreatorPath", "Programs\\Creator\\DiscImageCreator.exe"); }
|
||||
set { Settings["DiscImageCreatorPath"] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Path to Redumper
|
||||
/// </summary>
|
||||
public string? RedumperPath
|
||||
{
|
||||
get { return GetStringSetting(Settings, "RedumperPath", "Programs\\Redumper\\redumper.exe"); }
|
||||
set { Settings["RedumperPath"] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected dumping program
|
||||
/// </summary>
|
||||
public InternalProgram InternalProgram
|
||||
{
|
||||
get
|
||||
{
|
||||
var valueString = GetStringSetting(Settings, "InternalProgram", InternalProgram.Redumper.ToString());
|
||||
var valueEnum = EnumConverter.ToInternalProgram(valueString);
|
||||
return valueEnum == InternalProgram.NONE ? InternalProgram.Redumper : valueEnum;
|
||||
}
|
||||
set
|
||||
{
|
||||
Settings["InternalProgram"] = value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI Defaults
|
||||
|
||||
/// <summary>
|
||||
/// Enable dark mode for UI elements
|
||||
/// </summary>
|
||||
public bool EnableDarkMode
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "EnableDarkMode", false); }
|
||||
set { Settings["EnableDarkMode"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check for updates on startup
|
||||
/// </summary>
|
||||
public bool CheckForUpdatesOnStartup
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "CheckForUpdatesOnStartup", true); }
|
||||
set { Settings["CheckForUpdatesOnStartup"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fast update label - Skips disc checks and updates path only
|
||||
/// </summary>
|
||||
public bool FastUpdateLabel
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "FastUpdateLabel", false); }
|
||||
set { Settings["FastUpdateLabel"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default output path for dumps
|
||||
/// </summary>
|
||||
public string? DefaultOutputPath
|
||||
{
|
||||
get { return GetStringSetting(Settings, "DefaultOutputPath", "ISO"); }
|
||||
set { Settings["DefaultOutputPath"] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default system if none can be detected
|
||||
/// </summary>
|
||||
public RedumpSystem? DefaultSystem
|
||||
{
|
||||
get
|
||||
{
|
||||
var valueString = GetStringSetting(Settings, "DefaultSystem", null);
|
||||
var valueEnum = Extensions.ToRedumpSystem(valueString ?? string.Empty);
|
||||
return valueEnum;
|
||||
}
|
||||
set
|
||||
{
|
||||
Settings["DefaultSystem"] = value.LongName();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default output path for dumps
|
||||
/// </summary>
|
||||
/// <remarks>This is a hidden setting</remarks>
|
||||
public bool ShowDebugViewMenuItem
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "ShowDebugViewMenuItem", false); }
|
||||
set { Settings["ShowDebugViewMenuItem"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dumping Speeds
|
||||
|
||||
/// <summary>
|
||||
/// Default CD dumping speed
|
||||
/// </summary>
|
||||
public int PreferredDumpSpeedCD
|
||||
{
|
||||
get { return GetInt32Setting(Settings, "PreferredDumpSpeedCD", 24); }
|
||||
set { Settings["PreferredDumpSpeedCD"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default DVD dumping speed
|
||||
/// </summary>
|
||||
public int PreferredDumpSpeedDVD
|
||||
{
|
||||
get { return GetInt32Setting(Settings, "PreferredDumpSpeedDVD", 16); }
|
||||
set { Settings["PreferredDumpSpeedDVD"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default HD-DVD dumping speed
|
||||
/// </summary>
|
||||
public int PreferredDumpSpeedHDDVD
|
||||
{
|
||||
get { return GetInt32Setting(Settings, "PreferredDumpSpeedHDDVD", 8); }
|
||||
set { Settings["PreferredDumpSpeedHDDVD"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default BD dumping speed
|
||||
/// </summary>
|
||||
public int PreferredDumpSpeedBD
|
||||
{
|
||||
get { return GetInt32Setting(Settings, "PreferredDumpSpeedBD", 8); }
|
||||
set { Settings["PreferredDumpSpeedBD"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Aaru
|
||||
|
||||
/// <summary>
|
||||
/// Enable debug output while dumping by default
|
||||
/// </summary>
|
||||
public bool AaruEnableDebug
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "AaruEnableDebug", false); }
|
||||
set { Settings["AaruEnableDebug"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable verbose output while dumping by default
|
||||
/// </summary>
|
||||
public bool AaruEnableVerbose
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "AaruEnableVerbose", false); }
|
||||
set { Settings["AaruEnableVerbose"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable force dumping of media by default
|
||||
/// </summary>
|
||||
public bool AaruForceDumping
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "AaruForceDumping", true); }
|
||||
set { Settings["AaruForceDumping"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default number of sector/subchannel rereads
|
||||
/// </summary>
|
||||
public int AaruRereadCount
|
||||
{
|
||||
get { return GetInt32Setting(Settings, "AaruRereadCount", 5); }
|
||||
set { Settings["AaruRereadCount"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strip personal data information from Aaru metadata by default
|
||||
/// </summary>
|
||||
public bool AaruStripPersonalData
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "AaruStripPersonalData", false); }
|
||||
set { Settings["AaruStripPersonalData"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DiscImageCreator
|
||||
|
||||
/// <summary>
|
||||
/// Enable multi-sector read flag by default
|
||||
/// </summary>
|
||||
public bool DICMultiSectorRead
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "DICMultiSectorRead", false); }
|
||||
set { Settings["DICMultiSectorRead"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Include a default multi-sector read value
|
||||
/// </summary>
|
||||
public int DICMultiSectorReadValue
|
||||
{
|
||||
get { return GetInt32Setting(Settings, "DICMultiSectorReadValue", 0); }
|
||||
set { Settings["DICMultiSectorReadValue"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable overly-secure dumping flags by default
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Split this into component parts later. Currently does:
|
||||
/// - Scan sector protection and set subchannel read level to 2 for CD
|
||||
/// - Set scan file protect flag for DVD
|
||||
/// </remarks>
|
||||
public bool DICParanoidMode
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "DICParanoidMode", false); }
|
||||
set { Settings["DICParanoidMode"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable the Quiet flag by default
|
||||
/// </summary>
|
||||
public bool DICQuietMode
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "DICQuietMode", false); }
|
||||
set { Settings["DICQuietMode"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default number of C2 rereads
|
||||
/// </summary>
|
||||
public int DICRereadCount
|
||||
{
|
||||
get { return GetInt32Setting(Settings, "DICRereadCount", 20); }
|
||||
set { Settings["DICRereadCount"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default number of DVD/HD-DVD/BD rereads
|
||||
/// </summary>
|
||||
public int DICDVDRereadCount
|
||||
{
|
||||
get { return GetInt32Setting(Settings, "DICDVDRereadCount", 10); }
|
||||
set { Settings["DICDVDRereadCount"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset drive after dumping (useful for older drives)
|
||||
/// </summary>
|
||||
public bool DICResetDriveAfterDump
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "DICResetDriveAfterDump", false); }
|
||||
set { Settings["DICResetDriveAfterDump"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use the CMI flag for supported disc types
|
||||
/// </summary>
|
||||
public bool DICUseCMIFlag
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "DICUseCMIFlag", false); }
|
||||
set { Settings["DICUseCMIFlag"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Redumper
|
||||
|
||||
/// <summary>
|
||||
/// Enable debug output while dumping by default
|
||||
/// </summary>
|
||||
public bool RedumperEnableDebug
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "RedumperEnableDebug", false); }
|
||||
set { Settings["RedumperEnableDebug"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable verbose output while dumping by default
|
||||
/// </summary>
|
||||
public bool RedumperEnableVerbose
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "RedumperEnableVerbose", true); }
|
||||
set { Settings["RedumperEnableVerbose"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable BE reading by default with Redumper
|
||||
/// </summary>
|
||||
public bool RedumperUseBEReading
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "RedumperUseBEReading", false); }
|
||||
set { Settings["RedumperUseBEReading"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable generic drive type by default with Redumper
|
||||
/// </summary>
|
||||
public bool RedumperUseGenericDriveType
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "RedumperUseGenericDriveType", false); }
|
||||
set { Settings["RedumperUseGenericDriveType"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default number of rereads
|
||||
/// </summary>
|
||||
public int RedumperRereadCount
|
||||
{
|
||||
get { return GetInt32Setting(Settings, "RedumperRereadCount", 20); }
|
||||
set { Settings["RedumperRereadCount"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extra Dumping Options
|
||||
|
||||
/// <summary>
|
||||
/// Scan the disc for protection after dumping
|
||||
/// </summary>
|
||||
public bool ScanForProtection
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "ScanForProtection", true); }
|
||||
set { Settings["ScanForProtection"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Output all found protections to a separate file in the directory
|
||||
/// </summary>
|
||||
public bool OutputSeparateProtectionFile
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "OutputSeparateProtectionFile", true); }
|
||||
set { Settings["OutputSeparateProtectionFile"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add placeholder values in the submission info
|
||||
/// </summary>
|
||||
public bool AddPlaceholders
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "AddPlaceholders", true); }
|
||||
set { Settings["AddPlaceholders"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show the disc information window after dumping
|
||||
/// </summary>
|
||||
public bool PromptForDiscInformation
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "PromptForDiscInformation", true); }
|
||||
set { Settings["PromptForDiscInformation"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pull all information from Redump if signed in
|
||||
/// </summary>
|
||||
public bool PullAllInformation
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "PullAllInformation", false); }
|
||||
set { Settings["PullAllInformation"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable tabs in all input fields
|
||||
/// </summary>
|
||||
public bool EnableTabsInInputFields
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "EnableTabsInInputFields", false); }
|
||||
set { Settings["EnableTabsInInputFields"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Limit outputs to Redump-supported values only
|
||||
/// </summary>
|
||||
public bool EnableRedumpCompatibility
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "EnableRedumpCompatibility", true); }
|
||||
set { Settings["EnableRedumpCompatibility"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show disc eject reminder before the disc information window is shown
|
||||
/// </summary>
|
||||
public bool ShowDiscEjectReminder
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "ShowDiscEjectReminder", true); }
|
||||
set { Settings["ShowDiscEjectReminder"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Eject the disc after dumping
|
||||
/// </summary>
|
||||
public bool EjectAfterDump
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "EjectAfterDump", false); }
|
||||
set { Settings["EjectAfterDump"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ignore fixed drives when populating the list
|
||||
/// </summary>
|
||||
public bool IgnoreFixedDrives
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "IgnoreFixedDrives", true); }
|
||||
set { Settings["IgnoreFixedDrives"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show dumping tools in their own window instead of in the log
|
||||
/// </summary>
|
||||
public bool ToolsInSeparateWindow
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "ToolsInSeparateWindow", true); }
|
||||
set { Settings["ToolsInSeparateWindow"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add the dump filename as a suffix to the auto-generated files
|
||||
/// </summary>
|
||||
public bool AddFilenameSuffix
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "AddFilenameSuffix", false); }
|
||||
set { Settings["AddFilenameSuffix"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Output the compressed JSON version of the submission info
|
||||
/// </summary>
|
||||
public bool OutputSubmissionJSON
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "OutputSubmissionJSON", false); }
|
||||
set { Settings["OutputSubmissionJSON"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Include log files in serialized JSON data
|
||||
/// </summary>
|
||||
public bool IncludeArtifacts
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "IncludeArtifacts", false); }
|
||||
set { Settings["IncludeArtifacts"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compress output log files to reduce space
|
||||
/// </summary>
|
||||
public bool CompressLogFiles
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "CompressLogFiles", true); }
|
||||
set { Settings["CompressLogFiles"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete unnecessary files to reduce space
|
||||
/// </summary>
|
||||
public bool DeleteUnnecessaryFiles
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "DeleteUnnecessaryFiles", false); }
|
||||
set { Settings["DeleteUnnecessaryFiles"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a PS3 IRD file after dumping PS3 BD-ROM discs
|
||||
/// </summary>
|
||||
public bool CreateIRDAfterDumping
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "CreateIRDAfterDumping", false); }
|
||||
set { Settings["CreateIRDAfterDumping"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Skip Options
|
||||
|
||||
/// <summary>
|
||||
/// Skip detecting media type on disc scan
|
||||
/// </summary>
|
||||
public bool SkipMediaTypeDetection
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "SkipMediaTypeDetection", false); }
|
||||
set { Settings["SkipMediaTypeDetection"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Skip detecting known system on disc scan
|
||||
/// </summary>
|
||||
public bool SkipSystemDetection
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "SkipSystemDetection", false); }
|
||||
set { Settings["SkipSystemDetection"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protection Scanning Options
|
||||
|
||||
/// <summary>
|
||||
/// Scan archive contents during protection scanning
|
||||
/// </summary>
|
||||
public bool ScanArchivesForProtection
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "ScanArchivesForProtection", true); }
|
||||
set { Settings["ScanArchivesForProtection"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scan for executable packers during protection scanning
|
||||
/// </summary>
|
||||
public bool ScanPackersForProtection
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "ScanPackersForProtection", false); }
|
||||
set { Settings["ScanPackersForProtection"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Include debug information with scan results
|
||||
/// </summary>
|
||||
public bool IncludeDebugProtectionInformation
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "IncludeDebugProtectionInformation", false); }
|
||||
set { Settings["IncludeDebugProtectionInformation"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove drive letters from protection scan output
|
||||
/// </summary>
|
||||
public bool HideDriveLetters
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "HideDriveLetters", false); }
|
||||
set { Settings["HideDriveLetters"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Logging Options
|
||||
|
||||
/// <summary>
|
||||
/// Enable verbose and debug logs to be written
|
||||
/// </summary>
|
||||
public bool VerboseLogging
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "VerboseLogging", true); }
|
||||
set { Settings["VerboseLogging"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Have the log panel expanded by default on startup
|
||||
/// </summary>
|
||||
public bool OpenLogWindowAtStartup
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "OpenLogWindowAtStartup", true); }
|
||||
set { Settings["OpenLogWindowAtStartup"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Redump Login Information
|
||||
|
||||
public string? RedumpUsername
|
||||
{
|
||||
get { return GetStringSetting(Settings, "RedumpUsername", ""); }
|
||||
set { Settings["RedumpUsername"] = value; }
|
||||
}
|
||||
|
||||
// TODO: Figure out a way to keep this encrypted in some way, BASE64 to start?
|
||||
public string? RedumpPassword
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetStringSetting(Settings, "RedumpPassword", "");
|
||||
}
|
||||
set { Settings["RedumpPassword"] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if a complete set of Redump credentials might exist
|
||||
/// </summary>
|
||||
public bool HasRedumpLogin { get => !string.IsNullOrEmpty(RedumpUsername) && !string.IsNullOrEmpty(RedumpPassword); }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor taking a dictionary for settings
|
||||
/// </summary>
|
||||
/// <param name="settings"></param>
|
||||
public Options(Dictionary<string, string?>? settings = null)
|
||||
{
|
||||
this.Settings = settings ?? [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor taking an existing Options object
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
public Options(Options? source)
|
||||
{
|
||||
Settings = new Dictionary<string, string?>(source?.Settings ?? []);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accessor for the internal dictionary
|
||||
/// </summary>
|
||||
public string? this[string key]
|
||||
{
|
||||
get => this.Settings[key];
|
||||
set => this.Settings[key] = value;
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Get a Boolean setting from a settings, dictionary
|
||||
/// </summary>
|
||||
/// <param name="settings">Dictionary representing the settings</param>
|
||||
/// <param name="key">Setting key to get a value for</param>
|
||||
/// <param name="defaultValue">Default value to return if no value is found</param>
|
||||
/// <returns>Setting value if possible, default value otherwise</returns>
|
||||
private static bool GetBooleanSetting(Dictionary<string, string?> settings, string key, bool defaultValue)
|
||||
{
|
||||
if (settings.ContainsKey(key))
|
||||
{
|
||||
if (bool.TryParse(settings[key], out bool value))
|
||||
return value;
|
||||
else
|
||||
return defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an Int32 setting from a settings, dictionary
|
||||
/// </summary>
|
||||
/// <param name="settings">Dictionary representing the settings</param>
|
||||
/// <param name="key">Setting key to get a value for</param>
|
||||
/// <param name="defaultValue">Default value to return if no value is found</param>
|
||||
/// <returns>Setting value if possible, default value otherwise</returns>
|
||||
private static int GetInt32Setting(Dictionary<string, string?> settings, string key, int defaultValue)
|
||||
{
|
||||
if (settings.ContainsKey(key))
|
||||
{
|
||||
if (int.TryParse(settings[key], out int value))
|
||||
return value;
|
||||
else
|
||||
return defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a String setting from a settings, dictionary
|
||||
/// </summary>
|
||||
/// <param name="settings">Dictionary representing the settings</param>
|
||||
/// <param name="key">Setting key to get a value for</param>
|
||||
/// <param name="defaultValue">Default value to return if no value is found</param>
|
||||
/// <returns>Setting value if possible, default value otherwise</returns>
|
||||
private static string? GetStringSetting(Dictionary<string, string?> settings, string key, string? defaultValue)
|
||||
{
|
||||
if (settings.ContainsKey(key))
|
||||
return settings[key];
|
||||
else
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
102
MPF.Core/Data/ProcessingQueue.cs
Normal file
102
MPF.Core/Data/ProcessingQueue.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
#if NET20 || NET35
|
||||
using System.Collections.Generic;
|
||||
#else
|
||||
using System.Collections.Concurrent;
|
||||
#endif
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
public sealed class ProcessingQueue<T> : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Internal queue to hold data to process
|
||||
/// </summary>
|
||||
#if NET20 || NET35
|
||||
private readonly Queue<T> InternalQueue;
|
||||
#else
|
||||
private readonly ConcurrentQueue<T> InternalQueue;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Custom processing step for dequeued data
|
||||
/// </summary>
|
||||
private readonly Action<T> CustomProcessing;
|
||||
|
||||
/// <summary>
|
||||
/// Cancellation method for the processing task
|
||||
/// </summary>
|
||||
private readonly CancellationTokenSource TokenSource;
|
||||
|
||||
public ProcessingQueue(Action<T> customProcessing)
|
||||
{
|
||||
#if NET20 || NET35
|
||||
this.InternalQueue = new Queue<T>();
|
||||
#else
|
||||
this.InternalQueue = new ConcurrentQueue<T>();
|
||||
#endif
|
||||
this.CustomProcessing = customProcessing;
|
||||
this.TokenSource = new CancellationTokenSource();
|
||||
#if NET20 || NET35
|
||||
Task.Run(() => ProcessQueue());
|
||||
#elif NET40
|
||||
Task.Factory.StartNew(() => ProcessQueue());
|
||||
#else
|
||||
Task.Run(() => ProcessQueue(), this.TokenSource.Token);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose the current instance
|
||||
/// </summary>
|
||||
public void Dispose() => this.TokenSource.Cancel();
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue a new item for processing
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public void Enqueue(T? item)
|
||||
{
|
||||
// Only accept new data when not cancelled
|
||||
if (item != null && !this.TokenSource.IsCancellationRequested)
|
||||
this.InternalQueue.Enqueue(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process
|
||||
/// </summary>
|
||||
private void ProcessQueue()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Nothing in the queue means we get to idle
|
||||
#if NET20 || NET35
|
||||
if (InternalQueue.Count == 0)
|
||||
#else
|
||||
if (InternalQueue.IsEmpty)
|
||||
#endif
|
||||
{
|
||||
if (this.TokenSource.IsCancellationRequested)
|
||||
break;
|
||||
|
||||
Thread.Sleep(10);
|
||||
continue;
|
||||
}
|
||||
|
||||
#if NET20 || NET35
|
||||
// Get the next item from the queue and invoke the lambda, if possible
|
||||
this.CustomProcessing?.Invoke(this.InternalQueue.Dequeue());
|
||||
#else
|
||||
// Get the next item from the queue
|
||||
if (!this.InternalQueue.TryDequeue(out var nextItem))
|
||||
continue;
|
||||
|
||||
// Invoke the lambda, if possible
|
||||
this.CustomProcessing?.Invoke(nextItem);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
namespace DICUI.Utilities
|
||||
using System;
|
||||
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Generic success/failure result object, with optional message
|
||||
/// </summary>
|
||||
public class Result
|
||||
public class Result : System.EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Internal representation of success
|
||||
@@ -24,39 +26,30 @@
|
||||
/// <summary>
|
||||
/// Create a default success result with no message
|
||||
/// </summary>
|
||||
public static Result Success() => new Result(true, "");
|
||||
public static Result Success() => new(true, "");
|
||||
|
||||
/// <summary>
|
||||
/// Create a success result with a custom message
|
||||
/// </summary>
|
||||
/// <param name="message">String to add as a message</param>
|
||||
public static Result Success(string message) => new Result(true, message);
|
||||
|
||||
/// <summary>
|
||||
/// Create a success result with a custom message with format parameters
|
||||
/// </summary>
|
||||
/// <param name="message">String to add as a message</param>
|
||||
/// <param name="args">Formatting parameters for the string</param>
|
||||
public static Result Success(string message, params object[] args) => new Result(true, string.Format(message, args));
|
||||
public static Result Success(string? message) => new(true, message ?? string.Empty);
|
||||
|
||||
/// <summary>
|
||||
/// Create a default failure result with no message
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Result Failure() => new Result(false, "");
|
||||
public static Result Failure() => new(false, "");
|
||||
|
||||
/// <summary>
|
||||
/// Create a failure result with a custom message
|
||||
/// </summary>
|
||||
/// <param name="message">String to add as a message</param>
|
||||
public static Result Failure(string message) => new Result(false, message);
|
||||
public static Result Failure(string? message) => new(false, message ?? string.Empty);
|
||||
|
||||
/// <summary>
|
||||
/// Create a failure result with a custom message with format parameters
|
||||
/// </summary>
|
||||
/// <param name="message">String to add as a message</param>
|
||||
/// <param name="args">Formatting parameters for the string</param>
|
||||
public static Result Failure(string message, params object[] args) => new Result(false, string.Format(message, args));
|
||||
internal static Result Success(object value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Results can be compared to boolean values based on the success value
|
||||
580
MPF.Core/DumpEnvironment.cs
Normal file
580
MPF.Core/DumpEnvironment.cs
Normal file
@@ -0,0 +1,580 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.Modules;
|
||||
using MPF.Core.Utilities;
|
||||
using SabreTools.RedumpLib;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the state of all settings to be used during dumping
|
||||
/// </summary>
|
||||
public class DumpEnvironment
|
||||
{
|
||||
#region Output paths
|
||||
|
||||
/// <summary>
|
||||
/// Base output file path to write files to
|
||||
/// </summary>
|
||||
public string OutputPath { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI information
|
||||
|
||||
/// <summary>
|
||||
/// Drive object representing the current drive
|
||||
/// </summary>
|
||||
public Drive? Drive { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected system
|
||||
/// </summary>
|
||||
public RedumpSystem? System { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected media type
|
||||
/// </summary>
|
||||
public MediaType? Type { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected dumping program
|
||||
/// </summary>
|
||||
public InternalProgram InternalProgram { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Options object representing user-defined options
|
||||
/// </summary>
|
||||
public Data.Options Options { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Parameters object representing what to send to the internal program
|
||||
/// </summary>
|
||||
public BaseParameters? Parameters { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Generic way of reporting a message
|
||||
/// </summary>
|
||||
#if NET20 || NET35 || NET40
|
||||
public EventHandler<BaseParameters.StringEventArgs>? ReportStatus;
|
||||
#else
|
||||
public EventHandler<string>? ReportStatus;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Queue of items that need to be logged
|
||||
/// </summary>
|
||||
private ProcessingQueue<string>? outputQueue;
|
||||
|
||||
/// <summary>
|
||||
/// Event handler for data returned from a process
|
||||
/// </summary>
|
||||
#if NET20 || NET35 || NET40
|
||||
private void OutputToLog(object? proc, BaseParameters.StringEventArgs args) => outputQueue?.Enqueue(args.Value);
|
||||
#else
|
||||
private void OutputToLog(object? proc, string args) => outputQueue?.Enqueue(args);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Process the outputs in the queue
|
||||
/// </summary>
|
||||
#if NET20 || NET35 || NET40
|
||||
private void ProcessOutputs(string nextOutput) => ReportStatus?.Invoke(this, new BaseParameters.StringEventArgs { Value = nextOutput });
|
||||
#else
|
||||
private void ProcessOutputs(string nextOutput) => ReportStatus?.Invoke(this, nextOutput);
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for a full DumpEnvironment object from user information
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="outputPath"></param>
|
||||
/// <param name="drive"></param>
|
||||
/// <param name="system"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="internalProgram"></param>
|
||||
/// <param name="parameters"></param>
|
||||
public DumpEnvironment(Data.Options options,
|
||||
string outputPath,
|
||||
Drive? drive,
|
||||
RedumpSystem? system,
|
||||
MediaType? type,
|
||||
InternalProgram? internalProgram,
|
||||
string? parameters)
|
||||
{
|
||||
// Set options object
|
||||
Options = options;
|
||||
|
||||
// Output paths
|
||||
OutputPath = InfoTool.NormalizeOutputPaths(outputPath, false);
|
||||
|
||||
// UI information
|
||||
Drive = drive;
|
||||
System = system ?? options.DefaultSystem;
|
||||
Type = type ?? MediaType.NONE;
|
||||
InternalProgram = internalProgram ?? options.InternalProgram;
|
||||
|
||||
// Dumping program
|
||||
SetParameters(parameters);
|
||||
}
|
||||
|
||||
#region Public Functionality
|
||||
|
||||
/// <summary>
|
||||
/// Set the parameters object based on the internal program and parameters string
|
||||
/// </summary>
|
||||
/// <param name="parameters">String representation of the parameters</param>
|
||||
public void SetParameters(string? parameters)
|
||||
{
|
||||
Parameters = InternalProgram switch
|
||||
{
|
||||
// Dumping support
|
||||
InternalProgram.Aaru => new Modules.Aaru.Parameters(parameters) { ExecutablePath = Options.AaruPath },
|
||||
InternalProgram.DiscImageCreator => new Modules.DiscImageCreator.Parameters(parameters) { ExecutablePath = Options.DiscImageCreatorPath },
|
||||
InternalProgram.Redumper => new Modules.Redumper.Parameters(parameters) { ExecutablePath = Options.RedumperPath },
|
||||
|
||||
// Verification support only
|
||||
InternalProgram.CleanRip => new Modules.CleanRip.Parameters(parameters) { ExecutablePath = null },
|
||||
InternalProgram.DCDumper => null, // TODO: Create correct parameter type when supported
|
||||
InternalProgram.PS3CFW => new Modules.PS3CFW.Parameters(parameters) { ExecutablePath = null },
|
||||
InternalProgram.UmdImageCreator => new Modules.UmdImageCreator.Parameters(parameters) { ExecutablePath = null },
|
||||
|
||||
// If no dumping program found, set to null
|
||||
InternalProgram.NONE => null,
|
||||
|
||||
// This should never happen, but it needs a fallback
|
||||
_ => new Modules.Redumper.Parameters(parameters) { ExecutablePath = Options.RedumperPath },
|
||||
};
|
||||
|
||||
// Set system and type
|
||||
if (Parameters != null)
|
||||
{
|
||||
Parameters.System = System;
|
||||
Parameters.Type = Type;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the full parameter string for either DiscImageCreator or Aaru
|
||||
/// </summary>
|
||||
/// <param name="driveSpeed">Nullable int representing the drive speed</param>
|
||||
/// <returns>String representing the params, null on error</returns>
|
||||
public string? GetFullParameters(int? driveSpeed)
|
||||
{
|
||||
// Populate with the correct params for inputs (if we're not on the default option)
|
||||
if (System != null && Type != MediaType.NONE)
|
||||
{
|
||||
// If drive letter is invalid, skip this
|
||||
if (Drive == null)
|
||||
return null;
|
||||
|
||||
// Set the proper parameters
|
||||
Parameters = InternalProgram switch
|
||||
{
|
||||
InternalProgram.Aaru => new Modules.Aaru.Parameters(System, Type, Drive.Name, OutputPath, driveSpeed, Options),
|
||||
InternalProgram.DiscImageCreator => new Modules.DiscImageCreator.Parameters(System, Type, Drive.Name, OutputPath, driveSpeed, Options),
|
||||
InternalProgram.Redumper => new Modules.Redumper.Parameters(System, Type, Drive.Name, OutputPath, driveSpeed, Options),
|
||||
|
||||
// If no dumping program found, set to null
|
||||
InternalProgram.NONE => null,
|
||||
|
||||
// This should never happen, but it needs a fallback
|
||||
_ => new Modules.Redumper.Parameters(System, Type, Drive.Name, OutputPath, driveSpeed, Options),
|
||||
};
|
||||
|
||||
// Generate and return the param string
|
||||
return Parameters?.GenerateParameters();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dumping
|
||||
|
||||
/// <summary>
|
||||
/// Cancel an in-progress dumping process
|
||||
/// </summary>
|
||||
public void CancelDumping() => Parameters?.KillInternalProgram();
|
||||
|
||||
/// <summary>
|
||||
/// Eject the disc using DiscImageCreator
|
||||
/// </summary>
|
||||
public async Task<string?> EjectDisc() =>
|
||||
await RunStandaloneDiscImageCreatorCommand(Modules.DiscImageCreator.CommandStrings.Eject);
|
||||
|
||||
/// <summary>
|
||||
/// Reset the current drive using DiscImageCreator
|
||||
/// </summary>
|
||||
public async Task<string?> ResetDrive() =>
|
||||
await RunStandaloneDiscImageCreatorCommand(Modules.DiscImageCreator.CommandStrings.Reset);
|
||||
|
||||
/// <summary>
|
||||
/// Execute the initial invocation of the dumping programs
|
||||
/// </summary>
|
||||
/// <param name="progress">Optional result progress callback</param>
|
||||
#if NET40
|
||||
public Result Run(IProgress<Result>? progress = null)
|
||||
#else
|
||||
public async Task<Result> Run(IProgress<Result>? progress = null)
|
||||
#endif
|
||||
{
|
||||
// If we don't have parameters
|
||||
if (Parameters == null)
|
||||
return Result.Failure("Error! Current configuration is not supported!");
|
||||
|
||||
// Check that we have the basics for dumping
|
||||
Result result = IsValidForDump();
|
||||
if (!result)
|
||||
return result;
|
||||
|
||||
// Invoke output processing, if needed
|
||||
if (!Options.ToolsInSeparateWindow)
|
||||
{
|
||||
outputQueue = new ProcessingQueue<string>(ProcessOutputs);
|
||||
if (Parameters.ReportStatus != null)
|
||||
Parameters.ReportStatus += OutputToLog;
|
||||
}
|
||||
|
||||
// Execute internal tool
|
||||
progress?.Report(Result.Success($"Executing {InternalProgram}... {(Options.ToolsInSeparateWindow ? "please wait!" : "see log for output!")}"));
|
||||
|
||||
var directoryName = Path.GetDirectoryName(OutputPath);
|
||||
if (!string.IsNullOrEmpty(directoryName))
|
||||
Directory.CreateDirectory(directoryName);
|
||||
|
||||
#if NET40
|
||||
var executeTask = Task.Factory.StartNew(() => Parameters.ExecuteInternalProgram(Options.ToolsInSeparateWindow));
|
||||
executeTask.Wait();
|
||||
#else
|
||||
await Task.Run(() => Parameters.ExecuteInternalProgram(Options.ToolsInSeparateWindow));
|
||||
#endif
|
||||
progress?.Report(Result.Success($"{InternalProgram} has finished!"));
|
||||
|
||||
// Remove event handler if needed
|
||||
if (!Options.ToolsInSeparateWindow)
|
||||
{
|
||||
outputQueue?.Dispose();
|
||||
Parameters.ReportStatus -= OutputToLog;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that the current environment has a complete dump and create submission info is possible
|
||||
/// </summary>
|
||||
/// <param name="resultProgress">Optional result progress callback</param>
|
||||
/// <param name="protectionProgress">Optional protection progress callback</param>
|
||||
/// <param name="processUserInfo">Optional user prompt to deal with submission information</param>
|
||||
/// <param name="seedInfo">A seed SubmissionInfo object that contains user data</param>
|
||||
/// <returns>Result instance with the outcome</returns>
|
||||
public async Task<Result> VerifyAndSaveDumpOutput(
|
||||
IProgress<Result>? resultProgress = null,
|
||||
IProgress<BinaryObjectScanner.ProtectionProgress>? protectionProgress = null,
|
||||
Func<SubmissionInfo?, (bool?, SubmissionInfo?)>? processUserInfo = null,
|
||||
SubmissionInfo? seedInfo = null)
|
||||
{
|
||||
if (Parameters == null)
|
||||
return Result.Failure("Error! Current configuration is not supported!");
|
||||
|
||||
resultProgress?.Report(Result.Success("Gathering submission information... please wait!"));
|
||||
|
||||
// Get the output directory and filename separately
|
||||
var outputDirectory = Path.GetDirectoryName(OutputPath);
|
||||
var outputFilename = Path.GetFileName(OutputPath);
|
||||
|
||||
// Check to make sure that the output had all the correct files
|
||||
(bool foundFiles, List<string> missingFiles) = Parameters.FoundAllFiles(outputDirectory, outputFilename, false);
|
||||
if (!foundFiles)
|
||||
{
|
||||
resultProgress?.Report(Result.Failure($"There were files missing from the output:\n{string.Join("\n", [.. missingFiles])}"));
|
||||
return Result.Failure("Error! Please check output directory as dump may be incomplete!");
|
||||
}
|
||||
|
||||
// Extract the information from the output files
|
||||
resultProgress?.Report(Result.Success("Extracting output information from output files..."));
|
||||
var submissionInfo = await SubmissionInfoTool.ExtractOutputInformation(
|
||||
OutputPath,
|
||||
Drive,
|
||||
System,
|
||||
Type,
|
||||
Options,
|
||||
Parameters,
|
||||
resultProgress,
|
||||
protectionProgress);
|
||||
resultProgress?.Report(Result.Success("Extracting information complete!"));
|
||||
|
||||
// Inject seed submission info data, if necessary
|
||||
if (seedInfo != null)
|
||||
{
|
||||
resultProgress?.Report(Result.Success("Injecting user-supplied information..."));
|
||||
Builder.InjectSubmissionInformation(submissionInfo, seedInfo);
|
||||
resultProgress?.Report(Result.Success("Information injection complete!"));
|
||||
}
|
||||
|
||||
// Eject the disc automatically if configured to
|
||||
if (Options.EjectAfterDump == true)
|
||||
{
|
||||
resultProgress?.Report(Result.Success($"Ejecting disc in drive {Drive?.Name}"));
|
||||
await EjectDisc();
|
||||
}
|
||||
|
||||
// Reset the drive automatically if configured to
|
||||
if (InternalProgram == InternalProgram.DiscImageCreator && Options.DICResetDriveAfterDump)
|
||||
{
|
||||
resultProgress?.Report(Result.Success($"Resetting drive {Drive?.Name}"));
|
||||
await ResetDrive();
|
||||
}
|
||||
|
||||
// Get user-modifiable information if confugured to
|
||||
if (Options.PromptForDiscInformation && processUserInfo != null)
|
||||
{
|
||||
resultProgress?.Report(Result.Success("Waiting for additional disc information..."));
|
||||
|
||||
bool? filledInfo;
|
||||
(filledInfo, submissionInfo) = processUserInfo(submissionInfo);
|
||||
|
||||
if (filledInfo == true)
|
||||
resultProgress?.Report(Result.Success("Additional disc information added!"));
|
||||
else
|
||||
resultProgress?.Report(Result.Success("Disc information skipped!"));
|
||||
}
|
||||
|
||||
// Process special fields for site codes
|
||||
resultProgress?.Report(Result.Success("Processing site codes..."));
|
||||
Formatter.ProcessSpecialFields(submissionInfo);
|
||||
resultProgress?.Report(Result.Success("Processing complete!"));
|
||||
|
||||
// Format the information for the text output
|
||||
resultProgress?.Report(Result.Success("Formatting information..."));
|
||||
(var formattedValues, var formatResult) = Formatter.FormatOutputData(submissionInfo, Options.EnableRedumpCompatibility);
|
||||
if (formattedValues == null)
|
||||
resultProgress?.Report(Result.Failure(formatResult));
|
||||
else
|
||||
resultProgress?.Report(Result.Success(formatResult));
|
||||
|
||||
// Get the filename suffix for auto-generated files
|
||||
var filenameSuffix = Options.AddFilenameSuffix ? Path.GetFileNameWithoutExtension(outputFilename) : null;
|
||||
|
||||
// Write the text output
|
||||
resultProgress?.Report(Result.Success("Writing information to !submissionInfo.txt..."));
|
||||
(bool txtSuccess, string txtResult) = InfoTool.WriteOutputData(outputDirectory, filenameSuffix, formattedValues);
|
||||
if (txtSuccess)
|
||||
resultProgress?.Report(Result.Success(txtResult));
|
||||
else
|
||||
resultProgress?.Report(Result.Failure(txtResult));
|
||||
|
||||
// Write the copy protection output
|
||||
if (submissionInfo?.CopyProtection?.FullProtections != null && submissionInfo.CopyProtection.FullProtections.Any())
|
||||
{
|
||||
if (Options.ScanForProtection && Options.OutputSeparateProtectionFile)
|
||||
{
|
||||
resultProgress?.Report(Result.Success("Writing protection to !protectionInfo.txt..."));
|
||||
bool scanSuccess = InfoTool.WriteProtectionData(outputDirectory, filenameSuffix, submissionInfo, Options.HideDriveLetters);
|
||||
if (scanSuccess)
|
||||
resultProgress?.Report(Result.Success("Writing complete!"));
|
||||
else
|
||||
resultProgress?.Report(Result.Failure("Writing could not complete!"));
|
||||
}
|
||||
}
|
||||
|
||||
// Write the JSON output, if required
|
||||
if (Options.OutputSubmissionJSON)
|
||||
{
|
||||
resultProgress?.Report(Result.Success($"Writing information to !submissionInfo.json{(Options.IncludeArtifacts ? ".gz" : string.Empty)}..."));
|
||||
bool jsonSuccess = InfoTool.WriteOutputData(outputDirectory, filenameSuffix, submissionInfo, Options.IncludeArtifacts);
|
||||
if (jsonSuccess)
|
||||
resultProgress?.Report(Result.Success("Writing complete!"));
|
||||
else
|
||||
resultProgress?.Report(Result.Failure("Writing could not complete!"));
|
||||
}
|
||||
|
||||
// Compress the logs, if required
|
||||
if (Options.CompressLogFiles)
|
||||
{
|
||||
resultProgress?.Report(Result.Success("Compressing log files..."));
|
||||
(bool compressSuccess, string compressResult) = InfoTool.CompressLogFiles(outputDirectory, filenameSuffix, outputFilename, Parameters);
|
||||
if (compressSuccess)
|
||||
resultProgress?.Report(Result.Success(compressResult));
|
||||
else
|
||||
resultProgress?.Report(Result.Failure(compressResult));
|
||||
}
|
||||
|
||||
// Delete unnecessary files, if required
|
||||
if (Options.DeleteUnnecessaryFiles)
|
||||
{
|
||||
resultProgress?.Report(Result.Success("Deleting unnecessary files..."));
|
||||
(bool deleteSuccess, string deleteResult) = InfoTool.DeleteUnnecessaryFiles(outputDirectory, outputFilename, Parameters);
|
||||
if (deleteSuccess)
|
||||
resultProgress?.Report(Result.Success(deleteResult));
|
||||
else
|
||||
resultProgress?.Report(Result.Failure(deleteResult));
|
||||
}
|
||||
|
||||
// Create PS3 IRD, if required
|
||||
if (Options.CreateIRDAfterDumping && System == RedumpSystem.SonyPlayStation3 && Type == MediaType.BluRay)
|
||||
{
|
||||
resultProgress?.Report(Result.Success("Creating IRD... please wait!"));
|
||||
(bool deleteSuccess, string deleteResult) = await InfoTool.WriteIRD(OutputPath, submissionInfo?.Extras?.DiscKey, submissionInfo?.Extras?.DiscID, submissionInfo?.Extras?.PIC, submissionInfo?.SizeAndChecksums?.Layerbreak, submissionInfo?.SizeAndChecksums?.CRC32);
|
||||
if (deleteSuccess)
|
||||
resultProgress?.Report(Result.Success(deleteResult));
|
||||
else
|
||||
resultProgress?.Report(Result.Failure(deleteResult));
|
||||
}
|
||||
|
||||
resultProgress?.Report(Result.Success("Submission information process complete!"));
|
||||
return Result.Success();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the parameters are valid
|
||||
/// </summary>
|
||||
/// <returns>True if the configuration is valid, false otherwise</returns>
|
||||
internal bool ParametersValid()
|
||||
{
|
||||
// Missing drive means it can never be valid
|
||||
if (Drive == null)
|
||||
return false;
|
||||
|
||||
bool parametersValid = Parameters?.IsValid() ?? false;
|
||||
bool floppyValid = !(Drive.InternalDriveType == InternalDriveType.Floppy ^ Type == MediaType.FloppyDisk);
|
||||
|
||||
// TODO: HardDisk being in the Removable category is a hack, fix this later
|
||||
bool removableDiskValid = !((Drive.InternalDriveType == InternalDriveType.Removable || Drive.InternalDriveType == InternalDriveType.HardDisk)
|
||||
^ (Type == MediaType.CompactFlash || Type == MediaType.SDCard || Type == MediaType.FlashDrive || Type == MediaType.HardDisk));
|
||||
|
||||
return parametersValid && floppyValid && removableDiskValid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run internal program async with an input set of parameters
|
||||
/// </summary>
|
||||
/// <param name="parameters"></param>
|
||||
/// <returns>Standard output from commandline window</returns>
|
||||
private static async Task<string> ExecuteInternalProgram(BaseParameters parameters)
|
||||
{
|
||||
Process childProcess;
|
||||
#if NET40
|
||||
string output = await Task.Factory.StartNew(() =>
|
||||
#else
|
||||
string output = await Task.Run(() =>
|
||||
#endif
|
||||
{
|
||||
childProcess = new Process()
|
||||
{
|
||||
StartInfo = new ProcessStartInfo()
|
||||
{
|
||||
FileName = parameters.ExecutablePath!,
|
||||
Arguments = parameters.GenerateParameters()!,
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true,
|
||||
},
|
||||
};
|
||||
childProcess.Start();
|
||||
childProcess.WaitForExit(1000);
|
||||
|
||||
// Just in case, we want to push a button 5 times to clear any errors
|
||||
for (int i = 0; i < 5; i++)
|
||||
childProcess.StandardInput.WriteLine("Y");
|
||||
|
||||
string stdout = childProcess.StandardOutput.ReadToEnd();
|
||||
childProcess.Dispose();
|
||||
return stdout;
|
||||
});
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate the current environment is ready for a dump
|
||||
/// </summary>
|
||||
/// <returns>Result instance with the outcome</returns>
|
||||
private Result IsValidForDump()
|
||||
{
|
||||
// Validate that everything is good
|
||||
if (Parameters == null || !ParametersValid())
|
||||
return Result.Failure("Error! Current configuration is not supported!");
|
||||
|
||||
// Fix the output paths, just in case
|
||||
OutputPath = InfoTool.NormalizeOutputPaths(OutputPath, false);
|
||||
|
||||
// Validate that the output path isn't on the dumping drive
|
||||
if (Drive?.Name != null && OutputPath.StartsWith(Drive.Name))
|
||||
return Result.Failure("Error! Cannot output to same drive that is being dumped!");
|
||||
|
||||
// Validate that the required program exists
|
||||
if (!File.Exists(Parameters.ExecutablePath))
|
||||
return Result.Failure($"Error! {Parameters.ExecutablePath} does not exist!");
|
||||
|
||||
// Validate that the dumping drive doesn't contain the executable
|
||||
string fullExecutablePath = Path.GetFullPath(Parameters.ExecutablePath!);
|
||||
if (Drive?.Name != null && fullExecutablePath.StartsWith(Drive.Name))
|
||||
return Result.Failure("Error! Cannot dump same drive that executable resides on!");
|
||||
|
||||
// Validate that the current configuration is supported
|
||||
return Tools.GetSupportStatus(System, Type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate that DIscImageCreator is able to be found
|
||||
/// </summary>
|
||||
/// <returns>True if DiscImageCreator is found properly, false otherwise</returns>
|
||||
private bool RequiredProgramsExist()
|
||||
{
|
||||
// Validate that the path is configured
|
||||
if (string.IsNullOrEmpty(Options.DiscImageCreatorPath))
|
||||
return false;
|
||||
|
||||
// Validate that the required program exists
|
||||
if (!File.Exists(Options.DiscImageCreatorPath))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run a standalone DiscImageCreator command
|
||||
/// </summary>
|
||||
/// <param name="command">Command string to run</param>
|
||||
/// <returns>The output of the command on success, null on error</returns>
|
||||
private async Task<string?> RunStandaloneDiscImageCreatorCommand(string command)
|
||||
{
|
||||
// Validate that DiscImageCreator is all set
|
||||
if (!RequiredProgramsExist())
|
||||
return null;
|
||||
|
||||
// Validate we're not trying to eject a non-optical
|
||||
if (Drive == null || Drive.InternalDriveType != InternalDriveType.Optical)
|
||||
return null;
|
||||
|
||||
CancelDumping();
|
||||
|
||||
var parameters = new Modules.DiscImageCreator.Parameters(string.Empty)
|
||||
{
|
||||
BaseCommand = command,
|
||||
DrivePath = Drive.Name,
|
||||
ExecutablePath = Options.DiscImageCreatorPath,
|
||||
};
|
||||
|
||||
return await ExecuteInternalProgram(parameters);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
2015
MPF.Core/InfoTool.cs
Normal file
2015
MPF.Core/InfoTool.cs
Normal file
File diff suppressed because it is too large
Load Diff
63
MPF.Core/MPF.Core.csproj
Normal file
63
MPF.Core/MPF.Core.csproj
Normal file
@@ -0,0 +1,63 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<VersionPrefix>3.1.3</VersionPrefix>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
<Description>Common code for all MPF implementations</Description>
|
||||
<Copyright>Copyright (c) Matt Nadareski 2019-2024</Copyright>
|
||||
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="MPF.Test" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Support for old .NET versions -->
|
||||
<ItemGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net40`))">
|
||||
<PackageReference Include="MinAsyncBridge" Version="0.12.4" />
|
||||
<PackageReference Include="MinTasksExtensionsBridge" Version="0.3.4" />
|
||||
<PackageReference Include="MinThreadingBridge" Version="0.11.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`))">
|
||||
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="$(TargetFramework.StartsWith(`net4`)) AND !$(TargetFramework.StartsWith(`net40`))">
|
||||
<PackageReference Include="IndexRange" Version="1.0.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="$(TargetFramework.StartsWith(`net452`))">
|
||||
<PackageReference Include="Microsoft.Net.Http" Version="2.2.29" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))">
|
||||
<PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" />
|
||||
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
|
||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BinaryObjectScanner" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="3.1.1" GeneratePathProperty="true">
|
||||
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="LibIRD" Version="0.9.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="psxt001z.Library" Version="0.21.0-beta4" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="1.1.4" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.4.0" />
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="1.3.6" />
|
||||
<PackageReference Include="SabreTools.Serialization" Version="1.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
491
MPF.Core/Modules/Aaru/Constants.cs
Normal file
491
MPF.Core/Modules/Aaru/Constants.cs
Normal file
@@ -0,0 +1,491 @@
|
||||
namespace MPF.Core.Modules.Aaru
|
||||
{
|
||||
/// <summary>
|
||||
/// Top-level commands for Aaru
|
||||
/// </summary>
|
||||
public static class CommandStrings
|
||||
{
|
||||
public const string NONE = "";
|
||||
|
||||
// Archive Family
|
||||
public const string ArchivePrefixShort = "arc";
|
||||
public const string ArchivePrefixLong = "archive";
|
||||
public const string ArchiveInfo = "info";
|
||||
|
||||
// Database Family
|
||||
public const string DatabasePrefixShort = "db";
|
||||
public const string DatabasePrefixLong = "database";
|
||||
public const string DatabaseStats = "stats";
|
||||
public const string DatabaseUpdate = "update";
|
||||
|
||||
// Device Family
|
||||
public const string DevicePrefixShort = "dev";
|
||||
public const string DevicePrefixLong = "device";
|
||||
public const string DeviceInfo = "info";
|
||||
public const string DeviceList = "list";
|
||||
public const string DeviceReport = "report";
|
||||
|
||||
// Filesystem Family
|
||||
public const string FilesystemPrefixShort = "fi";
|
||||
public const string FilesystemPrefixShortAlt = "fs";
|
||||
public const string FilesystemPrefixLong = "filesystem";
|
||||
public const string FilesystemExtract = "extract";
|
||||
public const string FilesystemInfo = "info";
|
||||
public const string FilesystemListShort = "ls";
|
||||
public const string FilesystemListLong = "list";
|
||||
public const string FilesystemOptions = "options";
|
||||
|
||||
// Image Family
|
||||
public const string ImagePrefixShort = "i";
|
||||
public const string ImagePrefixLong = "image";
|
||||
public const string ImageChecksumShort = "chk";
|
||||
public const string ImageChecksumLong = "checksum";
|
||||
public const string ImageCompareShort = "cmp";
|
||||
public const string ImageCompareLong = "compare";
|
||||
public const string ImageConvert = "convert";
|
||||
public const string ImageCreateSidecar = "create-sidecar";
|
||||
public const string ImageDecode = "decode";
|
||||
public const string ImageEntropy = "entropy";
|
||||
public const string ImageInfo = "info";
|
||||
public const string ImageOptions = "options";
|
||||
public const string ImagePrint = "print";
|
||||
public const string ImageVerify = "verify";
|
||||
|
||||
// Media Family
|
||||
public const string MediaPrefixShort = "m";
|
||||
public const string MediaPrefixLong = "media";
|
||||
public const string MediaDump = "dump";
|
||||
public const string MediaInfo = "info";
|
||||
public const string MediaScan = "scan";
|
||||
|
||||
// Standalone Commands
|
||||
public const string Configure = "configure";
|
||||
public const string Formats = "formats";
|
||||
public const string ListEncodings = "list-encodings";
|
||||
public const string ListNamespaces = "list-namespaces";
|
||||
public const string Remote = "remote";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supported encodings for Aaru
|
||||
/// </summary>
|
||||
/// TODO: Use to verify encoding settings
|
||||
public static class EncodingStrings
|
||||
{
|
||||
public const string ArabicMac = "x-mac-arabic";
|
||||
public const string AtariASCII = "atascii";
|
||||
public const string CentralEuropeanMac = "x-mac-ce";
|
||||
public const string CommodorePETSCII = "petscii";
|
||||
public const string CroatianMac = "x-mac-croatian";
|
||||
public const string CyrillicMac = "x-mac-cryillic";
|
||||
public const string FarsiMac = "x-mac-farsi";
|
||||
public const string GreekMac = "x-mac-greek";
|
||||
public const string HebrewMac = "x-mac-hebrew";
|
||||
public const string RomanianMac = "x-mac-romanian";
|
||||
public const string SinclairZXSpectrum = "spectrum";
|
||||
public const string SinclairZX80 = "zx80";
|
||||
public const string SinclairZX81 = "zx81";
|
||||
public const string TurkishMac = "x-mac-turkish";
|
||||
public const string UkrainianMac = "x-mac-ukrainian";
|
||||
public const string Unicode = "utf-16";
|
||||
public const string UnicodeBigEndian = "utf-16BE";
|
||||
public const string UnicodeUTF32BigEndian = "utf-32BE";
|
||||
public const string UnicodeUTF32 = "utf-32";
|
||||
public const string UnicodeUTF7 = "utf-7";
|
||||
public const string UnicodeUTF8 = "utf-8";
|
||||
public const string USASCII = "us-ascii";
|
||||
public const string WesternEuropeanAppleII = "apple2";
|
||||
public const string WesternEuropeanAppleIIc = "apple2c";
|
||||
public const string WesternEuropeanAppleIIe = "apple2e";
|
||||
public const string WesternEuropeanAppleIIgs = "apple2gs";
|
||||
public const string WesternEuropeanAppleLisa = "lisa";
|
||||
public const string WesternEuropeanAtariST = "atarist";
|
||||
public const string WesternEuropeanGEM = "gem";
|
||||
public const string WesternEuropeanGEOS = "geos";
|
||||
public const string WesternEuropeanISO = "iso-8859-1";
|
||||
public const string WesternEuropeanMac = "macintosh";
|
||||
public const string WesternEuropeanRadix50 = "radix50";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dumping flags for Aaru
|
||||
/// </summary>
|
||||
public static class FlagStrings
|
||||
{
|
||||
// Boolean flags
|
||||
public const string Adler32Short = "-a";
|
||||
public const string Adler32Long = "--adler32";
|
||||
public const string ClearLong = "--clear";
|
||||
public const string ClearAllLong = "--clear-all";
|
||||
public const string CRC16Long = "--crc16";
|
||||
public const string CRC32Short = "-c";
|
||||
public const string CRC32Long = "--crc32";
|
||||
public const string CRC64Long = "--crc64";
|
||||
public const string DebugShort = "-d";
|
||||
public const string DebugLong = "--debug";
|
||||
public const string DiskTagsShort = "-f";
|
||||
public const string DiskTagsLong = "--disk-tags";
|
||||
public const string DuplicatedSectorsShort = "-p";
|
||||
public const string DuplicatedSectorsLong = "--duplicated-sectors";
|
||||
public const string EjectLong = "--eject";
|
||||
public const string ExtendedAttributesShort = "-x";
|
||||
public const string ExtendedAttributesLong = "--xattrs";
|
||||
public const string FilesystemsShort = "-f";
|
||||
public const string FilesystemsLong = "--filesystems";
|
||||
public const string FirstPregapLong = "--first-pregap";
|
||||
public const string FixOffsetLong = "--fix-offset";
|
||||
public const string FixSubchannelLong = "--fix-subchannel";
|
||||
public const string FixSubchannelCrcLong = "--fix-subchannel-crc";
|
||||
public const string FixSubchannelPositionLong = "--fix-subchannel-position";
|
||||
public const string Fletcher16Long = "--fletcher16";
|
||||
public const string Fletcher32Long = "--fletcher32";
|
||||
public const string ForceShort = "-f";
|
||||
public const string ForceLong = "--force";
|
||||
public const string GenerateSubchannelsLong = "--generate-subchannels";
|
||||
public const string HelpShort = "-h";
|
||||
public const string HelpShortAlt = "-?";
|
||||
public const string HelpLong = "--help";
|
||||
public const string LongFormatShort = "-l";
|
||||
public const string LongFormatLong = "--long-format";
|
||||
public const string LongSectorsShort = "-r";
|
||||
public const string LongSectorsLong = "--long-sectors";
|
||||
public const string MD5Short = "-m";
|
||||
public const string MD5Long = "--md5";
|
||||
public const string MetadataLong = "--metadata";
|
||||
public const string PartitionsShort = "-p";
|
||||
public const string PartitionsLong = "--partitions";
|
||||
public const string PauseLong = "--pause";
|
||||
public const string PersistentLong = "--persistent";
|
||||
public const string PrivateLong = "--private";
|
||||
public const string ResumeShort = "-r";
|
||||
public const string ResumeLong = "--resume";
|
||||
public const string RetrySubchannelLong = "--retry-subchannel";
|
||||
public const string SectorTagsShort = "-p";
|
||||
public const string SectorTagsLong = "--sector-tags";
|
||||
public const string SeparatedTracksShort = "-t";
|
||||
public const string SeparatedTracksLong = "--separated-tracks";
|
||||
public const string SHA1Short = "-s";
|
||||
public const string SHA1Long = "--sha1";
|
||||
public const string SHA256Long = "--sha256";
|
||||
public const string SHA384Long = "--sha384";
|
||||
public const string SHA512Long = "--sha512";
|
||||
public const string SkipCdiReadyHoleLong = "--skip-cdiready-hole";
|
||||
public const string SpamSumShort = "-f";
|
||||
public const string SpamSumLong = "--spamsum";
|
||||
public const string StopOnErrorShort = "-s";
|
||||
public const string StopOnErrorLong = "--stop-on-error";
|
||||
public const string StoreEncryptedLong = "--store-encrypted";
|
||||
public const string TapeShort = "-t";
|
||||
public const string TapeLong = "--tape";
|
||||
public const string TitleKeysLong = "--title-keys";
|
||||
public const string TrapDiscShort = "-t";
|
||||
public const string TrapDiscLong = "--trap-disc";
|
||||
public const string TrimLong = "--trim";
|
||||
public const string UseBufferedReadsLong = "--use-buffered-reads";
|
||||
public const string VerboseShort = "-v";
|
||||
public const string VerboseLong = "--verbose";
|
||||
public const string VerifyDiscShort = "-w";
|
||||
public const string VerifyDiscLong = "--verify-disc";
|
||||
public const string VerifySectorsShort = "-s";
|
||||
public const string VerifySectorsLong = "--verify-sectors";
|
||||
public const string VersionLong = "--version";
|
||||
public const string WholeDiscShort = "-w";
|
||||
public const string WholeDiscLong = "--whole-disc";
|
||||
|
||||
// Int8 flags
|
||||
public const string SpeedLong = "--speed";
|
||||
|
||||
// Int16 flags
|
||||
public const string RetryPassesShort = "-p";
|
||||
public const string RetryPassesLong = "--retry-passes";
|
||||
public const string WidthShort = "-w";
|
||||
public const string WidthLong = "--width";
|
||||
|
||||
// Int32 flags
|
||||
public const string BlockSizeShort = "-b";
|
||||
public const string BlockSizeLong = "--block-size";
|
||||
public const string CountShort = "-c";
|
||||
public const string CountLong = "--count";
|
||||
public const string MaxBlocksLong = "--max-blocks";
|
||||
public const string MediaLastSequenceLong = "--media-lastsequence";
|
||||
public const string MediaSequenceLong = "--media-sequence";
|
||||
public const string SkipShort = "-k";
|
||||
public const string SkipLong = "--skip";
|
||||
|
||||
// Int64 flags
|
||||
public const string LengthShort = "-l"; // or "all"
|
||||
public const string LengthLong = "--length"; // or "all"
|
||||
public const string StartShort = "-s";
|
||||
public const string StartLong = "--start";
|
||||
|
||||
// String flags
|
||||
public const string CommentsLong = "--comments";
|
||||
public const string CreatorLong = "--creator";
|
||||
public const string DriveManufacturerLong = "--drive-manufacturer";
|
||||
public const string DriveModelLong = "--drive-model";
|
||||
public const string DriveRevisionLong = "--drive-revision";
|
||||
public const string DriveSerialLong = "--drive-serial";
|
||||
public const string EncodingShort = "-e";
|
||||
public const string EncodingLong = "--encoding";
|
||||
public const string FormatConvertShort = "-p";
|
||||
public const string FormatConvertLong = "--format";
|
||||
public const string FormatDumpShort = "-t";
|
||||
public const string FormatDumpLong = "--format";
|
||||
public const string GeometryShort = "-g";
|
||||
public const string GeometryLong = "--geometry";
|
||||
public const string ImgBurnLogShort = "-b";
|
||||
public const string ImgBurnLogLong = "--ibg-log";
|
||||
public const string MediaBarcodeLong = "--media-barcode";
|
||||
public const string MediaManufacturerLong = "--media-manufacturer";
|
||||
public const string MediaModelLong = "--media-model";
|
||||
public const string MediaPartNumberLong = "--media-partnumber";
|
||||
public const string MediaSerialLong = "--media-serial";
|
||||
public const string MediaTitleLong = "--media-title";
|
||||
public const string MHDDLogShort = "-m";
|
||||
public const string MHDDLogLong = "--mhdd-log";
|
||||
public const string NamespaceShort = "-n";
|
||||
public const string NamespaceLong = "--namespace";
|
||||
public const string OptionsShort = "-O";
|
||||
public const string OptionsLong = "--options";
|
||||
public const string OutputPrefixShort = "-w";
|
||||
public const string OutputPrefixLong = "--output-prefix";
|
||||
public const string ResumeFileShort = "-r";
|
||||
public const string ResumeFileLong = "--resume-file";
|
||||
public const string SubchannelLong = "--subchannel";
|
||||
public const string XMLSidecarShort = "-x";
|
||||
public const string XMLSidecarLong = "--cicm-xml";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supported formats for Aaru
|
||||
/// </summary>
|
||||
/// TODO: Use to verify format settings
|
||||
public static class FormatStrings
|
||||
{
|
||||
// Supported filters
|
||||
public const string AppleDouble = "AppleDouble";
|
||||
public const string AppleSingle = "AppleSingle";
|
||||
public const string BZip2 = "BZip2";
|
||||
public const string GZip = "GZip";
|
||||
public const string LZip = "LZip";
|
||||
public const string MacBinary = "MacBinary";
|
||||
public const string NoFilter = "No filter";
|
||||
public const string PCExchange = "PCExchange";
|
||||
public const string XZ = "XZ";
|
||||
|
||||
// Read-only media image formats
|
||||
public const string AppleDiskArchivalRetrievalTool = "Apple Disk Archival/Retrieval Tool";
|
||||
public const string AppleNewDiskImageFormat = "Apple New Disk Image Format";
|
||||
public const string AppleNIB = "Apple NIB";
|
||||
public const string BlindWrite4 = "BlindWrite 4";
|
||||
public const string BlindWrite5 = "BlindWrite 5";
|
||||
public const string CPCEMUDiskFileAndExtendedCPCDiskFile = "CPCEMU Disk-File and Extended CPC Disk-File";
|
||||
public const string D2FDiskImage = "d2f disk image";
|
||||
public const string D88DiskImage = "D88 Disk Image";
|
||||
public const string DIMDiskImage = "DIM Disk Image";
|
||||
public const string DiscFerret = "DiscFerret";
|
||||
public const string DiscJuggler = "DiscJuggler";
|
||||
public const string DreamcastGDIImage = "Dreamcast GDI image";
|
||||
public const string DunfieldsIMD = "Dunfield's IMD";
|
||||
public const string HDCopyDiskImage = "HD-Copy disk image";
|
||||
public const string KryoFluxSTREAM = "KryoFlux STREAM";
|
||||
public const string MAMECompressedHunksOfData = "MAME Compressed Hunks of Data";
|
||||
public const string MicrosoftVHDX = "Microsoft VHDX";
|
||||
public const string NeroBurningROMImage = "Nero Burning ROM image";
|
||||
public const string PartCloneDiskImage = "PartClone disk image";
|
||||
public const string PartimageDiskImage = "Partimage disk image";
|
||||
public const string SpectrumFloppyDiskImage = "Spectrum Floppy Disk Image";
|
||||
public const string SuperCardPro = "SuperCardPro";
|
||||
public const string SydexCopyQM = "Sydex CopyQM";
|
||||
public const string SydexTeleDisk = "Sydex TeleDisk";
|
||||
|
||||
// Read/write media image formats
|
||||
public const string AaruFormat = "Aaru Format";
|
||||
public const string ACTApricotDiskImage = "ACT Apricot Disk Image";
|
||||
public const string Alcohol120MediaDescriptorStructure = "Alcohol 120% Media Descriptor Structure";
|
||||
public const string Anex86DiskImage = "Anex86 Disk Image";
|
||||
public const string Apple2InterleavedDiskImage = "Apple ][Interleaved Disk Image";
|
||||
public const string Apple2IMG = "Apple 2IMG";
|
||||
public const string AppleDiskCopy42 = "Apple DiskCopy 4.2";
|
||||
public const string AppleUniversalDiskImageFormat = "Apple Universal Disk Image Format";
|
||||
public const string BasicLisaUtility = "Basic Lisa Utility";
|
||||
public const string CDRDAOTocfile = "CDRDAO tocfile";
|
||||
public const string CDRWinCuesheet = "CDRWin cuesheet";
|
||||
public const string CisCopyDiskImageDCFile = "CisCopy Disk Image(DC-File)";
|
||||
public const string CloneCD = "CloneCD";
|
||||
public const string CopyTape = "CopyTape";
|
||||
public const string DigitalResearchDiskCopy = "Digital Research DiskCopy";
|
||||
public const string IBMSaveDskF = "IBM SaveDskF";
|
||||
public const string MAXIDiskImage = "MAXI Disk image";
|
||||
public const string ParallelsDiskImage = "Parallels disk image";
|
||||
public const string QEMUCopyOnWriteDiskImage = "QEMU Copy-On-Write disk image";
|
||||
public const string QEMUCopyOnWriteDiskImageV2 = "QEMU Copy-On-Write disk image v2";
|
||||
public const string QEMUEnhancedDiskImage = "QEMU Enhanced Disk image";
|
||||
public const string RawDiskImage = "Raw Disk Image";
|
||||
public const string RayAracheliansDiskIMage = "Ray Arachelian's Disk IMage";
|
||||
public const string RSIDEHardDiskImage = "RS-IDE Hard Disk Image";
|
||||
public const string T98HardDiskImage = "T98 Hard Disk Image";
|
||||
public const string T98NextNHDr0DiskImage = "T98-Next NHD r0 Disk Image";
|
||||
public const string Virtual98DiskImage = "Virtual98 Disk Image";
|
||||
public const string VirtualBoxDiskImage = "VirtualBox Disk Image";
|
||||
public const string VirtualPC = "VirtualPC";
|
||||
public const string VMwareDiskImage = "VMware disk image";
|
||||
|
||||
// Supported filesystems for identification and information only
|
||||
public const string AcornAdvancedDiscFilingSystem = "Acorn Advanced Disc Filing System";
|
||||
public const string AlexanderOsipovDOSFileSystem = "Alexander Osipov DOS file system";
|
||||
public const string AmigaDOSFilesystem = "Amiga DOS filesystem";
|
||||
public const string AppleFileSystem = "Apple File System";
|
||||
public const string AppleHFSPlusFilesystem = "Apple HFS+ filesystem";
|
||||
public const string AppleHierarchicalFileSystem = "Apple Hierarchical File System";
|
||||
public const string AppleProDOSFilesystem = "Apple ProDOS filesystem";
|
||||
public const string AtheOSFilesystem = "AtheOS Filesystem";
|
||||
public const string BeFilesystem = "Be Filesystem";
|
||||
public const string BSDFastFileSystem = "BSD Fast File System(aka UNIX File System, UFS)";
|
||||
public const string BTreeFileSystem = "B-tree file system";
|
||||
public const string CommodoreFileSystem = "Commodore file system";
|
||||
public const string CramFilesystem = "Cram filesystem";
|
||||
public const string DumpEightPlugin = "dump(8) Plugin";
|
||||
public const string ECMA67 = "ECMA-67";
|
||||
public const string ExtentFileSystemPlugin = "Extent File System Plugin";
|
||||
public const string F2FSPlugin = "F2FS Plugin";
|
||||
public const string Files11OnDiskStructure = "Files-11 On-Disk Structure";
|
||||
public const string FossilFilesystemPlugin = "Fossil Filesystem Plugin";
|
||||
public const string HAMMERFilesystem = "HAMMER Filesystem";
|
||||
public const string HighPerformanceOpticalFileSystem = "High Performance Optical File System";
|
||||
public const string HPLogicalInterchangeFormatPlugin = "HP Logical Interchange Format Plugin";
|
||||
public const string JFSPlugin = "JFS Plugin";
|
||||
public const string LinuxExtendedFilesystem = "Linux extended Filesystem";
|
||||
public const string LinuxExtendedFilesystem234 = "Linux extended Filesystem 2, 3 and 4";
|
||||
public const string LocusFilesystemPlugin = "Locus Filesystem Plugin";
|
||||
public const string MicroDOSFileSystem = "MicroDOS file system";
|
||||
public const string MicrosoftExtendedFileAllocationTable = "Microsoft Extended File Allocation Table";
|
||||
public const string MinixFilesystem = "Minix Filesystem";
|
||||
public const string NewTechnologyFileSystem = "New Technology File System(NTFS)";
|
||||
public const string NILFS2Plugin = "NILFS2 Plugin";
|
||||
public const string NintendoOpticalFilesystems = "Nintendo optical filesystems";
|
||||
public const string OS2HighPerformanceFileSystem = "OS/2 High Performance File System";
|
||||
public const string OS9RandomBlockFilePlugin = "OS-9 Random Block File Plugin";
|
||||
public const string PCEngineCDPlugin = "PC Engine CD Plugin";
|
||||
public const string PCFXPlugin = "PC-FX Plugin";
|
||||
public const string ProfessionalFileSystem = "Professional File System";
|
||||
public const string QNX4Plugin = "QNX4 Plugin";
|
||||
public const string QNX6Plugin = "QNX6 Plugin";
|
||||
public const string ReiserFilesystemPlugin = "Reiser Filesystem Plugin";
|
||||
public const string Reiser4FilesystemPlugin = "Reiser4 Filesystem Plugin";
|
||||
public const string ResilientFileSystemPlugin = "Resilient File System plugin";
|
||||
public const string RT11FileSystem = "RT-11 file system";
|
||||
public const string SmartFileSystem = "SmartFileSystem";
|
||||
public const string SolarOSFilesystem = "Solar_OS filesystem";
|
||||
public const string SquashFilesystem = "Squash filesystem";
|
||||
public const string UNICOSFilesystemPlugin = "UNICOS Filesystem Plugin";
|
||||
public const string UniversalDiskFormat = "Universal Disk Format";
|
||||
public const string UNIXBootFilesystem = "UNIX Boot filesystem";
|
||||
public const string UNIXSystemVFilesystem = "UNIX System V filesystem";
|
||||
public const string VeritasFilesystem = "Veritas filesystem";
|
||||
public const string VMwareFilesystem = "VMware filesystem";
|
||||
public const string XFSFilesystemPlugin = "XFS Filesystem Plugin";
|
||||
public const string XiaFilesystem = "Xia filesystem";
|
||||
public const string ZFSFilesystemPlugin = "ZFS Filesystem Plugin";
|
||||
|
||||
// Supported filesystems that can read their contents
|
||||
public const string AppleDOSFileSystem = "Apple DOS File System";
|
||||
public const string AppleLisaFileSystem = "Apple Lisa File System";
|
||||
public const string AppleMacintoshFileSystem = "Apple Macintosh File System";
|
||||
public const string CPMFileSystem = "CP/M File System";
|
||||
public const string FATXFilesystemPlugin = "FATX Filesystem Plugin";
|
||||
public const string ISO9660Filesystem = "ISO9660 Filesystem";
|
||||
public const string MicrosoftFileAllocationTable = "Microsoft File Allocation Table";
|
||||
public const string OperaFilesystemPlugin = "Opera Filesystem Plugin";
|
||||
public const string UCSDPascalFilesystem = "U.C.S.D.Pascal filesystem";
|
||||
|
||||
// Supported partitioning schemes
|
||||
public const string AcornFileCorePartitions = "Acorn FileCore partitions";
|
||||
public const string ACTApricotPartitions = "ACT Apricot partitions";
|
||||
public const string AmigaRigidDiskBlock = "Amiga Rigid Disk Block";
|
||||
public const string ApplePartitionMap = "Apple Partition Map";
|
||||
public const string AtariPartitions = "Atari partitions";
|
||||
public const string BSDDisklabel = "BSD disklabel";
|
||||
public const string DECDisklabel = "DEC disklabel";
|
||||
public const string DragonFlyBSD64bitDisklabel = "DragonFly BSD 64-bit disklabel";
|
||||
public const string GUIDPartitionTable = "GUID Partition Table";
|
||||
public const string Human68kPartitions = "Human 68k partitions";
|
||||
public const string MasterBootRecord = "Master Boot Record";
|
||||
public const string NECPC9800PartitionTable = "NEC PC-9800 partition table";
|
||||
public const string NeXTDisklabel = "NeXT Disklabel";
|
||||
public const string Plan9PartitionTable = "Plan9 partition table";
|
||||
public const string RioKarmaPartitioning = "Rio Karma partitioning";
|
||||
public const string SGIDiskVolumeHeader = "SGI Disk Volume Header";
|
||||
public const string SunDisklabel = "Sun Disklabel";
|
||||
public const string UNIXHardwired = "UNIX hardwired";
|
||||
public const string UNIXVTOC = "UNIX VTOC";
|
||||
public const string XboxPartitioning = "Xbox partitioning";
|
||||
public const string XENIX = "XENIX";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supported namespaces for Aaru
|
||||
/// </summary>
|
||||
/// TODO: Use to verify namespace settings
|
||||
public static class NamespaceStrings
|
||||
{
|
||||
// Namespaces for Apple Lisa File System
|
||||
public const string LisaOfficeSystem = "office";
|
||||
public const string LisaPascalWorkshop = "workshop"; // Default
|
||||
|
||||
// Namespaces for ISO9660 Filesystem
|
||||
public const string JolietVolumeDescriptor = "joliet"; // Default
|
||||
public const string PrimaryVolumeDescriptor = "normal";
|
||||
public const string PrimaryVolumeDescriptorwithEncoding = "romeo";
|
||||
public const string RockRidge = "rrip";
|
||||
public const string PrimaryVolumeDescriptorVersionSuffix = "vms";
|
||||
|
||||
// Namespaces for Microsoft File Allocation Table
|
||||
public const string DOS83UpperCase = "dos";
|
||||
public const string LFNWhenAvailableWithFallback = "ecs"; // Default
|
||||
public const string LongFileNames = "lfn";
|
||||
public const string WindowsNT83MixedCase = "nt";
|
||||
public const string OS2Extended = "os2";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supported options for Aaru
|
||||
/// </summary>
|
||||
/// TODO: Use to verify option settings
|
||||
public static class OptionStrings
|
||||
{
|
||||
// Aaru format
|
||||
public const string AaruCompress = "compress"; // boolean, default true;
|
||||
public const string AaruDeduplicate = "deduplicate"; // boolean, default true
|
||||
public const string AaruDictionary = "dictionary"; // number, default 33554432
|
||||
public const string AaruMaxDDTSize = "max_ddt_size"; // number, default 256
|
||||
public const string AaruMD5 = "md5"; // boolean, default false
|
||||
public const string AaruSectorsPerBlock = "sectors_per_block"; // number, default 4096 [power of 2]
|
||||
public const string AaruSHA1 = "sha1"; // boolean, default false
|
||||
public const string AaruSHA256 = "sha256"; // boolean, default false
|
||||
public const string AaruSpamSum = "spamsum"; // boolean, default false
|
||||
|
||||
// ACT Apricot Disk Image
|
||||
public const string ACTApricotDiskImageCompress = "compress"; // boolean, default false
|
||||
|
||||
// Apple DiskCopy 4.2
|
||||
public const string AppleDiskCopyMacOSX = "macosx"; // boolean, default false
|
||||
|
||||
// CDRDAO tocfile
|
||||
public const string CDRDAOTocfileSeparate = "separate"; // boolean, default false
|
||||
|
||||
// CDRWin cuesheet
|
||||
public const string CDRWinCuesheetSeparate = "separate"; // boolean, default false
|
||||
|
||||
// ISO9660 Filesystem
|
||||
public const string ISO9660FSUseEvd = "use_evd"; // boolean, default false
|
||||
public const string ISO9660FSUsePathTable = "use_path_table"; // boolean, default false
|
||||
public const string ISO9660FSUseTransTbl = "use_trans_tbl"; // boolean, default false
|
||||
|
||||
// VMware disk image
|
||||
public const string VMwareDiskImageAdapterType = "adapter_type"; // string, default ide [ide, lsilogic, buslogic, legacyESX]
|
||||
public const string VMwareDiskImageHWVersion = "hwversion"; // number, default 4
|
||||
public const string VMwareDiskImageSparse = "sparse"; // boolean, default false
|
||||
public const string VMwareDiskImageSplit = "split"; // boolean, default false
|
||||
}
|
||||
}
|
||||
22
MPF.Core/Modules/Aaru/Converters.cs
Normal file
22
MPF.Core/Modules/Aaru/Converters.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Modules.Aaru
|
||||
{
|
||||
public static class Converters
|
||||
{
|
||||
#region Cross-enumeration conversions
|
||||
|
||||
/// <summary>
|
||||
/// Get the default extension for a given disc type
|
||||
/// </summary>
|
||||
/// <param name="type">MediaType value to check</param>
|
||||
/// <returns>Valid extension (with leading '.'), null on error</returns>
|
||||
public static string Extension(MediaType? type)
|
||||
{
|
||||
// Aaru has a single, unified output format by default
|
||||
return ".aaruf";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
3414
MPF.Core/Modules/Aaru/Parameters.cs
Normal file
3414
MPF.Core/Modules/Aaru/Parameters.cs
Normal file
File diff suppressed because it is too large
Load Diff
7391
MPF.Core/Modules/Aaru/cicm.cs
Normal file
7391
MPF.Core/Modules/Aaru/cicm.cs
Normal file
File diff suppressed because it is too large
Load Diff
1214
MPF.Core/Modules/BaseParameters.cs
Normal file
1214
MPF.Core/Modules/BaseParameters.cs
Normal file
File diff suppressed because it is too large
Load Diff
395
MPF.Core/Modules/CleanRIp/Parameters.cs
Normal file
395
MPF.Core/Modules/CleanRIp/Parameters.cs
Normal file
@@ -0,0 +1,395 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Data;
|
||||
using SabreTools.RedumpLib;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Modules.CleanRip
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic set of CleanRip parameters
|
||||
/// </summary>
|
||||
public class Parameters : BaseParameters
|
||||
{
|
||||
#region Metadata
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override InternalProgram InternalProgram => InternalProgram.CleanRip;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(string? parameters) : base(parameters) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(RedumpSystem? system, MediaType? type, string? drivePath, string filename, int? driveSpeed, Options options)
|
||||
: base(system, type, drivePath, filename, driveSpeed, options)
|
||||
{
|
||||
}
|
||||
|
||||
#region BaseParameters Implementations
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override (bool, List<string>) CheckAllOutputFilesExist(string basePath, bool preCheck)
|
||||
{
|
||||
var missingFiles = new List<string>();
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.DVD: // Only added here to help users; not strictly correct
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
if (!File.Exists($"{basePath}_logs.zip") || !preCheck)
|
||||
{
|
||||
if (!File.Exists($"{basePath}-dumpinfo.txt"))
|
||||
missingFiles.Add($"{basePath}-dumpinfo.txt");
|
||||
if (!File.Exists($"{basePath}.bca"))
|
||||
missingFiles.Add($"{basePath}.bca");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
missingFiles.Add("Media and system combination not supported for CleanRip");
|
||||
break;
|
||||
}
|
||||
|
||||
return (!missingFiles.Any(), missingFiles);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive? drive, bool includeArtifacts)
|
||||
{
|
||||
// Ensure that required sections exist
|
||||
info = Builder.EnsureAllSections(info);
|
||||
|
||||
// TODO: Determine if there's a CleanRip version anywhere
|
||||
info.DumpingInfo!.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
|
||||
info.DumpingInfo.DumpingDate = InfoTool.GetFileModifiedDate(basePath + "-dumpinfo.txt")?.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
// Get the Datafile information
|
||||
var datafile = GenerateCleanripDatafile(basePath + ".iso", basePath + "-dumpinfo.txt");
|
||||
|
||||
// Fill in the hash data
|
||||
info.TracksAndWriteOffsets!.ClrMameProData = InfoTool.GenerateDatfile(datafile);
|
||||
|
||||
// Get the individual hash data, as per internal
|
||||
if (InfoTool.GetISOHashValues(datafile, out long size, out var crc32, out var md5, out var sha1))
|
||||
{
|
||||
info.SizeAndChecksums!.Size = size;
|
||||
info.SizeAndChecksums.CRC32 = crc32;
|
||||
info.SizeAndChecksums.MD5 = md5;
|
||||
info.SizeAndChecksums.SHA1 = sha1;
|
||||
|
||||
// Dual-layer discs have the same size and layerbreak
|
||||
if (size == 8511160320)
|
||||
info.SizeAndChecksums.Layerbreak = 2084960;
|
||||
}
|
||||
|
||||
// Extract info based generically on MediaType
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.DVD: // Only added here to help users; not strictly correct
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
if (File.Exists(basePath + ".bca"))
|
||||
info.Extras!.BCA = GetBCA(basePath + ".bca");
|
||||
|
||||
if (GetGameCubeWiiInformation(basePath + "-dumpinfo.txt", out Region? gcRegion, out var gcVersion, out var gcName, out var gcSerial))
|
||||
{
|
||||
info.CommonDiscInfo!.Region = gcRegion ?? info.CommonDiscInfo.Region;
|
||||
info.VersionAndEditions!.Version = gcVersion ?? info.VersionAndEditions.Version;
|
||||
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalName] = gcName ?? string.Empty;
|
||||
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = gcSerial ?? string.Empty;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill in any artifacts that exist, Base64-encoded, if we need to
|
||||
if (includeArtifacts)
|
||||
{
|
||||
info.Artifacts ??= [];
|
||||
|
||||
if (File.Exists(basePath + ".bca"))
|
||||
info.Artifacts["bca"] = GetBase64(GetFullFile(basePath + ".bca", binary: true)) ?? string.Empty;
|
||||
if (File.Exists(basePath + "-dumpinfo.txt"))
|
||||
info.Artifacts["dumpinfo"] = GetBase64(GetFullFile(basePath + "-dumpinfo.txt")) ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<string> GetLogFilePaths(string basePath)
|
||||
{
|
||||
var logFiles = new List<string>();
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.DVD: // Only added here to help users; not strictly correct
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
if (File.Exists($"{basePath}-dumpinfo.txt"))
|
||||
logFiles.Add($"{basePath}-dumpinfo.txt");
|
||||
if (File.Exists($"{basePath}.bca"))
|
||||
logFiles.Add($"{basePath}.bca");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return logFiles;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Information Extraction Methods
|
||||
|
||||
/// <summary>
|
||||
/// Get a formatted datfile from the cleanrip output, if possible
|
||||
/// </summary>
|
||||
/// <param name="iso">Path to ISO file</param>
|
||||
/// <param name="dumpinfo">Path to discinfo file</param>
|
||||
/// <returns></returns>
|
||||
private static Datafile? GenerateCleanripDatafile(string iso, string dumpinfo)
|
||||
{
|
||||
// If the files don't exist, we can't get info from it
|
||||
if (!File.Exists(iso) || !File.Exists(dumpinfo))
|
||||
return null;
|
||||
|
||||
long size = new FileInfo(iso).Length;
|
||||
string crc = string.Empty;
|
||||
string md5 = string.Empty;
|
||||
string sha1 = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
// Make sure this file is a dumpinfo
|
||||
using var sr = File.OpenText(dumpinfo);
|
||||
if (sr.ReadLine()?.Contains("--File Generated by CleanRip") != true)
|
||||
return null;
|
||||
|
||||
// Read all lines and gather dat information
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
var line = sr.ReadLine()?.Trim();
|
||||
if (string.IsNullOrEmpty(line))
|
||||
continue;
|
||||
else if (line!.StartsWith("CRC32"))
|
||||
crc = line.Substring(7).ToLowerInvariant();
|
||||
else if (line.StartsWith("MD5"))
|
||||
md5 = line.Substring(5);
|
||||
else if (line.StartsWith("SHA-1"))
|
||||
sha1 = line.Substring(7);
|
||||
}
|
||||
|
||||
return new Datafile
|
||||
{
|
||||
Games =
|
||||
[
|
||||
new()
|
||||
{
|
||||
Roms =
|
||||
[
|
||||
new Rom { Name = Path.GetFileName(iso), Size = size.ToString(), Crc = crc, Md5 = md5, Sha1 = sha1 },
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the exception is right now
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the hex contents of the BCA file
|
||||
/// </summary>
|
||||
/// <param name="bcaPath">Path to the BCA file associated with the dump</param>
|
||||
/// <returns>BCA data as a hex string if possible, null on error</returns>
|
||||
/// <remarks>https://stackoverflow.com/questions/9932096/add-separator-to-string-at-every-n-characters</remarks>
|
||||
private static string? GetBCA(string bcaPath)
|
||||
{
|
||||
// If the file doesn't exist, we can't get the info
|
||||
if (!File.Exists(bcaPath))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
var hex = GetFullFile(bcaPath, true);
|
||||
if (hex == null)
|
||||
return null;
|
||||
|
||||
return Regex.Replace(hex, ".{32}", "$0\n");
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error was right now
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a formatted datfile from the cleanrip output, if possible
|
||||
/// </summary>
|
||||
/// <param name="iso">Path to ISO file</param>
|
||||
/// <param name="dumpinfo">Path to discinfo file</param>
|
||||
/// <returns></returns>
|
||||
private static string? GetCleanripDatfile(string iso, string dumpinfo)
|
||||
{
|
||||
// If the files don't exist, we can't get info from it
|
||||
if (!File.Exists(iso) || !File.Exists(dumpinfo))
|
||||
return null;
|
||||
|
||||
long size = new FileInfo(iso).Length;
|
||||
string crc = string.Empty;
|
||||
string md5 = string.Empty;
|
||||
string sha1 = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
// Make sure this file is a dumpinfo
|
||||
using var sr = File.OpenText(dumpinfo);
|
||||
if (sr.ReadLine()?.Contains("--File Generated by CleanRip") != true)
|
||||
return null;
|
||||
|
||||
// Read all lines and gather dat information
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
var line = sr.ReadLine()?.Trim();
|
||||
if (string.IsNullOrEmpty(line))
|
||||
continue;
|
||||
else if (line!.StartsWith("CRC32"))
|
||||
crc = line.Substring(7).ToLowerInvariant();
|
||||
else if (line.StartsWith("MD5"))
|
||||
md5 = line.Substring(5);
|
||||
else if (line.StartsWith("SHA-1"))
|
||||
sha1 = line.Substring(7);
|
||||
}
|
||||
|
||||
return $"<rom name=\"{Path.GetFileName(iso)}\" size=\"{size}\" crc=\"{crc}\" md5=\"{md5}\" sha1=\"{sha1}\" />";
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the exception is right now
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the extracted GC and Wii version
|
||||
/// </summary>
|
||||
/// <param name="dumpinfo">Path to discinfo file</param>
|
||||
/// <param name="region">Output region, if possible</param>
|
||||
/// <param name="version">Output internal version of the game</param>
|
||||
/// <param name="name">Output internal name of the game</param>
|
||||
/// <param name="serial">Output internal serial of the game</param>
|
||||
/// <returns></returns>
|
||||
private static bool GetGameCubeWiiInformation(string dumpinfo, out Region? region, out string? version, out string? name, out string? serial)
|
||||
{
|
||||
region = null; version = null; name = null; serial = null;
|
||||
|
||||
// If the file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(dumpinfo))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
// Make sure this file is a dumpinfo
|
||||
using var sr = File.OpenText(dumpinfo);
|
||||
if (sr.ReadLine()?.Contains("--File Generated by CleanRip") != true)
|
||||
return false;
|
||||
|
||||
// Read all lines and gather dat information
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
var line = sr.ReadLine()?.Trim();
|
||||
if (string.IsNullOrEmpty(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (line!.StartsWith("Version"))
|
||||
{
|
||||
version = line.Substring("Version: ".Length);
|
||||
}
|
||||
else if (line.StartsWith("Internal Name"))
|
||||
{
|
||||
name = line.Substring("Internal Name: ".Length);
|
||||
}
|
||||
else if (line.StartsWith("Filename"))
|
||||
{
|
||||
serial = line.Substring("Filename: ".Length);
|
||||
if (serial.EndsWith("-disc2"))
|
||||
serial = serial.Replace("-disc2", string.Empty);
|
||||
|
||||
// char gameType = serial[0];
|
||||
// string gameid = serial[1] + serial[2];
|
||||
// string version = serial[4] + serial[5]
|
||||
|
||||
switch (serial[3])
|
||||
{
|
||||
case 'A':
|
||||
region = Region.World;
|
||||
break;
|
||||
case 'D':
|
||||
region = Region.Germany;
|
||||
break;
|
||||
case 'E':
|
||||
region = Region.UnitedStatesOfAmerica;
|
||||
break;
|
||||
case 'F':
|
||||
region = Region.France;
|
||||
break;
|
||||
case 'I':
|
||||
region = Region.Italy;
|
||||
break;
|
||||
case 'J':
|
||||
region = Region.Japan;
|
||||
break;
|
||||
case 'K':
|
||||
region = Region.SouthKorea;
|
||||
break;
|
||||
case 'L':
|
||||
region = Region.Europe; // Japanese import to Europe
|
||||
break;
|
||||
case 'M':
|
||||
region = Region.Europe; // American import to Europe
|
||||
break;
|
||||
case 'N':
|
||||
region = Region.UnitedStatesOfAmerica; // Japanese import to USA
|
||||
break;
|
||||
case 'P':
|
||||
region = Region.Europe;
|
||||
break;
|
||||
case 'R':
|
||||
region = Region.RussianFederation;
|
||||
break;
|
||||
case 'S':
|
||||
region = Region.Spain;
|
||||
break;
|
||||
case 'Q':
|
||||
region = Region.SouthKorea; // Korea with Japanese language
|
||||
break;
|
||||
case 'T':
|
||||
region = Region.SouthKorea; // Korea with English language
|
||||
break;
|
||||
case 'X':
|
||||
region = null; // Not a real region code
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the exception is right now
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
73
MPF.Core/Modules/Datafile.cs
Normal file
73
MPF.Core/Modules/Datafile.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace MPF.Core.Modules
|
||||
{
|
||||
[XmlRoot("datafile")]
|
||||
public class Datafile
|
||||
{
|
||||
[XmlElement("header")]
|
||||
public Header? Header;
|
||||
|
||||
[XmlElement("game")]
|
||||
public Game[]? Games;
|
||||
}
|
||||
|
||||
public class Header
|
||||
{
|
||||
[XmlElement("name")]
|
||||
public string? Name;
|
||||
|
||||
[XmlElement("description")]
|
||||
public string? Description;
|
||||
|
||||
[XmlElement("version")]
|
||||
public string? Version;
|
||||
|
||||
[XmlElement("date")]
|
||||
public string? Date;
|
||||
|
||||
[XmlElement("author")]
|
||||
public string? Author;
|
||||
|
||||
[XmlElement("homepage")]
|
||||
public string? Homepage;
|
||||
|
||||
[XmlElement("url")]
|
||||
public string? Url;
|
||||
}
|
||||
|
||||
public class Game
|
||||
{
|
||||
[XmlAttribute("name")]
|
||||
public string? Name;
|
||||
|
||||
[XmlElement("category")]
|
||||
public string? Category;
|
||||
|
||||
[XmlElement("description")]
|
||||
public string? Description;
|
||||
|
||||
[XmlElement("rom")]
|
||||
public Rom[]? Roms;
|
||||
}
|
||||
|
||||
public class Rom
|
||||
{
|
||||
[XmlAttribute("name")]
|
||||
public string? Name;
|
||||
|
||||
[XmlAttribute("size")]
|
||||
public string? Size;
|
||||
|
||||
[XmlAttribute("crc")]
|
||||
public string? Crc;
|
||||
|
||||
[XmlAttribute("md5")]
|
||||
public string? Md5;
|
||||
|
||||
[XmlAttribute("sha1")]
|
||||
public string? Sha1;
|
||||
|
||||
// TODO: Add extended hashes here
|
||||
}
|
||||
}
|
||||
77
MPF.Core/Modules/DiscImageCreator/Constants.cs
Normal file
77
MPF.Core/Modules/DiscImageCreator/Constants.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
namespace MPF.Core.Modules.DiscImageCreator
|
||||
{
|
||||
/// <summary>
|
||||
/// Top-level commands for DiscImageCreator
|
||||
/// </summary>
|
||||
public static class CommandStrings
|
||||
{
|
||||
public const string NONE = "";
|
||||
public const string Audio = "audio";
|
||||
public const string BluRay = "bd";
|
||||
public const string Close = "close";
|
||||
public const string CompactDisc = "cd";
|
||||
public const string Data = "data";
|
||||
public const string DigitalVideoDisc = "dvd";
|
||||
public const string Disk = "disk";
|
||||
public const string DriveSpeed = "ls";
|
||||
public const string Eject = "eject";
|
||||
public const string Floppy = "fd";
|
||||
public const string GDROM = "gd";
|
||||
public const string MDS = "mds";
|
||||
public const string Merge = "merge";
|
||||
public const string Reset = "reset";
|
||||
public const string SACD = "sacd";
|
||||
public const string Start = "start";
|
||||
public const string Stop = "stop";
|
||||
public const string Sub = "sub";
|
||||
public const string Swap = "swap";
|
||||
public const string Tape = "tape";
|
||||
public const string Version = "/v";
|
||||
public const string XBOX = "xbox";
|
||||
public const string XBOXSwap = "xboxswap";
|
||||
public const string XGD2Swap = "xgd2swap";
|
||||
public const string XGD3Swap = "xgd3swap";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dumping flags for DiscImageCreator
|
||||
/// </summary>
|
||||
public static class FlagStrings
|
||||
{
|
||||
public const string AddOffset = "/a";
|
||||
public const string AMSF = "/p";
|
||||
public const string AtariJaguar = "/aj";
|
||||
public const string BEOpcode = "/be";
|
||||
public const string C2Opcode = "/c2";
|
||||
public const string CopyrightManagementInformation = "/c";
|
||||
public const string D8Opcode = "/d8";
|
||||
public const string DatExpand = "/d";
|
||||
public const string DisableBeep = "/q";
|
||||
public const string DVDReread = "/rr";
|
||||
public const string ExtractMicroSoftCabFile = "/mscf";
|
||||
public const string Fix = "/fix";
|
||||
public const string ForceUnitAccess = "/f";
|
||||
public const string MultiSectorRead = "/mr";
|
||||
public const string NoFixSubP = "/np";
|
||||
public const string NoFixSubQ = "/nq";
|
||||
public const string NoFixSubQLibCrypt = "/nl";
|
||||
public const string NoFixSubRtoW = "/nr";
|
||||
public const string NoFixSubQSecuROM = "/ns";
|
||||
public const string NoSkipSS = "/nss";
|
||||
public const string PadSector = "/ps";
|
||||
public const string Range = "/ra";
|
||||
public const string Raw = "/raw";
|
||||
public const string Resume = "/re";
|
||||
public const string Reverse = "/r";
|
||||
public const string ScanAntiMod = "/am";
|
||||
public const string ScanFileProtect = "/sf";
|
||||
public const string ScanSectorProtect = "/ss";
|
||||
public const string SeventyFour = "/74";
|
||||
public const string SkipSector = "/sk";
|
||||
public const string SubchannelReadLevel = "/s";
|
||||
public const string UseAnchorVolumeDescriptorPointer = "/avdp";
|
||||
public const string VideoNow = "/vn";
|
||||
public const string VideoNowColor = "/vnc";
|
||||
public const string VideoNowXP = "/vnx";
|
||||
}
|
||||
}
|
||||
100
MPF.Core/Modules/DiscImageCreator/Converters.cs
Normal file
100
MPF.Core/Modules/DiscImageCreator/Converters.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Modules.DiscImageCreator
|
||||
{
|
||||
public static class Converters
|
||||
{
|
||||
#region Cross-enumeration conversions
|
||||
|
||||
/// <summary>
|
||||
/// Get the most common known system for a given MediaType
|
||||
/// </summary>
|
||||
/// <param name="baseCommand">Command value to check</param>
|
||||
/// <returns>RedumpSystem if possible, null on error</returns>
|
||||
public static RedumpSystem? ToRedumpSystem(string baseCommand)
|
||||
{
|
||||
return baseCommand switch
|
||||
{
|
||||
CommandStrings.Audio => (RedumpSystem?)RedumpSystem.AudioCD,
|
||||
CommandStrings.CompactDisc
|
||||
or CommandStrings.Data
|
||||
or CommandStrings.DigitalVideoDisc
|
||||
or CommandStrings.Disk
|
||||
or CommandStrings.Floppy
|
||||
or CommandStrings.Tape => (RedumpSystem?)RedumpSystem.IBMPCcompatible,
|
||||
CommandStrings.GDROM
|
||||
or CommandStrings.Swap => (RedumpSystem?)RedumpSystem.SegaDreamcast,
|
||||
CommandStrings.BluRay => (RedumpSystem?)RedumpSystem.SonyPlayStation3,
|
||||
CommandStrings.SACD => (RedumpSystem?)RedumpSystem.SuperAudioCD,
|
||||
CommandStrings.XBOX
|
||||
or CommandStrings.XBOXSwap => (RedumpSystem?)RedumpSystem.MicrosoftXbox,
|
||||
CommandStrings.XGD2Swap
|
||||
or CommandStrings.XGD3Swap => (RedumpSystem?)RedumpSystem.MicrosoftXbox360,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the MediaType associated with a given base command
|
||||
/// </summary>
|
||||
/// <param name="baseCommand">Command value to check</param>
|
||||
/// <returns>MediaType if possible, null on error</returns>
|
||||
/// <remarks>This takes the "safe" route by assuming the larger of any given format</remarks>
|
||||
public static MediaType? ToMediaType(string? baseCommand)
|
||||
{
|
||||
return baseCommand switch
|
||||
{
|
||||
CommandStrings.Audio
|
||||
or CommandStrings.CompactDisc
|
||||
or CommandStrings.Data
|
||||
or CommandStrings.SACD => (MediaType?)MediaType.CDROM,
|
||||
CommandStrings.GDROM
|
||||
or CommandStrings.Swap => (MediaType?)MediaType.GDROM,
|
||||
CommandStrings.DigitalVideoDisc
|
||||
or CommandStrings.XBOX
|
||||
or CommandStrings.XBOXSwap
|
||||
or CommandStrings.XGD2Swap
|
||||
or CommandStrings.XGD3Swap => (MediaType?)MediaType.DVD,
|
||||
CommandStrings.BluRay => (MediaType?)MediaType.BluRay,
|
||||
|
||||
// Non-optical
|
||||
CommandStrings.Floppy => (MediaType?)MediaType.FloppyDisk,
|
||||
CommandStrings.Disk => (MediaType?)MediaType.HardDisk,
|
||||
CommandStrings.Tape => (MediaType?)MediaType.DataCartridge,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the default extension for a given disc type
|
||||
/// </summary>
|
||||
/// <param name="type">MediaType value to check</param>
|
||||
/// <returns>Valid extension (with leading '.'), null on error</returns>
|
||||
public static string? Extension(MediaType? type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
MediaType.CDROM
|
||||
or MediaType.GDROM
|
||||
or MediaType.Cartridge
|
||||
or MediaType.HardDisk
|
||||
or MediaType.CompactFlash
|
||||
or MediaType.MMC
|
||||
or MediaType.SDCard
|
||||
or MediaType.FlashDrive => ".bin",
|
||||
MediaType.DVD
|
||||
or MediaType.HDDVD
|
||||
or MediaType.BluRay
|
||||
or MediaType.NintendoWiiOpticalDisc => ".iso",
|
||||
MediaType.LaserDisc
|
||||
or MediaType.NintendoGameCubeGameDisc => ".raw",
|
||||
MediaType.NintendoWiiUOpticalDisc => ".wud",
|
||||
MediaType.FloppyDisk => ".img",
|
||||
MediaType.Cassette => ".wav",
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
3933
MPF.Core/Modules/DiscImageCreator/Parameters.cs
Normal file
3933
MPF.Core/Modules/DiscImageCreator/Parameters.cs
Normal file
File diff suppressed because it is too large
Load Diff
293
MPF.Core/Modules/PS3CFW/Parameters.cs
Normal file
293
MPF.Core/Modules/PS3CFW/Parameters.cs
Normal file
@@ -0,0 +1,293 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Data;
|
||||
using SabreTools.Hashing;
|
||||
using SabreTools.RedumpLib;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Modules.PS3CFW
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic set of PlayStation 3 Custom Firmware parameters
|
||||
/// </summary>
|
||||
public class Parameters : BaseParameters
|
||||
{
|
||||
#region Metadata
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override InternalProgram InternalProgram => InternalProgram.PS3CFW;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(string? parameters) : base(parameters) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(RedumpSystem? system, MediaType? type, string? drivePath, string filename, int? driveSpeed, Options options)
|
||||
: base(system, type, drivePath, filename, driveSpeed, options)
|
||||
{
|
||||
}
|
||||
|
||||
#region BaseParameters Implementations
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override (bool, List<string>) CheckAllOutputFilesExist(string basePath, bool preCheck)
|
||||
{
|
||||
var missingFiles = new List<string>();
|
||||
|
||||
if (this.Type != MediaType.BluRay || this.System != RedumpSystem.SonyPlayStation3)
|
||||
{
|
||||
missingFiles.Add("Media and system combination not supported for PS3 CFW");
|
||||
}
|
||||
else
|
||||
{
|
||||
string? getKeyBasePath = GetCFWBasePath(basePath);
|
||||
if (!File.Exists($"{getKeyBasePath}.getkey.log"))
|
||||
missingFiles.Add($"{getKeyBasePath}.getkey.log");
|
||||
if (!File.Exists($"{getKeyBasePath}.disc.pic"))
|
||||
missingFiles.Add($"{getKeyBasePath}.disc.pic");
|
||||
}
|
||||
|
||||
return (missingFiles.Count == 0, missingFiles);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive? drive, bool includeArtifacts)
|
||||
{
|
||||
// Ensure that required sections exist
|
||||
info = Builder.EnsureAllSections(info);
|
||||
|
||||
info.DumpingInfo!.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
|
||||
|
||||
// Get the Datafile information
|
||||
Datafile? datafile = GeneratePS3CFWDatafile(basePath + ".iso");
|
||||
|
||||
// Fill in the hash data
|
||||
info.TracksAndWriteOffsets!.ClrMameProData = InfoTool.GenerateDatfile(datafile);
|
||||
|
||||
// Get the individual hash data, as per internal
|
||||
if (InfoTool.GetISOHashValues(datafile, out long size, out var crc32, out var md5, out var sha1))
|
||||
{
|
||||
info.SizeAndChecksums!.Size = size;
|
||||
info.SizeAndChecksums.CRC32 = crc32;
|
||||
info.SizeAndChecksums.MD5 = md5;
|
||||
info.SizeAndChecksums.SHA1 = sha1;
|
||||
}
|
||||
|
||||
// Get the PVD from the ISO
|
||||
if (GetPVD(basePath + ".iso", out string? pvd))
|
||||
info.Extras!.PVD = pvd;
|
||||
|
||||
// Try get the serial, version, and firmware version if a drive is provided
|
||||
if (drive != null)
|
||||
{
|
||||
info.VersionAndEditions!.Version = InfoTool.GetPlayStation3Version(drive?.Name) ?? string.Empty;
|
||||
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = InfoTool.GetPlayStation3Serial(drive?.Name) ?? string.Empty;
|
||||
string? firmwareVersion = InfoTool.GetPlayStation3FirmwareVersion(drive?.Name);
|
||||
if (firmwareVersion != null)
|
||||
info.CommonDiscInfo!.ContentsSpecialFields![SiteCode.Patches] = $"PS3 Firmware {firmwareVersion}";
|
||||
}
|
||||
|
||||
// Try to determine the name of the GetKey file(s)
|
||||
string? getKeyBasePath = GetCFWBasePath(basePath);
|
||||
|
||||
// If GenerateSubmissionInfo is run, .getkey.log existence should already be checked
|
||||
if (!File.Exists(getKeyBasePath + ".getkey.log"))
|
||||
return;
|
||||
|
||||
// Get dumping date from GetKey log date
|
||||
info.DumpingInfo.DumpingDate = InfoTool.GetFileModifiedDate(getKeyBasePath + ".getkey.log")?.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
// TODO: Put info about abnormal PIC info beyond 132 bytes in comments?
|
||||
if (File.Exists(getKeyBasePath + ".disc.pic"))
|
||||
info.Extras!.PIC = GetPIC(getKeyBasePath + ".disc.pic", 264);
|
||||
|
||||
// Parse Disc Key, Disc ID, and PIC from the .getkey.log file
|
||||
if (Utilities.Tools.ParseGetKeyLog(getKeyBasePath + ".getkey.log", out string? key, out string? id, out string? pic))
|
||||
{
|
||||
if (key != null)
|
||||
info.Extras!.DiscKey = key.ToUpperInvariant();
|
||||
if (id != null)
|
||||
info.Extras!.DiscID = id.ToUpperInvariant().Substring(0, 24) + "XXXXXXXX";
|
||||
if (string.IsNullOrEmpty(info.Extras!.PIC) && !string.IsNullOrEmpty(pic))
|
||||
{
|
||||
pic = Regex.Replace(pic, ".{32}", "$0\n");
|
||||
info.Extras.PIC = pic;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in any artifacts that exist, Base64-encoded, if we need to
|
||||
if (includeArtifacts)
|
||||
{
|
||||
info.Artifacts ??= [];
|
||||
|
||||
if (File.Exists(getKeyBasePath + ".disc.pic"))
|
||||
info.Artifacts["discpic"] = GetBase64(GetFullFile(getKeyBasePath + ".disc.pic", binary: true)) ?? string.Empty;
|
||||
if (File.Exists(getKeyBasePath + ".getkey.log"))
|
||||
info.Artifacts["getkeylog"] = GetBase64(GetFullFile(getKeyBasePath + ".getkey.log")) ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<string> GetLogFilePaths(string basePath)
|
||||
{
|
||||
var logFiles = new List<string>();
|
||||
string? getKeyBasePath = GetCFWBasePath(basePath);
|
||||
|
||||
if (this.System != RedumpSystem.SonyPlayStation3)
|
||||
return logFiles;
|
||||
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.BluRay:
|
||||
if (File.Exists($"{getKeyBasePath}.getkey.log"))
|
||||
logFiles.Add($"{getKeyBasePath}.getkey.log");
|
||||
if (File.Exists($"{getKeyBasePath}.disc.pic"))
|
||||
logFiles.Add($"{getKeyBasePath}.disc.pic");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return logFiles;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Information Extraction Methods
|
||||
|
||||
/// <summary>
|
||||
/// Get a formatted datfile from the PS3 CFW output, if possible
|
||||
/// </summary>
|
||||
/// <param name="iso">Path to ISO file</param>
|
||||
/// <returns></returns>
|
||||
private static Datafile? GeneratePS3CFWDatafile(string iso)
|
||||
{
|
||||
// If the ISO file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(iso))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
if (HashTool.GetStandardHashes(iso, out long size, out string? crc, out string? md5, out string? sha1))
|
||||
{
|
||||
return new Datafile
|
||||
{
|
||||
Games = [new Game { Roms = [new Rom { Name = Path.GetFileName(iso), Size = size.ToString(), Crc = crc, Md5 = md5, Sha1 = sha1, }] }]
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the exception is right now
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Don't hardcode 0x8320 and move this function to BaseParameters
|
||||
/// <summary>
|
||||
/// Get a isobuster-formatted PVD from a PS3 ISO, if possible
|
||||
/// </summary>
|
||||
/// <param name="isoPath">Path to ISO file</param>
|
||||
/// <param name="pvd">Formatted PVD string, otherwise null</param>
|
||||
/// <returns>True if PVD was successfully parsed, otherwise false</returns>
|
||||
private static bool GetPVD(string isoPath, out string? pvd)
|
||||
{
|
||||
pvd = null;
|
||||
try
|
||||
{
|
||||
// Get PVD bytes from ISO file
|
||||
var buf = new byte[96];
|
||||
using (FileStream iso = File.OpenRead(isoPath))
|
||||
{
|
||||
iso.Seek(0x8320, SeekOrigin.Begin);
|
||||
|
||||
int offset = 0;
|
||||
while (offset < 96)
|
||||
{
|
||||
int read = iso.Read(buf, offset, buf.Length - offset);
|
||||
if (read == 0)
|
||||
throw new EndOfStreamException();
|
||||
offset += read;
|
||||
}
|
||||
}
|
||||
|
||||
// Format PVD to isobuster standard
|
||||
char[] pvdCharArray = new char[96];
|
||||
for (int i = 0; i < 96; i++)
|
||||
{
|
||||
if (buf[i] >= 0x20 && buf[i] <= 0x7E)
|
||||
pvdCharArray[i] = (char)buf[i];
|
||||
else
|
||||
pvdCharArray[i] = '.';
|
||||
}
|
||||
string pvdASCII = new string(pvdCharArray, 0, 96);
|
||||
pvd = string.Empty;
|
||||
for (int i = 0; i < 96; i += 16)
|
||||
{
|
||||
pvd += $"{(0x0320+i):X4} : {buf[i]:X2} {buf[i+1]:X2} {buf[i+2]:X2} {buf[i+3]:X2} {buf[i+4]:X2} {buf[i+5]:X2} {buf[i+6]:X2} {buf[i+7]:X2} " +
|
||||
$"{buf[i+8]:X2} {buf[i+9]:X2} {buf[i+10]:X2} {buf[i+11]:X2} {buf[i+12]:X2} {buf[i+13]:X2} {buf[i+14]:X2} {buf[i+15]:X2} {pvdASCII.Substring(i, 16)}\n";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error is
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a formatted datfile from the PS3 CFW output, if possible
|
||||
/// </summary>
|
||||
/// <param name="iso">Path to ISO file</param>
|
||||
/// <returns>Formatted datfile, null if not valid</returns>
|
||||
private static string? GetPS3CFWDatfile(string iso)
|
||||
{
|
||||
// If the files don't exist, we can't get info from it
|
||||
if (!File.Exists(iso))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
if (HashTool.GetStandardHashes(iso, out long size, out string? crc, out string? md5, out string? sha1))
|
||||
return $"<rom name=\"{Path.GetFileName(iso)}\" size=\"{size}\" crc=\"{crc}\" md5=\"{md5}\" sha1=\"{sha1}\" />";
|
||||
return null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the exception is right now
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper Functions
|
||||
|
||||
/// <summary>
|
||||
/// Estimate the base filename of the .getkey.log file associated with the dump
|
||||
/// </summary>
|
||||
/// <param name="iso">Path to ISO file</param>
|
||||
/// <returns>Base filename, null if not found</returns>
|
||||
private string? GetCFWBasePath(string iso)
|
||||
{
|
||||
string? dir = Path.GetDirectoryName(iso);
|
||||
dir ??= ".";
|
||||
|
||||
string[] files = Directory.GetFiles(dir, "*.getkey.log");
|
||||
|
||||
if (files.Length != 1)
|
||||
return null;
|
||||
|
||||
return files[0].Substring(0, files[0].Length - 11);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
83
MPF.Core/Modules/Redumper/Constants.cs
Normal file
83
MPF.Core/Modules/Redumper/Constants.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
namespace MPF.Core.Modules.Redumper
|
||||
{
|
||||
/// <summary>
|
||||
/// Top-level commands for Redumper
|
||||
/// </summary>
|
||||
public static class CommandStrings
|
||||
{
|
||||
public const string NONE = "";
|
||||
public const string CD = "cd";
|
||||
public const string DVD = "dvd"; // Synonym for CD
|
||||
public const string BluRay = "bd"; // Synonym for CD
|
||||
public const string SACD = "sacd"; // Synonym for CD
|
||||
public const string Rings = "rings";
|
||||
public const string Dump = "dump";
|
||||
public const string DumpNew = "dumpnew"; // Temporary command, to be removed later
|
||||
public const string Refine = "refine";
|
||||
public const string RefineNew = "refinenew"; // Temporary command, to be removed later
|
||||
public const string Verify = "verify";
|
||||
public const string DVDKey = "dvdkey";
|
||||
public const string DVDIsoKey = "dvdisokey";
|
||||
public const string Protection = "protection";
|
||||
public const string Split = "split";
|
||||
public const string Hash = "hash";
|
||||
public const string Info = "info";
|
||||
public const string Skeleton = "skeleton";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dumping flags for Redumper
|
||||
/// </summary>
|
||||
public static class FlagStrings
|
||||
{
|
||||
// General
|
||||
public const string HelpLong = "--help";
|
||||
public const string HelpShort = "-h";
|
||||
public const string Version = "--version";
|
||||
public const string Verbose = "--verbose";
|
||||
public const string Debug = "--debug";
|
||||
public const string Drive = "--drive";
|
||||
public const string Speed = "--speed";
|
||||
public const string Retries = "--retries";
|
||||
public const string ImagePath = "--image-path";
|
||||
public const string ImageName = "--image-name";
|
||||
public const string Overwrite = "--overwrite";
|
||||
|
||||
// Drive Configuration
|
||||
public const string DriveType = "--drive-type";
|
||||
public const string DriveReadOffset = "--drive-read-offset";
|
||||
public const string DriveC2Shift = "--drive-c2-shift";
|
||||
public const string DrivePregapStart = "--drive-pregap-start";
|
||||
public const string DriveReadMethod = "--drive-read-method";
|
||||
public const string DriveSectorOrder = "--drive-sector-order";
|
||||
|
||||
// Drive Specific
|
||||
public const string PlextorSkipLeadin = "--plextor-skip-leadin";
|
||||
public const string PlextorLeadinRetries = "--plextor-leadin-retries";
|
||||
public const string AsusSkipLeadout = "--asus-skip-leadout";
|
||||
|
||||
// Offset
|
||||
public const string ForceOffset = "--force-offset";
|
||||
public const string AudioSilenceThreshold = "--audio-silence-threshold";
|
||||
public const string CorrectOffsetShift = "--correct-offset-shift";
|
||||
public const string OffsetShiftRelocate = "--offset-shift-relocate";
|
||||
|
||||
// Split
|
||||
public const string ForceSplit = "--force-split";
|
||||
public const string LeaveUnchanged = "--leave-unchanged";
|
||||
public const string ForceQTOC = "--force-qtoc";
|
||||
public const string SkipFill = "--skip-fill";
|
||||
public const string ISO9660Trim = "--iso9660-trim";
|
||||
|
||||
// Miscellaneous
|
||||
public const string LBAStart = "--lba-start";
|
||||
public const string LBAEnd = "--lba-end";
|
||||
public const string RefineSubchannel = "--refine-subchannel";
|
||||
public const string Skip = "--skip";
|
||||
public const string DumpWriteOffset = "--dump-write-offset";
|
||||
public const string DumpReadSize = "--dump-read-size";
|
||||
public const string OverreadLeadout = "--overread-leadout";
|
||||
public const string LegacySubs = "--legacy-subs";
|
||||
public const string DisableCDText = "--disable-cdtext";
|
||||
}
|
||||
}
|
||||
28
MPF.Core/Modules/Redumper/Converters.cs
Normal file
28
MPF.Core/Modules/Redumper/Converters.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Modules.Redumper
|
||||
{
|
||||
public static class Converters
|
||||
{
|
||||
#region Cross-enumeration conversions
|
||||
|
||||
/// <summary>
|
||||
/// Get the default extension for a given disc type
|
||||
/// </summary>
|
||||
/// <param name="type">MediaType value to check</param>
|
||||
/// <returns>Valid extension (with leading '.'), null on error</returns>
|
||||
public static string? Extension(MediaType? type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
MediaType.CDROM => ".bin",
|
||||
MediaType.DVD
|
||||
or MediaType.HDDVD
|
||||
or MediaType.BluRay => ".iso",
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
2437
MPF.Core/Modules/Redumper/Parameters.cs
Normal file
2437
MPF.Core/Modules/Redumper/Parameters.cs
Normal file
File diff suppressed because it is too large
Load Diff
242
MPF.Core/Modules/UmdImageCreator/Parameters.cs
Normal file
242
MPF.Core/Modules/UmdImageCreator/Parameters.cs
Normal file
@@ -0,0 +1,242 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Data;
|
||||
using SabreTools.Hashing;
|
||||
using SabreTools.RedumpLib;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Modules.UmdImageCreator
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic set of UmdImageCreator parameters
|
||||
/// </summary>
|
||||
public class Parameters : BaseParameters
|
||||
{
|
||||
#region Metadata
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override InternalProgram InternalProgram => InternalProgram.UmdImageCreator;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(string? parameters) : base(parameters) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(RedumpSystem? system, MediaType? type, string? drivePath, string filename, int? driveSpeed, Options options)
|
||||
: base(system, type, drivePath, filename, driveSpeed, options)
|
||||
{
|
||||
}
|
||||
|
||||
#region BaseParameters Implementations
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override (bool, List<string>) CheckAllOutputFilesExist(string basePath, bool preCheck)
|
||||
{
|
||||
var missingFiles = new List<string>();
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.UMD:
|
||||
if (!File.Exists($"{basePath}_logs.zip") || !preCheck)
|
||||
{
|
||||
if (!File.Exists($"{basePath}_disc.txt"))
|
||||
missingFiles.Add($"{basePath}_disc.txt");
|
||||
if (!File.Exists($"{basePath}_mainError.txt"))
|
||||
missingFiles.Add($"{basePath}_mainError.txt");
|
||||
if (!File.Exists($"{basePath}_mainInfo.txt"))
|
||||
missingFiles.Add($"{basePath}_mainInfo.txt");
|
||||
if (!File.Exists($"{basePath}_volDesc.txt"))
|
||||
missingFiles.Add($"{basePath}_volDesc.txt");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
missingFiles.Add("Media and system combination not supported for UmdImageCreator");
|
||||
break;
|
||||
}
|
||||
|
||||
return (!missingFiles.Any(), missingFiles);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive? drive, bool includeArtifacts)
|
||||
{
|
||||
// Ensure that required sections exist
|
||||
info = Builder.EnsureAllSections(info);
|
||||
|
||||
// TODO: Determine if there's a UMDImageCreator version anywhere
|
||||
info.DumpingInfo!.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
|
||||
info.DumpingInfo.DumpingDate = InfoTool.GetFileModifiedDate(basePath + "_disc.txt")?.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
// Extract info based generically on MediaType
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.UMD:
|
||||
info.Extras!.PVD = GetPVD(basePath + "_mainInfo.txt") ?? string.Empty;
|
||||
|
||||
if (HashTool.GetStandardHashes(basePath + ".iso", out long filesize, out var crc32, out var md5, out var sha1))
|
||||
{
|
||||
// Get the Datafile information
|
||||
var datafile = new Datafile
|
||||
{
|
||||
Games = [new Game { Roms = [new Rom { Name = string.Empty, Size = filesize.ToString(), Crc = crc32, Md5 = md5, Sha1 = sha1, }] }]
|
||||
};
|
||||
|
||||
// Fill in the hash data
|
||||
info.TracksAndWriteOffsets!.ClrMameProData = InfoTool.GenerateDatfile(datafile);
|
||||
|
||||
info.SizeAndChecksums!.Size = filesize;
|
||||
info.SizeAndChecksums.CRC32 = crc32;
|
||||
info.SizeAndChecksums.MD5 = md5;
|
||||
info.SizeAndChecksums.SHA1 = sha1;
|
||||
}
|
||||
|
||||
if (GetUMDAuxInfo(basePath + "_disc.txt", out var title, out DiscCategory? umdcat, out var umdversion, out var umdlayer, out long umdsize))
|
||||
{
|
||||
info.CommonDiscInfo!.Title = title ?? string.Empty;
|
||||
info.CommonDiscInfo.Category = umdcat ?? DiscCategory.Games;
|
||||
info.VersionAndEditions!.Version = umdversion ?? string.Empty;
|
||||
info.SizeAndChecksums!.Size = umdsize;
|
||||
|
||||
if (!string.IsNullOrEmpty(umdlayer))
|
||||
info.SizeAndChecksums.Layerbreak = Int64.Parse(umdlayer ?? "-1");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill in any artifacts that exist, Base64-encoded, if we need to
|
||||
if (includeArtifacts)
|
||||
{
|
||||
info.Artifacts ??= [];
|
||||
|
||||
if (File.Exists(basePath + "_disc.txt"))
|
||||
info.Artifacts["disc"] = GetBase64(GetFullFile(basePath + "_disc.txt")) ?? string.Empty;
|
||||
if (File.Exists(basePath + "_drive.txt"))
|
||||
info.Artifacts["drive"] = GetBase64(GetFullFile(basePath + "_drive.txt")) ?? string.Empty;
|
||||
if (File.Exists(basePath + "_mainError.txt"))
|
||||
info.Artifacts["mainError"] = GetBase64(GetFullFile(basePath + "_mainError.txt")) ?? string.Empty;
|
||||
if (File.Exists(basePath + "_mainInfo.txt"))
|
||||
info.Artifacts["mainInfo"] = GetBase64(GetFullFile(basePath + "_mainInfo.txt")) ?? string.Empty;
|
||||
if (File.Exists(basePath + "_volDesc.txt"))
|
||||
info.Artifacts["volDesc"] = GetBase64(GetFullFile(basePath + "_volDesc.txt")) ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<string> GetLogFilePaths(string basePath)
|
||||
{
|
||||
var logFiles = new List<string>();
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.UMD:
|
||||
if (File.Exists($"{basePath}_disc.txt"))
|
||||
logFiles.Add($"{basePath}_disc.txt");
|
||||
if (File.Exists($"{basePath}_drive.txt"))
|
||||
logFiles.Add($"{basePath}_drive.txt");
|
||||
if (File.Exists($"{basePath}_mainError.txt"))
|
||||
logFiles.Add($"{basePath}_mainError.txt");
|
||||
if (File.Exists($"{basePath}_mainInfo.txt"))
|
||||
logFiles.Add($"{basePath}_mainInfo.txt");
|
||||
if (File.Exists($"{basePath}_volDesc.txt"))
|
||||
logFiles.Add($"{basePath}_volDesc.txt");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return logFiles;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Information Extraction Methods
|
||||
|
||||
/// <summary>
|
||||
/// Get the PVD from the input file, if possible
|
||||
/// </summary>
|
||||
/// <param name="mainInfo">_mainInfo.txt file location</param>
|
||||
/// <returns>Newline-deliminated PVD if possible, null on error</returns>
|
||||
private static string? GetPVD(string mainInfo)
|
||||
{
|
||||
// If the file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(mainInfo))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
// Make sure we're in the right sector
|
||||
using var sr = File.OpenText(mainInfo);
|
||||
while (sr.ReadLine()?.StartsWith("========== LBA[000016, 0x0000010]: Main Channel ==========") == false) ;
|
||||
|
||||
// Fast forward to the PVD
|
||||
while (sr.ReadLine()?.StartsWith("0310") == false) ;
|
||||
|
||||
// Now that we're at the PVD, read each line in and concatenate
|
||||
string pvd = "";
|
||||
for (int i = 0; i < 6; i++)
|
||||
pvd += sr.ReadLine() + "\n"; // 320-370
|
||||
|
||||
return pvd;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the exception is right now
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the UMD auxiliary info from the outputted files, if possible
|
||||
/// </summary>
|
||||
/// <param name="disc">_disc.txt file location</param>
|
||||
/// <returns>True on successful extraction of info, false otherwise</returns>
|
||||
private static bool GetUMDAuxInfo(string disc, out string? title, out DiscCategory? umdcat, out string? umdversion, out string? umdlayer, out long umdsize)
|
||||
{
|
||||
title = null; umdcat = null; umdversion = null; umdlayer = null; umdsize = -1;
|
||||
|
||||
// If the file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(disc))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
// Loop through everything to get the first instance of each required field
|
||||
using var sr = File.OpenText(disc);
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
string? line = sr.ReadLine()?.Trim();
|
||||
if (line == null)
|
||||
break;
|
||||
|
||||
if (line.StartsWith("TITLE") && title == null)
|
||||
title = line.Substring("TITLE: ".Length);
|
||||
else if (line.StartsWith("DISC_VERSION") && umdversion == null)
|
||||
umdversion = line.Split(' ')[1];
|
||||
else if (line.StartsWith("pspUmdTypes"))
|
||||
umdcat = InfoTool.GetUMDCategory(line.Split(' ')[1]);
|
||||
else if (line.StartsWith("L0 length"))
|
||||
umdlayer = line.Split(' ')[2];
|
||||
else if (line.StartsWith("FileSize:"))
|
||||
umdsize = Int64.Parse(line.Split(' ')[1]);
|
||||
}
|
||||
|
||||
// If the L0 length is the size of the full disc, there's no layerbreak
|
||||
if (Int64.TryParse(umdlayer, out long umdlayerValue) && umdlayerValue * 2048 == umdsize)
|
||||
umdlayer = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the exception is right now
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
398
MPF.Core/Protection.cs
Normal file
398
MPF.Core/Protection.cs
Normal file
@@ -0,0 +1,398 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using psxt001z;
|
||||
|
||||
#pragma warning disable SYSLIB1045 // Convert to 'GeneratedRegexAttribute'.
|
||||
|
||||
namespace MPF.Core
|
||||
{
|
||||
public static class Protection
|
||||
{
|
||||
/// <summary>
|
||||
/// Run protection scan on a given path
|
||||
/// </summary>
|
||||
/// <param name="path">Path to scan for protection</param>
|
||||
/// <param name="options">Options object that determines what to scan</param>
|
||||
/// <param name="progress">Optional progress callback</param>
|
||||
/// <returns>Set of all detected copy protections with an optional error string</returns>
|
||||
public static async Task<(Dictionary<string, List<string>>?, string?)> RunProtectionScanOnPath(string path, Data.Options options, IProgress<BinaryObjectScanner.ProtectionProgress>? progress = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
#if NET40
|
||||
var found = await Task.Factory.StartNew(() =>
|
||||
{
|
||||
var scanner = new BinaryObjectScanner.Scanner(
|
||||
options.ScanArchivesForProtection,
|
||||
scanContents: true, // Hardcoded value to avoid issues
|
||||
scanGameEngines: false, // Hardcoded value to avoid issues
|
||||
options.ScanPackersForProtection,
|
||||
scanPaths: true, // Hardcoded value to avoid issues
|
||||
options.IncludeDebugProtectionInformation,
|
||||
progress);
|
||||
|
||||
return scanner.GetProtections(path);
|
||||
});
|
||||
#else
|
||||
var found = await Task.Run(() =>
|
||||
{
|
||||
var scanner = new BinaryObjectScanner.Scanner(
|
||||
options.ScanArchivesForProtection,
|
||||
scanContents: true, // Hardcoded value to avoid issues
|
||||
scanGameEngines: false, // Hardcoded value to avoid issues
|
||||
options.ScanPackersForProtection,
|
||||
scanPaths: true, // Hardcoded value to avoid issues
|
||||
options.IncludeDebugProtectionInformation,
|
||||
progress);
|
||||
|
||||
return scanner.GetProtections(path);
|
||||
});
|
||||
#endif
|
||||
|
||||
// If nothing was returned, return
|
||||
#if NET20 || NET35
|
||||
if (found == null || found.Count == 0)
|
||||
#else
|
||||
if (found == null || found.IsEmpty)
|
||||
#endif
|
||||
return (null, null);
|
||||
|
||||
// Filter out any empty protections
|
||||
var filteredProtections = found
|
||||
#if NET20 || NET35
|
||||
.Where(kvp => kvp.Value != null && kvp.Value.Count > 0)
|
||||
#else
|
||||
.Where(kvp => kvp.Value != null && !kvp.Value.IsEmpty)
|
||||
#endif
|
||||
.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value.OrderBy(s => s).ToList());
|
||||
|
||||
// Return the filtered set of protections
|
||||
return (filteredProtections, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (null, ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Format found protections to a deduplicated, ordered string
|
||||
/// </summary>
|
||||
/// <param name="protections">Dictionary of file to list of protection mappings</param>
|
||||
/// <returns>Detected protections, if any</returns>
|
||||
public static string? FormatProtections(Dictionary<string, List<string>>? protections)
|
||||
{
|
||||
// If the filtered list is empty in some way, return
|
||||
if (protections == null || !protections.Any())
|
||||
return "None found [OMIT FROM SUBMISSION]";
|
||||
|
||||
// Get an ordered list of distinct found protections
|
||||
var orderedDistinctProtections = protections
|
||||
.SelectMany(kvp => kvp.Value)
|
||||
.Distinct()
|
||||
.OrderBy(p => p);
|
||||
|
||||
// Sanitize and join protections for writing
|
||||
string protectionString = SanitizeFoundProtections(orderedDistinctProtections);
|
||||
if (string.IsNullOrEmpty(protectionString))
|
||||
return "None found [OMIT FROM SUBMISSION]";
|
||||
|
||||
return protectionString;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the existence of an anti-modchip string from a PlayStation disc, if possible
|
||||
/// </summary>
|
||||
/// <param name="path">Path to scan for anti-modchip strings</param>
|
||||
/// <returns>Anti-modchip existence if possible, false on error</returns>
|
||||
public static async Task<bool> GetPlayStationAntiModchipDetected(string? path)
|
||||
{
|
||||
// If there is no valid path
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return false;
|
||||
|
||||
#if NET40
|
||||
return await Task.Factory.StartNew(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var antiModchip = new BinaryObjectScanner.Protection.PSXAntiModchip();
|
||||
foreach (string file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] fileContent = File.ReadAllBytes(file);
|
||||
var protection = antiModchip.CheckContents(file, fileContent, false);
|
||||
if (!string.IsNullOrEmpty(protection))
|
||||
return true;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
return false;
|
||||
});
|
||||
#else
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var antiModchip = new BinaryObjectScanner.Protection.PSXAntiModchip();
|
||||
#if NET20 || NET35
|
||||
foreach (string file in Directory.GetFiles(path, "*", SearchOption.AllDirectories))
|
||||
#else
|
||||
foreach (string file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories))
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] fileContent = File.ReadAllBytes(file);
|
||||
var protection = antiModchip.CheckContents(file, fileContent, false);
|
||||
if (!string.IsNullOrEmpty(protection))
|
||||
return true;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
return false;
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get if LibCrypt data is detected in the subchannel file, if possible
|
||||
/// </summary>
|
||||
/// <param name="sub">.sub file location</param>
|
||||
/// <returns>Status of the LibCrypt data, if possible</returns>
|
||||
public static bool? GetLibCryptDetected(string sub)
|
||||
{
|
||||
// If the file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(sub))
|
||||
return null;
|
||||
|
||||
return LibCrypt.DetectLibCrypt([sub]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sanitize unnecessary protection duplication from output
|
||||
/// </summary>
|
||||
/// <param name="foundProtections">Enumerable of found protections</param>
|
||||
public static string SanitizeFoundProtections(IEnumerable<string> foundProtections)
|
||||
{
|
||||
// EXCEPTIONS
|
||||
if (foundProtections.Any(p => p.StartsWith("[Exception opening file")))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => !p.StartsWith("[Exception opening file"));
|
||||
#if NET20 || NET35 || NET40 || NET452 || NET462
|
||||
var tempList = new List<string> { "Exception occurred while scanning [RESCAN NEEDED]" };
|
||||
tempList.AddRange(foundProtections);
|
||||
foundProtections = tempList.OrderBy(p => p);
|
||||
#else
|
||||
foundProtections = foundProtections
|
||||
.Prepend("Exception occurred while scanning [RESCAN NEEDED]")
|
||||
.OrderBy(p => p);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ActiveMARK
|
||||
if (foundProtections.Any(p => p == "ActiveMARK 5") && foundProtections.Any(p => p == "ActiveMARK"))
|
||||
foundProtections = foundProtections.Where(p => p != "ActiveMARK");
|
||||
|
||||
// Cactus Data Shield
|
||||
if (foundProtections.Any(p => Regex.IsMatch(p, @"Cactus Data Shield [0-9]{3} .+", RegexOptions.Compiled)) && foundProtections.Any(p => p == "Cactus Data Shield 200"))
|
||||
foundProtections = foundProtections.Where(p => p != "Cactus Data Shield 200");
|
||||
|
||||
// CD-Check
|
||||
foundProtections = foundProtections.Where(p => p != "Executable-Based CD Check");
|
||||
|
||||
// CD-Cops
|
||||
if (foundProtections.Any(p => p == "CD-Cops") && foundProtections.Any(p => p.StartsWith("CD-Cops") && p.Length > "CD-Cops".Length))
|
||||
foundProtections = foundProtections.Where(p => p != "CD-Cops");
|
||||
|
||||
// CD-Key / Serial
|
||||
foundProtections = foundProtections.Where(p => p != "CD-Key / Serial");
|
||||
|
||||
// Electronic Arts
|
||||
if (foundProtections.Any(p => p == "EA CdKey Registration Module") && foundProtections.Any(p => p.StartsWith("EA CdKey Registration Module") && p.Length > "EA CdKey Registration Module".Length))
|
||||
foundProtections = foundProtections.Where(p => p != "EA CdKey Registration Module");
|
||||
if (foundProtections.Any(p => p == "EA DRM Protection") && foundProtections.Any(p => p.StartsWith("EA DRM Protection") && p.Length > "EA DRM Protection".Length))
|
||||
foundProtections = foundProtections.Where(p => p != "EA DRM Protection");
|
||||
|
||||
// Games for Windows LIVE
|
||||
if (foundProtections.Any(p => p == "Games for Windows LIVE") && foundProtections.Any(p => p.StartsWith("Games for Windows LIVE") && !p.Contains("Zero Day Piracy Protection") && p.Length > "Games for Windows LIVE".Length))
|
||||
foundProtections = foundProtections.Where(p => p != "Games for Windows LIVE");
|
||||
|
||||
// Impulse Reactor
|
||||
if (foundProtections.Any(p => p.StartsWith("Impulse Reactor Core Module")) && foundProtections.Any(p => p == "Impulse Reactor"))
|
||||
foundProtections = foundProtections.Where(p => p != "Impulse Reactor");
|
||||
|
||||
// JoWood X-Prot
|
||||
if (foundProtections.Any(p => p.StartsWith("JoWood X-Prot")))
|
||||
{
|
||||
if (foundProtections.Any(p => Regex.IsMatch(p, @"JoWood X-Prot [0-9]\.[0-9]\.[0-9]\.[0-9]{2}", RegexOptions.Compiled)))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "JoWood X-Prot")
|
||||
.Where(p => p != "JoWood X-Prot v1.0-v1.3")
|
||||
.Where(p => p != "JoWood X-Prot v1.4+")
|
||||
.Where(p => p != "JoWood X-Prot v2");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "JoWood X-Prot v2"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "JoWood X-Prot")
|
||||
.Where(p => p != "JoWood X-Prot v1.0-v1.3")
|
||||
.Where(p => p != "JoWood X-Prot v1.4+");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "JoWood X-Prot v1.4+"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "JoWood X-Prot")
|
||||
.Where(p => p != "JoWood X-Prot v1.0-v1.3");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "JoWood X-Prot v1.0-v1.3"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "JoWood X-Prot");
|
||||
}
|
||||
}
|
||||
|
||||
// LaserLok
|
||||
// TODO: Figure this one out
|
||||
|
||||
// Online Registration
|
||||
foundProtections = foundProtections.Where(p => !p.StartsWith("Executable-Based Online Registration"));
|
||||
|
||||
// ProtectDISC / VOB ProtectCD/DVD
|
||||
// TODO: Figure this one out
|
||||
|
||||
// SafeCast
|
||||
// TODO: Figure this one out
|
||||
|
||||
// Cactus Data Shield / SafeDisc
|
||||
if (foundProtections.Any(p => p == "Cactus Data Shield 300 (Confirm presence of other CDS-300 files)"))
|
||||
{
|
||||
foundProtections = foundProtections
|
||||
.Where(p => p != "Cactus Data Shield 300 (Confirm presence of other CDS-300 files)");
|
||||
|
||||
if (foundProtections.Any(p => !p.StartsWith("SafeDisc")))
|
||||
{
|
||||
#if NET20 || NET35 || NET40 || NET452 || NET462
|
||||
var tempList = new List<string>();
|
||||
tempList.AddRange(foundProtections);
|
||||
tempList.Add("Cactus Data Shield 300");
|
||||
foundProtections = tempList;
|
||||
#else
|
||||
foundProtections = foundProtections.Append("Cactus Data Shield 300");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// SafeDisc
|
||||
if (foundProtections.Any(p => p.StartsWith("SafeDisc")))
|
||||
{
|
||||
if (foundProtections.Any(p => Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled)))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => !p.StartsWith("Macrovision Protected Application"))
|
||||
.Where(p => !p.StartsWith("Macrovision Protection File"))
|
||||
.Where(p => !p.StartsWith("Macrovision Security Driver"))
|
||||
.Where(p => p != "SafeDisc")
|
||||
.Where(p => !(Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}-[0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled)))
|
||||
.Where(p => !(Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}/+", RegexOptions.Compiled)))
|
||||
.Where(p => p != "SafeDisc 1/Lite")
|
||||
.Where(p => p != "SafeDisc 2+");
|
||||
}
|
||||
else if (foundProtections.Any(p => Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}-[0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled)))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => !p.StartsWith("Macrovision Protected Application"))
|
||||
.Where(p => !p.StartsWith("Macrovision Protection File"))
|
||||
.Where(p => !p.StartsWith("Macrovision Security Driver"))
|
||||
.Where(p => p != "SafeDisc")
|
||||
.Where(p => !(Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}/+", RegexOptions.Compiled)))
|
||||
.Where(p => p != "SafeDisc 1/Lite")
|
||||
.Where(p => p != "SafeDisc 2+");
|
||||
}
|
||||
else if (foundProtections.Any(p => Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}/+", RegexOptions.Compiled)))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => !p.StartsWith("Macrovision Protected Application"))
|
||||
.Where(p => !p.StartsWith("Macrovision Protection File"))
|
||||
.Where(p => !p.StartsWith("Macrovision Security Driver"))
|
||||
.Where(p => p != "SafeDisc")
|
||||
.Where(p => p != "SafeDisc 1/Lite")
|
||||
.Where(p => p != "SafeDisc 2+");
|
||||
}
|
||||
else if (foundProtections.Any(p => p.StartsWith("Macrovision Security Driver")))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => !p.StartsWith("Macrovision Protected Application"))
|
||||
.Where(p => !p.StartsWith("Macrovision Protection File"))
|
||||
.Where(p => p != "SafeDisc")
|
||||
.Where(p => p != "SafeDisc 1/Lite")
|
||||
.Where(p => p != "SafeDisc 2+");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "SafeDisc 2+"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => !p.StartsWith("Macrovision Protected Application"))
|
||||
.Where(p => !p.StartsWith("Macrovision Protection File"))
|
||||
.Where(p => p != "SafeDisc");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "SafeDisc 1/Lite"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => !p.StartsWith("Macrovision Protected Application"))
|
||||
.Where(p => !p.StartsWith("Macrovision Protection File"))
|
||||
.Where(p => p != "SafeDisc");
|
||||
}
|
||||
}
|
||||
|
||||
// SecuROM
|
||||
// TODO: Figure this one out
|
||||
|
||||
// SolidShield
|
||||
// TODO: Figure this one out
|
||||
|
||||
// StarForce
|
||||
if (foundProtections.Any(p => p.StartsWith("StarForce")))
|
||||
{
|
||||
if (foundProtections.Any(p => Regex.IsMatch(p, @"StarForce [0-9]+\..+", RegexOptions.Compiled)))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "StarForce")
|
||||
.Where(p => p != "StarForce 3-5")
|
||||
.Where(p => p != "StarForce 5")
|
||||
.Where(p => p != "StarForce 5 [Protected Module]");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "StarForce 5 [Protected Module]"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "StarForce")
|
||||
.Where(p => p != "StarForce 3-5")
|
||||
.Where(p => p != "StarForce 5");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "StarForce 5"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "StarForce")
|
||||
.Where(p => p != "StarForce 3-5");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "StarForce 3-5"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "StarForce");
|
||||
}
|
||||
}
|
||||
|
||||
// Sysiphus
|
||||
if (foundProtections.Any(p => p == "Sysiphus") && foundProtections.Any(p => p.StartsWith("Sysiphus") && p.Length > "Sysiphus".Length))
|
||||
foundProtections = foundProtections.Where(p => p != "Sysiphus");
|
||||
|
||||
// TAGES
|
||||
// TODO: Figure this one out
|
||||
|
||||
// XCP
|
||||
if (foundProtections.Any(p => p == "XCP") && foundProtections.Any(p => p.StartsWith("XCP") && p.Length > "XCP".Length))
|
||||
foundProtections = foundProtections.Where(p => p != "XCP");
|
||||
|
||||
return string.Join(", ", foundProtections.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
743
MPF.Core/SubmissionInfoTool.cs
Normal file
743
MPF.Core/SubmissionInfoTool.cs
Normal file
@@ -0,0 +1,743 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.Modules;
|
||||
using SabreTools.RedumpLib;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
using SabreTools.RedumpLib.Web;
|
||||
|
||||
namespace MPF.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Class to hold all SubmissionInfo-related methods
|
||||
/// </summary>
|
||||
internal static class SubmissionInfoTool
|
||||
{
|
||||
#region Extraction and Filling
|
||||
|
||||
/// <summary>
|
||||
/// Extract all of the possible information from a given input combination
|
||||
/// </summary>
|
||||
/// <param name="outputPath">Output path to write to</param>
|
||||
/// <param name="drive">Drive object representing the current drive</param>
|
||||
/// <param name="system">Currently selected system</param>
|
||||
/// <param name="mediaType">Currently selected media type</param>
|
||||
/// <param name="options">Options object representing user-defined options</param>
|
||||
/// <param name="parameters">Parameters object representing what to send to the internal program</param>
|
||||
/// <param name="resultProgress">Optional result progress callback</param>
|
||||
/// <param name="protectionProgress">Optional protection progress callback</param>
|
||||
/// <returns>SubmissionInfo populated based on outputs, null on error</returns>
|
||||
public static async Task<SubmissionInfo?> ExtractOutputInformation(
|
||||
string outputPath,
|
||||
Drive? drive,
|
||||
RedumpSystem? system,
|
||||
MediaType? mediaType,
|
||||
Options options,
|
||||
BaseParameters? parameters,
|
||||
IProgress<Result>? resultProgress = null,
|
||||
IProgress<BinaryObjectScanner.ProtectionProgress>? protectionProgress = null)
|
||||
{
|
||||
// Ensure the current disc combination should exist
|
||||
if (!system.MediaTypes().Contains(mediaType))
|
||||
return null;
|
||||
|
||||
// Split the output path for easier use
|
||||
var outputDirectory = Path.GetDirectoryName(outputPath);
|
||||
string outputFilename = Path.GetFileName(outputPath);
|
||||
|
||||
// Check that all of the relevant files are there
|
||||
(bool foundFiles, List<string> missingFiles) = parameters.FoundAllFiles(outputDirectory, outputFilename, false);
|
||||
if (!foundFiles)
|
||||
{
|
||||
resultProgress?.Report(Result.Failure($"There were files missing from the output:\n{string.Join("\n", [.. missingFiles])}"));
|
||||
resultProgress?.Report(Result.Failure($"This may indicate an issue with the hardware or media, including unsupported devices.\nPlease see dumping program documentation for more details."));
|
||||
return null;
|
||||
}
|
||||
|
||||
// Sanitize the output filename to strip off any potential extension
|
||||
outputFilename = Path.GetFileNameWithoutExtension(outputFilename);
|
||||
|
||||
// Create the SubmissionInfo object with all user-inputted values by default
|
||||
string combinedBase;
|
||||
if (string.IsNullOrEmpty(outputDirectory))
|
||||
combinedBase = outputFilename;
|
||||
else
|
||||
combinedBase = Path.Combine(outputDirectory, outputFilename);
|
||||
|
||||
var info = new SubmissionInfo()
|
||||
{
|
||||
CommonDiscInfo = new CommonDiscInfoSection()
|
||||
{
|
||||
System = system,
|
||||
Media = mediaType.ToDiscType(),
|
||||
Title = options.AddPlaceholders ? Template.RequiredValue : string.Empty,
|
||||
ForeignTitleNonLatin = options.AddPlaceholders ? Template.OptionalValue : string.Empty,
|
||||
DiscNumberLetter = options.AddPlaceholders ? Template.OptionalValue : string.Empty,
|
||||
DiscTitle = options.AddPlaceholders ? Template.OptionalValue : string.Empty,
|
||||
Category = null,
|
||||
Region = null,
|
||||
Languages = null,
|
||||
Serial = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty,
|
||||
Barcode = options.AddPlaceholders ? Template.OptionalValue : string.Empty,
|
||||
Contents = string.Empty,
|
||||
},
|
||||
VersionAndEditions = new VersionAndEditionsSection()
|
||||
{
|
||||
Version = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty,
|
||||
OtherEditions = options.AddPlaceholders ? "(VERIFY THIS) Original" : string.Empty,
|
||||
},
|
||||
DumpingInfo = new DumpingInfoSection()
|
||||
{
|
||||
FrontendVersion = Utilities.Tools.GetCurrentVersion(),
|
||||
},
|
||||
};
|
||||
|
||||
// Ensure that required sections exist
|
||||
info = Builder.EnsureAllSections(info);
|
||||
|
||||
// Get specific tool output handling
|
||||
parameters?.GenerateSubmissionInfo(info, options, combinedBase, drive, options.IncludeArtifacts);
|
||||
|
||||
// Get a list of matching IDs for each line in the DAT
|
||||
if (!string.IsNullOrEmpty(info.TracksAndWriteOffsets!.ClrMameProData) && options.HasRedumpLogin)
|
||||
#if NET40
|
||||
_ = FillFromRedump(options, info, resultProgress);
|
||||
#else
|
||||
_ = await FillFromRedump(options, info, resultProgress);
|
||||
#endif
|
||||
|
||||
// If we have both ClrMamePro and Size and Checksums data, remove the ClrMamePro
|
||||
if (!string.IsNullOrEmpty(info.SizeAndChecksums?.CRC32))
|
||||
info.TracksAndWriteOffsets.ClrMameProData = null;
|
||||
|
||||
// Add the volume label to comments, if possible or necessary
|
||||
string? volLabels = FormatVolumeLabels(drive?.VolumeLabel, parameters?.VolumeLabels);
|
||||
if (volLabels != null)
|
||||
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.VolumeLabel] = volLabels;
|
||||
|
||||
// Extract info based generically on MediaType
|
||||
switch (mediaType)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
case MediaType.GDROM:
|
||||
info.CommonDiscInfo!.Layer0MasteringRing = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0MasteringSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0ToolstampMasteringCode = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0MouldSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer1MouldSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0AdditionalMould = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
break;
|
||||
|
||||
case MediaType.DVD:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.BluRay:
|
||||
|
||||
// If we have a single-layer disc
|
||||
if (info.SizeAndChecksums!.Layerbreak == default)
|
||||
{
|
||||
info.CommonDiscInfo!.Layer0MasteringRing = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0MasteringSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0ToolstampMasteringCode = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0MouldSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer1MouldSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0AdditionalMould = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
}
|
||||
// If we have a dual-layer disc
|
||||
else if (info.SizeAndChecksums!.Layerbreak2 == default)
|
||||
{
|
||||
info.CommonDiscInfo!.Layer0MasteringRing = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0MasteringSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0ToolstampMasteringCode = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0MouldSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0AdditionalMould = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
|
||||
info.CommonDiscInfo.Layer1MasteringRing = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer1MasteringSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer1ToolstampMasteringCode = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer1MouldSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
}
|
||||
// If we have a triple-layer disc
|
||||
else if (info.SizeAndChecksums!.Layerbreak3 == default)
|
||||
{
|
||||
info.CommonDiscInfo!.Layer0MasteringRing = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0MasteringSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0ToolstampMasteringCode = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0MouldSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0AdditionalMould = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
|
||||
info.CommonDiscInfo.Layer1MasteringRing = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer1MasteringSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer1ToolstampMasteringCode = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer1MouldSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
|
||||
info.CommonDiscInfo.Layer2MasteringRing = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer2MasteringSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer2ToolstampMasteringCode = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
}
|
||||
// If we have a quad-layer disc
|
||||
else
|
||||
{
|
||||
info.CommonDiscInfo!.Layer0MasteringRing = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0MasteringSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0ToolstampMasteringCode = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0MouldSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0AdditionalMould = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
|
||||
info.CommonDiscInfo.Layer1MasteringRing = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer1MasteringSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer1ToolstampMasteringCode = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer1MouldSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
|
||||
info.CommonDiscInfo.Layer2MasteringRing = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer2MasteringSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer2ToolstampMasteringCode = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
|
||||
info.CommonDiscInfo.Layer3MasteringRing = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer3MasteringSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer3ToolstampMasteringCode = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
info.CommonDiscInfo!.Layer0MasteringRing = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0MasteringSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0ToolstampMasteringCode = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0MouldSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer1MouldSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0AdditionalMould = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.Extras!.BCA ??= (options.AddPlaceholders ? Template.RequiredValue : string.Empty);
|
||||
break;
|
||||
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
|
||||
// If we have a single-layer disc
|
||||
if (info.SizeAndChecksums!.Layerbreak == default)
|
||||
{
|
||||
info.CommonDiscInfo!.Layer0MasteringRing = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0MasteringSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0ToolstampMasteringCode = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0MouldSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer1MouldSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0AdditionalMould = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
}
|
||||
// If we have a dual-layer disc
|
||||
else
|
||||
{
|
||||
info.CommonDiscInfo!.Layer0MasteringRing = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0MasteringSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0ToolstampMasteringCode = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0MouldSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0AdditionalMould = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
|
||||
info.CommonDiscInfo.Layer1MasteringRing = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer1MasteringSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer1ToolstampMasteringCode = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer1MouldSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
}
|
||||
|
||||
info.Extras!.DiscKey = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.Extras.BCA = info.Extras.BCA ?? (options.AddPlaceholders ? Template.RequiredValue : string.Empty);
|
||||
|
||||
break;
|
||||
|
||||
case MediaType.UMD:
|
||||
// Both single- and dual-layer discs have two "layers" for the ring
|
||||
info.CommonDiscInfo!.Layer0MasteringRing = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0MasteringSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0ToolstampMasteringCode = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer0MouldSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
|
||||
info.CommonDiscInfo.Layer1MasteringRing = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer1MasteringSID = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CommonDiscInfo.Layer1ToolstampMasteringCode = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
|
||||
info.SizeAndChecksums!.CRC32 ??= (options.AddPlaceholders ? Template.RequiredValue + " [Not automatically generated for UMD]" : string.Empty);
|
||||
info.SizeAndChecksums.MD5 ??= (options.AddPlaceholders ? Template.RequiredValue + " [Not automatically generated for UMD]" : string.Empty);
|
||||
info.SizeAndChecksums.SHA1 ??= (options.AddPlaceholders ? Template.RequiredValue + " [Not automatically generated for UMD]" : string.Empty);
|
||||
info.TracksAndWriteOffsets.ClrMameProData = null;
|
||||
break;
|
||||
}
|
||||
|
||||
// Extract info based specifically on RedumpSystem
|
||||
switch (system)
|
||||
{
|
||||
case RedumpSystem.AcornArchimedes:
|
||||
info.CommonDiscInfo!.Region ??= Region.UnitedKingdom;
|
||||
break;
|
||||
|
||||
case RedumpSystem.AppleMacintosh:
|
||||
case RedumpSystem.EnhancedCD:
|
||||
case RedumpSystem.IBMPCcompatible:
|
||||
case RedumpSystem.PalmOS:
|
||||
case RedumpSystem.PocketPC:
|
||||
case RedumpSystem.RainbowDisc:
|
||||
case RedumpSystem.SonyElectronicBook:
|
||||
resultProgress?.Report(Result.Success("Running copy protection scan... this might take a while!"));
|
||||
var (protectionString, fullProtections) = await InfoTool.GetCopyProtection(drive, options, protectionProgress);
|
||||
|
||||
info.CopyProtection!.Protection += protectionString;
|
||||
info.CopyProtection.FullProtections = fullProtections as Dictionary<string, List<string>?> ?? [];
|
||||
resultProgress?.Report(Result.Success("Copy protection scan complete!"));
|
||||
|
||||
break;
|
||||
|
||||
case RedumpSystem.AudioCD:
|
||||
case RedumpSystem.DVDAudio:
|
||||
case RedumpSystem.SuperAudioCD:
|
||||
info.CommonDiscInfo!.Category ??= DiscCategory.Audio;
|
||||
break;
|
||||
|
||||
case RedumpSystem.BandaiPlaydiaQuickInteractiveSystem:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? Region.Japan;
|
||||
break;
|
||||
|
||||
case RedumpSystem.BDVideo:
|
||||
info.CommonDiscInfo!.Category ??= DiscCategory.BonusDiscs;
|
||||
info.CopyProtection!.Protection = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.CommodoreAmigaCD:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.CommodoreAmigaCD32:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo.Region ??= Region.Europe;
|
||||
break;
|
||||
|
||||
case RedumpSystem.CommodoreAmigaCDTV:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo.Region ??= Region.Europe;
|
||||
break;
|
||||
|
||||
case RedumpSystem.DVDVideo:
|
||||
info.CommonDiscInfo!.Category ??= DiscCategory.BonusDiscs;
|
||||
break;
|
||||
|
||||
case RedumpSystem.FujitsuFMTownsseries:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? Region.Japan;
|
||||
break;
|
||||
|
||||
case RedumpSystem.FujitsuFMTownsMarty:
|
||||
info.CommonDiscInfo!.Region ??= Region.Japan;
|
||||
break;
|
||||
|
||||
case RedumpSystem.IncredibleTechnologiesEagle:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.KonamieAmusement:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.KonamiFireBeat:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.KonamiSystemGV:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.KonamiSystem573:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.KonamiTwinkle:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.MattelHyperScan:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.MicrosoftXboxOne:
|
||||
if (drive?.Name != null)
|
||||
{
|
||||
string xboxOneMsxcPath = Path.Combine(drive.Name, "MSXC");
|
||||
if (drive != null && Directory.Exists(xboxOneMsxcPath))
|
||||
{
|
||||
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.Filename] = string.Join("\n",
|
||||
Directory.GetFiles(xboxOneMsxcPath, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName).ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RedumpSystem.MicrosoftXboxSeriesXS:
|
||||
if (drive?.Name != null)
|
||||
{
|
||||
string xboxSeriesXMsxcPath = Path.Combine(drive.Name, "MSXC");
|
||||
if (drive != null && Directory.Exists(xboxSeriesXMsxcPath))
|
||||
{
|
||||
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.Filename] = string.Join("\n",
|
||||
Directory.GetFiles(xboxSeriesXMsxcPath, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName).ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RedumpSystem.NamcoSegaNintendoTriforce:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.NavisoftNaviken21:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo.Region ??= Region.Japan;
|
||||
break;
|
||||
|
||||
case RedumpSystem.NECPC88series:
|
||||
info.CommonDiscInfo!.Region ??= Region.Japan;
|
||||
break;
|
||||
|
||||
case RedumpSystem.NECPC98series:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo!.Region ??= Region.Japan;
|
||||
break;
|
||||
|
||||
case RedumpSystem.NECPCFXPCFXGA:
|
||||
info.CommonDiscInfo!.Region ??= Region.Japan;
|
||||
break;
|
||||
|
||||
case RedumpSystem.SegaChihiro:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.SegaDreamcast:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.SegaNaomi:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.SegaNaomi2:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.SegaTitanVideo:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.SharpX68000:
|
||||
info.CommonDiscInfo!.Region ??= Region.Japan;
|
||||
break;
|
||||
|
||||
case RedumpSystem.SNKNeoGeoCD:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.SonyPlayStation:
|
||||
// Only check the disc if the dumping program couldn't detect
|
||||
if (drive != null && info.CopyProtection!.AntiModchip == YesNo.NULL)
|
||||
{
|
||||
resultProgress?.Report(Result.Success("Checking for anti-modchip strings... this might take a while!"));
|
||||
info.CopyProtection.AntiModchip = await InfoTool.GetAntiModchipDetected(drive) ? YesNo.Yes : YesNo.No;
|
||||
resultProgress?.Report(Result.Success("Anti-modchip string scan complete!"));
|
||||
}
|
||||
|
||||
// Special case for DIC only
|
||||
if (parameters?.InternalProgram == InternalProgram.DiscImageCreator)
|
||||
{
|
||||
resultProgress?.Report(Result.Success("Checking for LibCrypt status... this might take a while!"));
|
||||
InfoTool.GetLibCryptDetected(info, combinedBase);
|
||||
resultProgress?.Report(Result.Success("LibCrypt status checking complete!"));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RedumpSystem.SonyPlayStation2:
|
||||
info.CommonDiscInfo!.LanguageSelection = [LanguageSelection.BiosSettings, LanguageSelection.LanguageSelector, LanguageSelection.OptionsMenu];
|
||||
break;
|
||||
|
||||
case RedumpSystem.SonyPlayStation3:
|
||||
info.Extras!.DiscKey ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.Extras.DiscID ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.TomyKissSite:
|
||||
info.CommonDiscInfo!.Region ??= Region.Japan;
|
||||
break;
|
||||
|
||||
case RedumpSystem.ZAPiTGamesGameWaveFamilyEntertainmentSystem:
|
||||
info.CopyProtection!.Protection = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
break;
|
||||
}
|
||||
|
||||
// Set the category if it's not overriden
|
||||
info.CommonDiscInfo!.Category ??= DiscCategory.Games;
|
||||
|
||||
// Comments and contents have odd handling
|
||||
if (string.IsNullOrEmpty(info.CommonDiscInfo.Comments))
|
||||
info.CommonDiscInfo.Comments = options.AddPlaceholders ? Template.OptionalValue : string.Empty;
|
||||
if (string.IsNullOrEmpty(info.CommonDiscInfo.Contents))
|
||||
info.CommonDiscInfo.Contents = options.AddPlaceholders ? Template.OptionalValue : string.Empty;
|
||||
|
||||
// Normalize the disc type with all current information
|
||||
Validator.NormalizeDiscType(info);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill in a SubmissionInfo object from Redump, if possible
|
||||
/// </summary>
|
||||
/// <param name="options">Options object representing user-defined options</param>
|
||||
/// <param name="info">Existing SubmissionInfo object to fill</param>
|
||||
/// <param name="resultProgress">Optional result progress callback</param>
|
||||
#if NET40
|
||||
public static bool FillFromRedump(Options options, SubmissionInfo info, IProgress<Result>? resultProgress = null)
|
||||
#else
|
||||
public async static Task<bool> FillFromRedump(Options options, SubmissionInfo info, IProgress<Result>? resultProgress = null)
|
||||
#endif
|
||||
{
|
||||
// If no username is provided
|
||||
if (string.IsNullOrEmpty(options.RedumpUsername) || string.IsNullOrEmpty(options.RedumpPassword))
|
||||
return false;
|
||||
|
||||
// Set the current dumper based on username
|
||||
info.DumpersAndStatus ??= new DumpersAndStatusSection();
|
||||
info.DumpersAndStatus.Dumpers = [options.RedumpUsername!];
|
||||
info.PartiallyMatchedIDs = [];
|
||||
|
||||
// Login to Redump
|
||||
#if NETFRAMEWORK
|
||||
using var wc = new RedumpWebClient();
|
||||
bool? loggedIn = wc.Login(options.RedumpUsername!, options.RedumpPassword!);
|
||||
#else
|
||||
using var wc = new RedumpHttpClient();
|
||||
bool? loggedIn = await wc.Login(options.RedumpUsername, options.RedumpPassword);
|
||||
#endif
|
||||
if (loggedIn == null)
|
||||
{
|
||||
resultProgress?.Report(Result.Failure("There was an unknown error connecting to Redump"));
|
||||
return false;
|
||||
}
|
||||
else if (loggedIn == false)
|
||||
{
|
||||
// Don't log the as a failure or error
|
||||
return false;
|
||||
}
|
||||
|
||||
// Setup the full-track checks
|
||||
bool allFound = true;
|
||||
List<int>? fullyMatchedIDs = null;
|
||||
|
||||
// Loop through all of the hashdata to find matching IDs
|
||||
resultProgress?.Report(Result.Success("Finding disc matches on Redump..."));
|
||||
var splitData = info.TracksAndWriteOffsets?.ClrMameProData?.TrimEnd('\n')?.Split('\n');
|
||||
int trackCount = splitData?.Length ?? 0;
|
||||
foreach (string hashData in splitData ?? [])
|
||||
{
|
||||
// Catch any errant blank lines
|
||||
if (string.IsNullOrEmpty(hashData))
|
||||
{
|
||||
trackCount--;
|
||||
resultProgress?.Report(Result.Success("Blank line found, skipping!"));
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the line ends in a known extra track names, skip them for checking
|
||||
if (hashData.Contains("(Track 0).bin")
|
||||
|| hashData.Contains("(Track 0.2).bin")
|
||||
|| hashData.Contains("(Track 00).bin")
|
||||
|| hashData.Contains("(Track 00.2).bin")
|
||||
|| hashData.Contains("(Track A).bin")
|
||||
|| hashData.Contains("(Track A.2).bin")
|
||||
|| hashData.Contains("(Track AA).bin")
|
||||
|| hashData.Contains("(Track AA.2).bin"))
|
||||
{
|
||||
trackCount--;
|
||||
resultProgress?.Report(Result.Success("Extra track found, skipping!"));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the SHA-1 hash
|
||||
if (!InfoTool.GetISOHashValues(hashData, out _, out _, out _, out string? sha1))
|
||||
{
|
||||
resultProgress?.Report(Result.Failure($"Line could not be parsed: {hashData}"));
|
||||
continue;
|
||||
}
|
||||
|
||||
#if NET40
|
||||
var validateTask = Validator.ValidateSingleTrack(wc, info, sha1);
|
||||
validateTask.Wait();
|
||||
(bool singleFound, var foundIds, string? result) = validateTask.Result;
|
||||
#else
|
||||
(bool singleFound, var foundIds, string? result) = await Validator.ValidateSingleTrack(wc, info, sha1);
|
||||
#endif
|
||||
if (singleFound)
|
||||
resultProgress?.Report(Result.Success(result));
|
||||
else
|
||||
resultProgress?.Report(Result.Failure(result));
|
||||
|
||||
// Ensure that all tracks are found
|
||||
allFound &= singleFound;
|
||||
|
||||
// If we found a track, only keep track of distinct found tracks
|
||||
if (singleFound && foundIds != null)
|
||||
{
|
||||
if (fullyMatchedIDs == null)
|
||||
fullyMatchedIDs = foundIds;
|
||||
else
|
||||
fullyMatchedIDs = fullyMatchedIDs.Intersect(foundIds).ToList();
|
||||
}
|
||||
// If no tracks were found, remove all fully matched IDs found so far
|
||||
else
|
||||
{
|
||||
fullyMatchedIDs = [];
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't have any matches but we have a universal hash
|
||||
if (!info.PartiallyMatchedIDs.Any() && info.CommonDiscInfo?.CommentsSpecialFields?.ContainsKey(SiteCode.UniversalHash) == true)
|
||||
{
|
||||
#if NET40
|
||||
var validateTask = Validator.ValidateUniversalHash(wc, info);
|
||||
validateTask.Wait();
|
||||
(bool singleFound, var foundIds, string? result) = validateTask.Result;
|
||||
#else
|
||||
(bool singleFound, var foundIds, string? result) = await Validator.ValidateUniversalHash(wc, info);
|
||||
#endif
|
||||
if (singleFound)
|
||||
resultProgress?.Report(Result.Success(result));
|
||||
else
|
||||
resultProgress?.Report(Result.Failure(result));
|
||||
|
||||
// Ensure that the hash is found
|
||||
allFound = singleFound;
|
||||
|
||||
// If we found a track, only keep track of distinct found tracks
|
||||
if (singleFound && foundIds != null)
|
||||
{
|
||||
fullyMatchedIDs = foundIds;
|
||||
}
|
||||
// If no tracks were found, remove all fully matched IDs found so far
|
||||
else
|
||||
{
|
||||
fullyMatchedIDs = [];
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we only have unique IDs
|
||||
info.PartiallyMatchedIDs = [.. info.PartiallyMatchedIDs.Distinct().OrderBy(id => id)];
|
||||
|
||||
resultProgress?.Report(Result.Success("Match finding complete! " + (fullyMatchedIDs != null && fullyMatchedIDs.Count > 0
|
||||
? "Fully Matched IDs: " + string.Join(",", fullyMatchedIDs.Select(i => i.ToString()).ToArray())
|
||||
: "No matches found")));
|
||||
|
||||
// Exit early if one failed or there are no matched IDs
|
||||
if (!allFound || fullyMatchedIDs == null || fullyMatchedIDs.Count == 0)
|
||||
return false;
|
||||
|
||||
// Find the first matched ID where the track count matches, we can grab a bunch of info from it
|
||||
int totalMatchedIDsCount = fullyMatchedIDs.Count;
|
||||
for (int i = 0; i < totalMatchedIDsCount; i++)
|
||||
{
|
||||
// Skip if the track count doesn't match
|
||||
#if NET40
|
||||
var validateTask = Validator.ValidateTrackCount(wc, fullyMatchedIDs[i], trackCount);
|
||||
validateTask.Wait();
|
||||
if (!validateTask.Result)
|
||||
#else
|
||||
if (!await Validator.ValidateTrackCount(wc, fullyMatchedIDs[i], trackCount))
|
||||
#endif
|
||||
continue;
|
||||
|
||||
// Fill in the fields from the existing ID
|
||||
resultProgress?.Report(Result.Success($"Filling fields from existing ID {fullyMatchedIDs[i]}..."));
|
||||
#if NET40
|
||||
var fillTask = Task.Factory.StartNew(() => Builder.FillFromId(wc, info, fullyMatchedIDs[i], options.PullAllInformation));
|
||||
fillTask.Wait();
|
||||
_ = fillTask.Result;
|
||||
#else
|
||||
_ = await Builder.FillFromId(wc, info, fullyMatchedIDs[i], options.PullAllInformation);
|
||||
#endif
|
||||
resultProgress?.Report(Result.Success("Information filling complete!"));
|
||||
|
||||
// Set the fully matched ID to the current
|
||||
info.FullyMatchedID = fullyMatchedIDs[i];
|
||||
break;
|
||||
}
|
||||
|
||||
// Clear out fully matched IDs from the partial list
|
||||
if (info.FullyMatchedID.HasValue)
|
||||
{
|
||||
if (info.PartiallyMatchedIDs.Count == 1)
|
||||
info.PartiallyMatchedIDs = null;
|
||||
else
|
||||
info.PartiallyMatchedIDs.Remove(info.FullyMatchedID.Value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper Functions
|
||||
|
||||
/// <summary>
|
||||
/// Formats a list of volume labels and their corresponding filesystems
|
||||
/// </summary>
|
||||
/// <param name="labels">Dictionary of volume labels and their filesystems</param>
|
||||
/// <returns>Formatted string of volume labels and their filesystems</returns>
|
||||
private static string? FormatVolumeLabels(string? driveLabel, Dictionary<string, List<string>>? labels)
|
||||
{
|
||||
// Must have at least one label to format
|
||||
if (driveLabel == null && (labels == null || labels.Count == 0))
|
||||
return null;
|
||||
|
||||
// If no labels given, use drive label
|
||||
if (labels == null || labels.Count == 0)
|
||||
{
|
||||
// Ignore common volume labels
|
||||
if (Drive.GetRedumpSystemFromVolumeLabel(driveLabel) != null)
|
||||
return null;
|
||||
|
||||
return driveLabel;
|
||||
}
|
||||
|
||||
// If only one label, don't mention fs
|
||||
string firstLabel = labels.First().Key;
|
||||
if (labels.Count == 1 && (firstLabel == driveLabel || driveLabel == null))
|
||||
{
|
||||
// Ignore common volume labels
|
||||
if (Drive.GetRedumpSystemFromVolumeLabel(firstLabel) != null)
|
||||
return null;
|
||||
|
||||
return firstLabel;
|
||||
}
|
||||
|
||||
// Otherwise, state filesystem for each label
|
||||
List<string> volLabels = [];
|
||||
|
||||
// Begin formatted output with the label from Windows, if it is unique and not a common volume label
|
||||
if (driveLabel != null && !labels.TryGetValue(driveLabel, out List<string>? value) && Drive.GetRedumpSystemFromVolumeLabel(driveLabel) == null)
|
||||
volLabels.Add(driveLabel);
|
||||
|
||||
// Add remaining labels with their corresponding filesystems
|
||||
foreach (KeyValuePair<string, List<string>> label in labels)
|
||||
{
|
||||
// Ignore common volume labels
|
||||
if (Drive.GetRedumpSystemFromVolumeLabel(label.Key) == null)
|
||||
volLabels.Add($"{label.Key} ({string.Join(", ", [.. label.Value])})");
|
||||
}
|
||||
|
||||
// Ensure that no labels are empty
|
||||
volLabels = volLabels.Where(l => !string.IsNullOrEmpty(l?.Trim())).ToList();
|
||||
|
||||
// Print each label separated by a comma and a space
|
||||
if (volLabels.Count == 0)
|
||||
return null;
|
||||
|
||||
return string.Join(", ", [.. volLabels]);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
69
MPF.Core/UI/ComboBoxItems/Element.cs
Normal file
69
MPF.Core/UI/ComboBoxItems/Element.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MPF.Core.Converters;
|
||||
|
||||
namespace MPF.Core.UI.ComboBoxItems
|
||||
{
|
||||
/// <summary>
|
||||
/// A generic combo box element
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Enum type representing the possible values</typeparam>
|
||||
public class Element<T> : IEquatable<Element<T>>, IElement where T : struct, Enum
|
||||
{
|
||||
private readonly T Data;
|
||||
|
||||
public Element(T data) => Data = data;
|
||||
|
||||
/// <summary>
|
||||
/// Allow elements to be used as their internal enum type
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public static implicit operator T? (Element<T> item) => item?.Data;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => EnumConverter.GetLongName(Data);
|
||||
|
||||
public override string ToString() => Name;
|
||||
|
||||
/// <summary>
|
||||
/// Internal enum value
|
||||
/// </summary>
|
||||
public T Value => Data;
|
||||
|
||||
/// <summary>
|
||||
/// Determine if the item is selected or not
|
||||
/// </summary>
|
||||
/// <remarks>Only applies to CheckBox type</remarks>
|
||||
public bool IsChecked { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Generate all elements associated with the data enum type
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Element<T>> GenerateElements()
|
||||
{
|
||||
return Enum.GetValues(typeof(T))
|
||||
.OfType<T>()
|
||||
.Select(e => new Element<T>(e));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return Equals(obj as Element<T>);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(Element<T>? other)
|
||||
{
|
||||
if (other == null)
|
||||
return false;
|
||||
|
||||
return Name == other.Name;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
}
|
||||
}
|
||||
10
MPF.Core/UI/ComboBoxItems/IElement.cs
Normal file
10
MPF.Core/UI/ComboBoxItems/IElement.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace MPF.Core.UI.ComboBoxItems
|
||||
{
|
||||
public interface IElement
|
||||
{
|
||||
/// <summary>
|
||||
/// Display name for the combo box element
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
}
|
||||
}
|
||||
101
MPF.Core/UI/ComboBoxItems/RedumpSystemComboBoxItem.cs
Normal file
101
MPF.Core/UI/ComboBoxItems/RedumpSystemComboBoxItem.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.UI.ComboBoxItems
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single item in the System combo box
|
||||
/// </summary>
|
||||
public class RedumpSystemComboBoxItem : IEquatable<RedumpSystemComboBoxItem>, IElement
|
||||
{
|
||||
private readonly object? Data;
|
||||
|
||||
public RedumpSystemComboBoxItem(RedumpSystem? system) => Data = system;
|
||||
public RedumpSystemComboBoxItem(SystemCategory? category) => Data = category;
|
||||
|
||||
public static implicit operator RedumpSystem?(RedumpSystemComboBoxItem item) => item.Data as RedumpSystem?;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsHeader)
|
||||
return "---------- " + (Data as SystemCategory?).LongName() + " ----------";
|
||||
else
|
||||
return (Data as RedumpSystem?).LongName() ?? "No system selected";
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() => Name;
|
||||
|
||||
/// <summary>
|
||||
/// Internal enum value
|
||||
/// </summary>
|
||||
public RedumpSystem? Value => Data as RedumpSystem?;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the item is a header value
|
||||
/// </summary>
|
||||
public bool IsHeader => Data is SystemCategory?;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the item is a standard system value
|
||||
/// </summary>
|
||||
public bool IsSystem => Data is RedumpSystem?;
|
||||
|
||||
/// <summary>
|
||||
/// Generate all elements for the known system combo box
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<RedumpSystemComboBoxItem> GenerateElements()
|
||||
{
|
||||
var knownSystems = Enum.GetValues(typeof(RedumpSystem))
|
||||
.OfType<RedumpSystem?>()
|
||||
.Where(s => !s.IsMarker() && s.GetCategory() != SystemCategory.NONE)
|
||||
.ToList();
|
||||
|
||||
Dictionary<SystemCategory, List<RedumpSystem?>> mapping = knownSystems
|
||||
.GroupBy(s => s.GetCategory())
|
||||
.ToDictionary(
|
||||
k => k.Key,
|
||||
v => v
|
||||
.OrderBy(s => s.LongName())
|
||||
.ToList()
|
||||
);
|
||||
|
||||
var systemsValues = new List<RedumpSystemComboBoxItem>
|
||||
{
|
||||
new RedumpSystemComboBoxItem((RedumpSystem?)null),
|
||||
};
|
||||
|
||||
foreach (var group in mapping)
|
||||
{
|
||||
systemsValues.Add(new RedumpSystemComboBoxItem(group.Key));
|
||||
group.Value.ForEach(system => systemsValues.Add(new RedumpSystemComboBoxItem(system)));
|
||||
}
|
||||
|
||||
return systemsValues;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return Equals(obj as RedumpSystemComboBoxItem);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(RedumpSystemComboBoxItem? other)
|
||||
{
|
||||
if (other == null)
|
||||
return false;
|
||||
|
||||
return Value == other.Value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
}
|
||||
}
|
||||
484
MPF.Core/UI/ViewModels/CheckDumpViewModel.cs
Normal file
484
MPF.Core/UI/ViewModels/CheckDumpViewModel.cs
Normal file
@@ -0,0 +1,484 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BinaryObjectScanner;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.UI.ComboBoxItems;
|
||||
using MPF.Core.Utilities;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.UI.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public class CheckDumpViewModel : INotifyPropertyChanged
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Access to the current options
|
||||
/// </summary>
|
||||
public Data.Options Options
|
||||
{
|
||||
get => _options;
|
||||
}
|
||||
private readonly Data.Options _options;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if SelectionChanged events can be executed
|
||||
/// </summary>
|
||||
public bool CanExecuteSelectionChanged { get; private set; } = false;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected system value
|
||||
/// </summary>
|
||||
public RedumpSystem? CurrentSystem
|
||||
{
|
||||
get => _currentSystem;
|
||||
set
|
||||
{
|
||||
_currentSystem = value;
|
||||
TriggerPropertyChanged(nameof(CurrentSystem));
|
||||
}
|
||||
}
|
||||
private RedumpSystem? _currentSystem;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the status of the system type combo box
|
||||
/// </summary>
|
||||
public bool SystemTypeComboBoxEnabled
|
||||
{
|
||||
get => _systemTypeComboBoxEnabled;
|
||||
set
|
||||
{
|
||||
_systemTypeComboBoxEnabled = value;
|
||||
TriggerPropertyChanged(nameof(SystemTypeComboBoxEnabled));
|
||||
}
|
||||
}
|
||||
private bool _systemTypeComboBoxEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected media type value
|
||||
/// </summary>
|
||||
public MediaType? CurrentMediaType
|
||||
{
|
||||
get => _currentMediaType;
|
||||
set
|
||||
{
|
||||
_currentMediaType = value;
|
||||
TriggerPropertyChanged(nameof(CurrentMediaType));
|
||||
}
|
||||
}
|
||||
private MediaType? _currentMediaType;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the status of the media type combo box
|
||||
/// </summary>
|
||||
public bool MediaTypeComboBoxEnabled
|
||||
{
|
||||
get => _mediaTypeComboBoxEnabled;
|
||||
set
|
||||
{
|
||||
_mediaTypeComboBoxEnabled = value;
|
||||
TriggerPropertyChanged(nameof(MediaTypeComboBoxEnabled));
|
||||
}
|
||||
}
|
||||
private bool _mediaTypeComboBoxEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Currently provided input path
|
||||
/// </summary>
|
||||
public string? InputPath
|
||||
{
|
||||
get => _inputPath;
|
||||
set
|
||||
{
|
||||
_inputPath = value;
|
||||
TriggerPropertyChanged(nameof(InputPath));
|
||||
}
|
||||
}
|
||||
private string? _inputPath;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the status of the input path text box
|
||||
/// </summary>
|
||||
public bool InputPathTextBoxEnabled
|
||||
{
|
||||
get => _inputPathTextBoxEnabled;
|
||||
set
|
||||
{
|
||||
_inputPathTextBoxEnabled = value;
|
||||
TriggerPropertyChanged(nameof(InputPathTextBoxEnabled));
|
||||
}
|
||||
}
|
||||
private bool _inputPathTextBoxEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the status of the input path browse button
|
||||
/// </summary>
|
||||
public bool InputPathBrowseButtonEnabled
|
||||
{
|
||||
get => _inputPathBrowseButtonEnabled;
|
||||
set
|
||||
{
|
||||
_inputPathBrowseButtonEnabled = value;
|
||||
TriggerPropertyChanged(nameof(InputPathBrowseButtonEnabled));
|
||||
}
|
||||
}
|
||||
private bool _inputPathBrowseButtonEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected dumping program
|
||||
/// </summary>
|
||||
public InternalProgram CurrentProgram
|
||||
{
|
||||
get => _currentProgram;
|
||||
set
|
||||
{
|
||||
_currentProgram = value;
|
||||
TriggerPropertyChanged(nameof(CurrentProgram));
|
||||
}
|
||||
}
|
||||
private InternalProgram _currentProgram;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the status of the dumping program combo box
|
||||
/// </summary>
|
||||
public bool DumpingProgramComboBoxEnabled
|
||||
{
|
||||
get => _dumpingProgramComboBoxEnabled;
|
||||
set
|
||||
{
|
||||
_dumpingProgramComboBoxEnabled = value;
|
||||
TriggerPropertyChanged(nameof(DumpingProgramComboBoxEnabled));
|
||||
}
|
||||
}
|
||||
private bool _dumpingProgramComboBoxEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the status of the check dump button
|
||||
/// </summary>
|
||||
public bool CheckDumpButtonEnabled
|
||||
{
|
||||
get => _checkDumpButtonEnabled;
|
||||
set
|
||||
{
|
||||
_checkDumpButtonEnabled = value;
|
||||
TriggerPropertyChanged(nameof(CheckDumpButtonEnabled));
|
||||
}
|
||||
}
|
||||
private bool _checkDumpButtonEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the status of the cancel button
|
||||
/// </summary>
|
||||
public bool CancelButtonEnabled
|
||||
{
|
||||
get => _cancelButtonEnabled;
|
||||
set
|
||||
{
|
||||
_cancelButtonEnabled = value;
|
||||
TriggerPropertyChanged(nameof(CancelButtonEnabled));
|
||||
}
|
||||
}
|
||||
private bool _cancelButtonEnabled;
|
||||
|
||||
#endregion
|
||||
|
||||
#region List Properties
|
||||
|
||||
/// <summary>
|
||||
/// Current list of supported media types
|
||||
/// </summary>
|
||||
public List<Element<MediaType>>? MediaTypes
|
||||
{
|
||||
get => _mediaTypes;
|
||||
set
|
||||
{
|
||||
_mediaTypes = value;
|
||||
TriggerPropertyChanged(nameof(MediaTypes));
|
||||
}
|
||||
}
|
||||
private List<Element<MediaType>>? _mediaTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Current list of supported system profiles
|
||||
/// </summary>
|
||||
public List<RedumpSystemComboBoxItem> Systems
|
||||
{
|
||||
get => _systems;
|
||||
set
|
||||
{
|
||||
_systems = value;
|
||||
TriggerPropertyChanged(nameof(Systems));
|
||||
}
|
||||
}
|
||||
private List<RedumpSystemComboBoxItem> _systems;
|
||||
|
||||
/// <summary>
|
||||
/// List of available internal programs
|
||||
/// </summary>
|
||||
public List<Element<InternalProgram>> InternalPrograms
|
||||
{
|
||||
get => _internalPrograms;
|
||||
set
|
||||
{
|
||||
_internalPrograms = value;
|
||||
TriggerPropertyChanged(nameof(InternalPrograms));
|
||||
}
|
||||
}
|
||||
private List<Element<InternalProgram>> _internalPrograms;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for pure view model
|
||||
/// </summary>
|
||||
public CheckDumpViewModel()
|
||||
{
|
||||
_options = OptionsLoader.LoadFromConfig();
|
||||
_internalPrograms = [];
|
||||
_inputPath = string.Empty;
|
||||
_systems = [];
|
||||
|
||||
SystemTypeComboBoxEnabled = true;
|
||||
InputPathTextBoxEnabled = true;
|
||||
InputPathBrowseButtonEnabled = true;
|
||||
MediaTypeComboBoxEnabled = true;
|
||||
DumpingProgramComboBoxEnabled = true;
|
||||
CheckDumpButtonEnabled = false;
|
||||
CancelButtonEnabled = true;
|
||||
|
||||
MediaTypes = [];
|
||||
Systems = RedumpSystemComboBoxItem.GenerateElements().ToList();
|
||||
InternalPrograms = [];
|
||||
|
||||
PopulateMediaType();
|
||||
PopulateInternalPrograms();
|
||||
EnableEventHandlers();
|
||||
}
|
||||
|
||||
#region Property Updates
|
||||
|
||||
/// <summary>
|
||||
/// Trigger a property changed event
|
||||
/// </summary>
|
||||
private void TriggerPropertyChanged(string propertyName)
|
||||
{
|
||||
// Disable event handlers temporarily
|
||||
bool cachedCanExecuteSelectionChanged = CanExecuteSelectionChanged;
|
||||
DisableEventHandlers();
|
||||
|
||||
// If the property change event is initialized
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
|
||||
// Reenable event handlers, if necessary
|
||||
if (cachedCanExecuteSelectionChanged) EnableEventHandlers();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI Commands
|
||||
|
||||
/// <summary>
|
||||
/// Change the currently selected system
|
||||
/// </summary>
|
||||
public void ChangeSystem()
|
||||
{
|
||||
PopulateMediaType();
|
||||
this.CheckDumpButtonEnabled = ShouldEnableCheckDumpButton();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change the currently selected media type
|
||||
/// </summary>
|
||||
public void ChangeMediaType()
|
||||
{
|
||||
this.CheckDumpButtonEnabled = ShouldEnableCheckDumpButton();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change the currently selected dumping program
|
||||
/// </summary>
|
||||
public void ChangeDumpingProgram()
|
||||
{
|
||||
this.CheckDumpButtonEnabled = ShouldEnableCheckDumpButton();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change the currently selected input path
|
||||
/// </summary>
|
||||
public void ChangeInputPath()
|
||||
{
|
||||
this.CheckDumpButtonEnabled = ShouldEnableCheckDumpButton();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI Control
|
||||
|
||||
/// <summary>
|
||||
/// Enables all UI elements that should be enabled
|
||||
/// </summary>
|
||||
private void EnableUIElements()
|
||||
{
|
||||
SystemTypeComboBoxEnabled = true;
|
||||
InputPathTextBoxEnabled = true;
|
||||
InputPathBrowseButtonEnabled = true;
|
||||
DumpingProgramComboBoxEnabled = true;
|
||||
PopulateMediaType();
|
||||
CheckDumpButtonEnabled = ShouldEnableCheckDumpButton();
|
||||
CancelButtonEnabled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables all UI elements
|
||||
/// </summary>
|
||||
private void DisableUIElements()
|
||||
{
|
||||
SystemTypeComboBoxEnabled = false;
|
||||
InputPathTextBoxEnabled = false;
|
||||
InputPathBrowseButtonEnabled = false;
|
||||
MediaTypeComboBoxEnabled = false;
|
||||
DumpingProgramComboBoxEnabled = false;
|
||||
CheckDumpButtonEnabled = false;
|
||||
CancelButtonEnabled = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Population
|
||||
|
||||
/// <summary>
|
||||
/// Populate media type according to system type
|
||||
/// </summary>
|
||||
private void PopulateMediaType()
|
||||
{
|
||||
// Disable other UI updates
|
||||
bool cachedCanExecuteSelectionChanged = CanExecuteSelectionChanged;
|
||||
DisableEventHandlers();
|
||||
|
||||
if (this.CurrentSystem != null)
|
||||
{
|
||||
var mediaTypeValues = this.CurrentSystem.MediaTypes();
|
||||
int index = mediaTypeValues.FindIndex(m => m == this.CurrentMediaType);
|
||||
|
||||
MediaTypes = mediaTypeValues.Select(m => new Element<MediaType>(m ?? MediaType.NONE)).ToList();
|
||||
this.MediaTypeComboBoxEnabled = MediaTypes.Count > 1;
|
||||
this.CurrentMediaType = (index > -1 ? MediaTypes[index] : MediaTypes[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.MediaTypeComboBoxEnabled = false;
|
||||
this.MediaTypes = null;
|
||||
this.CurrentMediaType = null;
|
||||
}
|
||||
|
||||
// Reenable event handlers, if necessary
|
||||
if (cachedCanExecuteSelectionChanged) EnableEventHandlers();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populate media type according to system type
|
||||
/// </summary>
|
||||
private void PopulateInternalPrograms()
|
||||
{
|
||||
// Disable other UI updates
|
||||
bool cachedCanExecuteSelectionChanged = CanExecuteSelectionChanged;
|
||||
DisableEventHandlers();
|
||||
|
||||
// Get the current internal program
|
||||
InternalProgram internalProgram = this.Options.InternalProgram;
|
||||
|
||||
// Create a static list of supported Check programs, not everything
|
||||
var internalPrograms = new List<InternalProgram> { InternalProgram.Redumper, InternalProgram.Aaru, InternalProgram.DiscImageCreator, InternalProgram.CleanRip, InternalProgram.PS3CFW, InternalProgram.UmdImageCreator };
|
||||
InternalPrograms = internalPrograms.Select(ip => new Element<InternalProgram>(ip)).ToList();
|
||||
|
||||
// Select the current default dumping program
|
||||
int currentIndex = InternalPrograms.FindIndex(m => m == internalProgram);
|
||||
this.CurrentProgram = (currentIndex > -1 ? InternalPrograms[currentIndex].Value : InternalPrograms[0].Value);
|
||||
|
||||
// Reenable event handlers, if necessary
|
||||
if (cachedCanExecuteSelectionChanged) EnableEventHandlers();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI Functionality
|
||||
|
||||
private bool ShouldEnableCheckDumpButton()
|
||||
{
|
||||
return this.CurrentSystem != null && this.CurrentMediaType != null && !string.IsNullOrEmpty(this.InputPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable all textbox and combobox event handlers
|
||||
/// </summary>
|
||||
private void EnableEventHandlers()
|
||||
{
|
||||
CanExecuteSelectionChanged = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disable all textbox and combobox event handlers
|
||||
/// </summary>
|
||||
private void DisableEventHandlers()
|
||||
{
|
||||
CanExecuteSelectionChanged = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MPF.Check
|
||||
|
||||
/// <summary>
|
||||
/// Performs MPF.Check functionality
|
||||
/// </summary>
|
||||
/// <returns>An error message if failed, otherwise string.Empty/null</returns>
|
||||
public async Task<string?> CheckDump(Func<SubmissionInfo?, (bool?, SubmissionInfo?)> processUserInfo)
|
||||
{
|
||||
if (string.IsNullOrEmpty(InputPath))
|
||||
return "Invalid Input path";
|
||||
|
||||
if (!File.Exists(this.InputPath!.Trim('"')))
|
||||
return "Input Path is not a valid file";
|
||||
|
||||
// Disable UI while Check is running
|
||||
DisableUIElements();
|
||||
bool cachedCanExecuteSelectionChanged = CanExecuteSelectionChanged;
|
||||
DisableEventHandlers();
|
||||
|
||||
// Populate an environment
|
||||
var env = new DumpEnvironment(Options, Path.GetFullPath(this.InputPath.Trim('"')), null, this.CurrentSystem, this.CurrentMediaType, this.CurrentProgram, parameters: null);
|
||||
|
||||
// Make new Progress objects
|
||||
var resultProgress = new Progress<Result>();
|
||||
resultProgress.ProgressChanged += ConsoleLogger.ProgressUpdated;
|
||||
var protectionProgress = new Progress<ProtectionProgress>();
|
||||
protectionProgress.ProgressChanged += ConsoleLogger.ProgressUpdated;
|
||||
|
||||
// Finally, attempt to do the output dance
|
||||
var result = await env.VerifyAndSaveDumpOutput(resultProgress, protectionProgress, processUserInfo);
|
||||
|
||||
// Reenable UI and event handlers, if necessary
|
||||
EnableUIElements();
|
||||
if (cachedCanExecuteSelectionChanged)
|
||||
EnableEventHandlers();
|
||||
|
||||
return result.Message;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
1069
MPF.Core/UI/ViewModels/CreateIRDViewModel.cs
Normal file
1069
MPF.Core/UI/ViewModels/CreateIRDViewModel.cs
Normal file
File diff suppressed because it is too large
Load Diff
247
MPF.Core/UI/ViewModels/DiscInformationViewModel.cs
Normal file
247
MPF.Core/UI/ViewModels/DiscInformationViewModel.cs
Normal file
@@ -0,0 +1,247 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.UI.ComboBoxItems;
|
||||
using MPF.Core.Utilities;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.UI.ViewModels
|
||||
{
|
||||
public class DiscInformationViewModel
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Application-level Options object
|
||||
/// </summary>
|
||||
public Options Options { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// SubmissionInfo object to fill and save
|
||||
/// </summary>
|
||||
public SubmissionInfo SubmissionInfo { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Lists
|
||||
|
||||
/// <summary>
|
||||
/// List of available disc categories
|
||||
/// </summary>
|
||||
public List<Element<DiscCategory>> Categories { get; private set; } = Element<DiscCategory>.GenerateElements().ToList();
|
||||
|
||||
/// <summary>
|
||||
/// List of available regions
|
||||
/// </summary>
|
||||
public List<Element<Region>> Regions { get; private set; } = Element<Region>.GenerateElements().ToList();
|
||||
|
||||
/// <summary>
|
||||
/// List of Redump-supported Regions
|
||||
/// </summary>
|
||||
private static readonly List<Region> RedumpRegions = new()
|
||||
{
|
||||
Region.Argentina,
|
||||
Region.Asia,
|
||||
Region.AsiaEurope,
|
||||
Region.AsiaUSA,
|
||||
Region.Australia,
|
||||
Region.AustraliaGermany,
|
||||
Region.AustraliaNewZealand,
|
||||
Region.Austria,
|
||||
Region.AustriaSwitzerland,
|
||||
Region.Belarus,
|
||||
Region.Belgium,
|
||||
Region.BelgiumNetherlands,
|
||||
Region.Brazil,
|
||||
Region.Bulgaria,
|
||||
Region.Canada,
|
||||
Region.China,
|
||||
Region.Croatia,
|
||||
Region.Czechia,
|
||||
Region.Denmark,
|
||||
Region.Estonia,
|
||||
Region.Europe,
|
||||
Region.EuropeAsia,
|
||||
Region.EuropeAustralia,
|
||||
Region.EuropeCanada,
|
||||
Region.EuropeGermany,
|
||||
Region.Export,
|
||||
Region.Finland,
|
||||
Region.France,
|
||||
Region.FranceSpain,
|
||||
Region.Germany,
|
||||
Region.GreaterChina,
|
||||
Region.Greece,
|
||||
Region.Hungary,
|
||||
Region.Iceland,
|
||||
Region.India,
|
||||
Region.Ireland,
|
||||
Region.Israel,
|
||||
Region.Italy,
|
||||
Region.Japan,
|
||||
Region.JapanAsia,
|
||||
Region.JapanEurope,
|
||||
Region.JapanKorea,
|
||||
Region.JapanUSA,
|
||||
Region.SouthKorea,
|
||||
Region.LatinAmerica,
|
||||
Region.Lithuania,
|
||||
Region.Netherlands,
|
||||
Region.NewZealand,
|
||||
Region.Norway,
|
||||
Region.Poland,
|
||||
Region.Portugal,
|
||||
Region.Romania,
|
||||
Region.RussianFederation,
|
||||
Region.Scandinavia,
|
||||
Region.Serbia,
|
||||
Region.Singapore,
|
||||
Region.Slovakia,
|
||||
Region.SouthAfrica,
|
||||
Region.Spain,
|
||||
Region.SpainPortugal,
|
||||
Region.Sweden,
|
||||
Region.Switzerland,
|
||||
Region.Taiwan,
|
||||
Region.Thailand,
|
||||
Region.Turkey,
|
||||
Region.UnitedArabEmirates,
|
||||
Region.UnitedKingdom,
|
||||
Region.UKAustralia,
|
||||
Region.Ukraine,
|
||||
Region.UnitedStatesOfAmerica,
|
||||
Region.USAAsia,
|
||||
Region.USAAustralia,
|
||||
Region.USABrazil,
|
||||
Region.USACanada,
|
||||
Region.USAEurope,
|
||||
Region.USAGermany,
|
||||
Region.USAJapan,
|
||||
Region.USAKorea,
|
||||
Region.World,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of available languages
|
||||
/// </summary>
|
||||
public List<Element<Language>> Languages { get; private set; } = Element<Language>.GenerateElements().ToList();
|
||||
|
||||
/// <summary>
|
||||
/// List of Redump-supported Languages
|
||||
/// </summary>
|
||||
private static readonly List<Language> RedumpLanguages = new()
|
||||
{
|
||||
Language.Afrikaans,
|
||||
Language.Albanian,
|
||||
Language.Arabic,
|
||||
Language.Armenian,
|
||||
Language.Basque,
|
||||
Language.Belarusian,
|
||||
Language.Bulgarian,
|
||||
Language.Catalan,
|
||||
Language.Chinese,
|
||||
Language.Croatian,
|
||||
Language.Czech,
|
||||
Language.Danish,
|
||||
Language.Dutch,
|
||||
Language.English,
|
||||
Language.Estonian,
|
||||
Language.Finnish,
|
||||
Language.French,
|
||||
Language.Gaelic,
|
||||
Language.German,
|
||||
Language.Greek,
|
||||
Language.Hebrew,
|
||||
Language.Hindi,
|
||||
Language.Hungarian,
|
||||
Language.Icelandic,
|
||||
Language.Indonesian,
|
||||
Language.Italian,
|
||||
Language.Japanese,
|
||||
Language.Korean,
|
||||
Language.Latin,
|
||||
Language.Latvian,
|
||||
Language.Lithuanian,
|
||||
Language.Macedonian,
|
||||
Language.Norwegian,
|
||||
Language.Polish,
|
||||
Language.Portuguese,
|
||||
Language.Panjabi,
|
||||
Language.Romanian,
|
||||
Language.Russian,
|
||||
Language.Serbian,
|
||||
Language.Slovak,
|
||||
Language.Slovenian,
|
||||
Language.Spanish,
|
||||
Language.Swedish,
|
||||
Language.Tamil,
|
||||
Language.Thai,
|
||||
Language.Turkish,
|
||||
Language.Ukrainian,
|
||||
Language.Vietnamese,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of available languages
|
||||
/// </summary>
|
||||
public List<Element<LanguageSelection>> LanguageSelections { get; private set; } = Element<LanguageSelection>.GenerateElements().ToList();
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public DiscInformationViewModel(Options options, SubmissionInfo? submissionInfo)
|
||||
{
|
||||
Options = options;
|
||||
SubmissionInfo = submissionInfo?.Clone() as SubmissionInfo ?? new SubmissionInfo();
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Load the current contents of the base SubmissionInfo to the UI
|
||||
/// </summary>
|
||||
/// TODO: Convert selected list item to binding
|
||||
public void Load()
|
||||
{
|
||||
if (SubmissionInfo.CommonDiscInfo?.Languages != null)
|
||||
Languages.ForEach(l => l.IsChecked = SubmissionInfo.CommonDiscInfo.Languages.Contains(l));
|
||||
if (SubmissionInfo.CommonDiscInfo?.LanguageSelection != null)
|
||||
LanguageSelections.ForEach(ls => ls.IsChecked = SubmissionInfo.CommonDiscInfo.LanguageSelection.Contains(ls));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save the current contents of the UI to the base SubmissionInfo
|
||||
/// </summary>
|
||||
/// TODO: Convert selected list item to binding
|
||||
public void Save()
|
||||
{
|
||||
if (SubmissionInfo.CommonDiscInfo == null)
|
||||
SubmissionInfo.CommonDiscInfo = new CommonDiscInfoSection();
|
||||
SubmissionInfo.CommonDiscInfo.Languages = Languages.Where(l => l.IsChecked).Select(l => l?.Value).ToArray();
|
||||
if (!SubmissionInfo.CommonDiscInfo.Languages.Any())
|
||||
SubmissionInfo.CommonDiscInfo.Languages = [null];
|
||||
SubmissionInfo.CommonDiscInfo.LanguageSelection = LanguageSelections.Where(ls => ls.IsChecked).Select(ls => ls?.Value).ToArray();
|
||||
SubmissionInfo.CommonDiscInfo.Title = InfoTool.NormalizeDiscTitle(SubmissionInfo.CommonDiscInfo.Title, SubmissionInfo.CommonDiscInfo.Languages);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Repopulate the list of Languages based on Redump support
|
||||
/// </summary>
|
||||
public void SetRedumpLanguages()
|
||||
{
|
||||
this.Languages = RedumpLanguages.Select(l => new Element<Language>(l)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Repopulate the list of Regions based on Redump support
|
||||
/// </summary>
|
||||
public void SetRedumpRegions()
|
||||
{
|
||||
this.Regions = RedumpRegions.Select(r => new Element<Region>(r)).ToList();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user