mirror of
https://github.com/SabreTools/MPF.git
synced 2026-02-04 05:35:52 +00:00
Compare commits
1105 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61f90a635f | ||
|
|
8cc0ff3829 | ||
|
|
cac6bcc4de | ||
|
|
7ac0089e81 | ||
|
|
48576b38be | ||
|
|
82dedf1ceb | ||
|
|
395cded5ef | ||
|
|
a48f9d1c83 | ||
|
|
3975003686 | ||
|
|
4beae71511 | ||
|
|
f0f41c86c5 | ||
|
|
b1b6eb2c9d | ||
|
|
29754b4c0e | ||
|
|
35cda84308 | ||
|
|
a877397fe6 | ||
|
|
2f0471d596 | ||
|
|
2037ded792 | ||
|
|
5f1a68a5f5 | ||
|
|
87746c8677 | ||
|
|
2665c29918 | ||
|
|
5637cf5201 | ||
|
|
eb1d000e4f | ||
|
|
8db467128d | ||
|
|
dc90e2609d | ||
|
|
e96bd21f1d | ||
|
|
693599b986 | ||
|
|
d482fe926c | ||
|
|
17b5432352 | ||
|
|
ca480f27ed | ||
|
|
4bad66e706 | ||
|
|
abe00fe132 | ||
|
|
ba73479837 | ||
|
|
f2a28dd36b | ||
|
|
928e30a5de | ||
|
|
007fc2f9b9 | ||
|
|
d2d23ebbdf | ||
|
|
e02ab769ec | ||
|
|
3df78def00 | ||
|
|
7eddfc5fed | ||
|
|
f6f154b6db | ||
|
|
47cd133437 | ||
|
|
74c9641a54 | ||
|
|
fc5929db2a | ||
|
|
f53b428075 | ||
|
|
46dc931b3f | ||
|
|
9608cfb700 | ||
|
|
3493238849 | ||
|
|
4c364f519e | ||
|
|
337a7a181c | ||
|
|
071e3a0024 | ||
|
|
ff0c742dee | ||
|
|
7aba0d1c9c | ||
|
|
ac6a77d9da | ||
|
|
6eb976c842 | ||
|
|
ba39a8b22f | ||
|
|
88a6fa71a9 | ||
|
|
584b8c0109 | ||
|
|
c6258b5520 | ||
|
|
d6dbbbe928 | ||
|
|
f22b3c4ac0 | ||
|
|
fae399f8bc | ||
|
|
d2ed2f81ae | ||
|
|
7dbcfce46c | ||
|
|
ebd0552a2a | ||
|
|
343973263c | ||
|
|
e5220a8224 | ||
|
|
146120c210 | ||
|
|
807e4655a6 | ||
|
|
e32ebec197 | ||
|
|
8d8886390d | ||
|
|
5a2aa9d325 | ||
|
|
37aa1645dd | ||
|
|
052d074e92 | ||
|
|
8c551dc990 | ||
|
|
b2fcc190fd | ||
|
|
2325844bd4 | ||
|
|
f63517bb52 | ||
|
|
99d26f177b | ||
|
|
d6b28de586 | ||
|
|
e8d1567d07 | ||
|
|
cd8b484ae3 | ||
|
|
65b9735941 | ||
|
|
22f7e2a0ed | ||
|
|
2c5dc7390a | ||
|
|
c5e01b9578 | ||
|
|
882243316c | ||
|
|
1b62ed0c03 | ||
|
|
edb8c08a39 | ||
|
|
ad93387aea | ||
|
|
9012ff85a9 | ||
|
|
ccc33bebbd | ||
|
|
57b07aee02 | ||
|
|
069d676492 | ||
|
|
a26dfb7e7a | ||
|
|
a9ea457808 | ||
|
|
41bc410452 | ||
|
|
bbfdf462d0 | ||
|
|
5a1d51c05f | ||
|
|
16e80f75cf | ||
|
|
2a6e066707 | ||
|
|
d6102107fb | ||
|
|
79163dcb35 | ||
|
|
c1aa863c91 | ||
|
|
dbd4b55dda | ||
|
|
1f58521f51 | ||
|
|
4da1ab9c29 | ||
|
|
5771add8c0 | ||
|
|
977a71d9cf | ||
|
|
b2d09d04ea | ||
|
|
78df92e5d3 | ||
|
|
9770b7c917 | ||
|
|
1ddb287977 | ||
|
|
b9e4bbf744 | ||
|
|
08829ed811 | ||
|
|
bf181e2294 | ||
|
|
49571c6bfc | ||
|
|
9a0bc868f8 | ||
|
|
bc2c08690d | ||
|
|
493cb80624 | ||
|
|
49b8ecf6c3 | ||
|
|
c9b7ad7819 | ||
|
|
fe76387f6a | ||
|
|
0a60fe5a37 | ||
|
|
baffdb8b29 | ||
|
|
4a3c585a8d | ||
|
|
1ee7ea1948 | ||
|
|
ee08bfe0fc | ||
|
|
896caec9cd | ||
|
|
68932ab473 | ||
|
|
d105d04146 | ||
|
|
7023c78d40 | ||
|
|
81156a3c63 | ||
|
|
7b2b06a36f | ||
|
|
3f974ab336 | ||
|
|
b238616685 | ||
|
|
2984459823 | ||
|
|
ce979b3c3f | ||
|
|
cb8e1fd34b | ||
|
|
cc148735f8 | ||
|
|
8238d14f7b | ||
|
|
a56676501e | ||
|
|
79716ea0b5 | ||
|
|
43477a133f | ||
|
|
8889beef1d | ||
|
|
ac4be751b3 | ||
|
|
69f855fc93 | ||
|
|
cf01095623 | ||
|
|
3236223e3f | ||
|
|
36450cd22b | ||
|
|
6a9b6748d2 | ||
|
|
3bf83378a2 | ||
|
|
bc938fd58c | ||
|
|
f50a110acd | ||
|
|
fcda2a6e3b | ||
|
|
d33526b27e | ||
|
|
0b0427e9c1 | ||
|
|
c34b92bad8 | ||
|
|
89145df0fa | ||
|
|
ee7cde6360 | ||
|
|
8e9edf43ac | ||
|
|
51115430cb | ||
|
|
7cf108828e | ||
|
|
020390af65 | ||
|
|
e04ceb953c | ||
|
|
363b018cb7 | ||
|
|
cf025522ef | ||
|
|
0fb8bf5c29 | ||
|
|
e280745eee | ||
|
|
fb306750e6 | ||
|
|
da5a514482 | ||
|
|
fc288e1c46 | ||
|
|
102acb9ebf | ||
|
|
b76b2a69f5 | ||
|
|
254ad6cfd0 | ||
|
|
f432f438ab | ||
|
|
e890243830 | ||
|
|
6493b462f1 | ||
|
|
54c0716ea9 | ||
|
|
7fbb5133d7 | ||
|
|
993a0fd7d3 | ||
|
|
47878fee1f | ||
|
|
4cb8a31505 | ||
|
|
0685972842 | ||
|
|
5b1cc3c715 | ||
|
|
572f0d5095 | ||
|
|
23bafad3db | ||
|
|
c7b77e4bd7 | ||
|
|
755eee4441 | ||
|
|
fca2c53d6c | ||
|
|
8f6f5f6ef0 | ||
|
|
2e9970ee6a | ||
|
|
4fa1273111 | ||
|
|
d3993a48e4 | ||
|
|
d522bb6c76 | ||
|
|
816672a817 | ||
|
|
f8171da306 | ||
|
|
ce073e5fbf | ||
|
|
28205e42f0 | ||
|
|
0160366530 | ||
|
|
663477d408 | ||
|
|
bd2e012eef | ||
|
|
a514374169 | ||
|
|
f73c0730e2 | ||
|
|
a658c80de7 | ||
|
|
b806bc6cd1 | ||
|
|
cf9675f620 | ||
|
|
ea18051709 | ||
|
|
4fdf8e5dde | ||
|
|
a4616d139d | ||
|
|
0f09a9c913 | ||
|
|
48ffd6f40c | ||
|
|
6612c8ea4d | ||
|
|
68d1a0664a | ||
|
|
86d8590789 | ||
|
|
e23427d7c9 | ||
|
|
cd19a2e4a0 | ||
|
|
000e7d88a8 | ||
|
|
e3beb1ef77 | ||
|
|
a3a75b1c2d | ||
|
|
11850a8d6b | ||
|
|
bf6b58d64b | ||
|
|
1789334625 | ||
|
|
9520f58240 | ||
|
|
48e5e01729 | ||
|
|
8c7959fb08 | ||
|
|
8ef7543cf1 | ||
|
|
f9e39ee4be | ||
|
|
0a4621c963 | ||
|
|
04b4f528ba | ||
|
|
f024e49c21 | ||
|
|
7ca404f9dd | ||
|
|
18fc162cd8 | ||
|
|
b577bbae37 | ||
|
|
02f9509b86 | ||
|
|
8b00e3deed | ||
|
|
3ffea60402 | ||
|
|
f8eab60ecc | ||
|
|
9e8d46fb03 | ||
|
|
3831922f29 | ||
|
|
7f7416c053 | ||
|
|
529ada1b8b | ||
|
|
6260f1a1fe | ||
|
|
a7f6e09226 | ||
|
|
4b49815a7a | ||
|
|
14c17bbdf7 | ||
|
|
0fe30d2d4f | ||
|
|
1c3f65e7f9 | ||
|
|
62ff0f955a | ||
|
|
a942e6142a | ||
|
|
f637e629a3 | ||
|
|
72b00953d8 | ||
|
|
cfac607c7d | ||
|
|
e9a84e5429 | ||
|
|
2f985d0526 | ||
|
|
e1ace14753 | ||
|
|
9c29967f65 | ||
|
|
5612d7989d | ||
|
|
f872a6be29 | ||
|
|
59e7ecfa8a | ||
|
|
79cce37cf6 | ||
|
|
4016b3fc19 | ||
|
|
e5bcada606 | ||
|
|
60d31363e3 | ||
|
|
22a125a838 | ||
|
|
0a86781d61 | ||
|
|
c5649ecdbb | ||
|
|
df22336ba0 | ||
|
|
2d7350cbaf | ||
|
|
6a56a58b7c | ||
|
|
a97c94885c | ||
|
|
9548993982 | ||
|
|
1476972c26 | ||
|
|
85cde67d0a | ||
|
|
bfaf24c237 | ||
|
|
adfa8a9a0c | ||
|
|
3d68d880f6 | ||
|
|
77bc7e7b1a | ||
|
|
23837ee555 | ||
|
|
0553d1256a | ||
|
|
68f0c6cf35 | ||
|
|
32d3996432 | ||
|
|
5af02fe508 | ||
|
|
eba6a7ce4a | ||
|
|
7faedc92e4 | ||
|
|
3de48fc24e | ||
|
|
9400523c4f | ||
|
|
48c945f194 | ||
|
|
d9a8050beb | ||
|
|
6ec179f0ed | ||
|
|
620851af73 | ||
|
|
f5c4b7ebdf | ||
|
|
364ae1b837 | ||
|
|
b4b864cd9f | ||
|
|
acc2f30bd2 | ||
|
|
dc0675d8c6 | ||
|
|
33ce0e4024 | ||
|
|
fa8fdac0ce | ||
|
|
a4d876d273 | ||
|
|
3cc779ba77 | ||
|
|
5c8f4b9cac | ||
|
|
fb2b926986 | ||
|
|
3442a1f5b2 | ||
|
|
1fb9039985 | ||
|
|
0032066363 | ||
|
|
c1ed042190 | ||
|
|
6c0f2415b7 | ||
|
|
ca898c4689 | ||
|
|
3be4378b61 | ||
|
|
c1641d7461 | ||
|
|
aefb5a3778 | ||
|
|
4557017fc5 | ||
|
|
d77e9c1612 | ||
|
|
455fb8228a | ||
|
|
679b40de7c | ||
|
|
fb2b1b7c54 | ||
|
|
ac649af511 | ||
|
|
4fb0e38f54 | ||
|
|
a84904e374 | ||
|
|
7b8becfa40 | ||
|
|
ba0fefca42 | ||
|
|
d7736055a0 | ||
|
|
8e37932b86 | ||
|
|
d2c58d4c39 | ||
|
|
34f3449231 | ||
|
|
31ee29a716 | ||
|
|
c1f2fd5f19 | ||
|
|
172f9afbcf | ||
|
|
19dd4f43e4 | ||
|
|
0ae7352c5e | ||
|
|
e7c11d40ac | ||
|
|
dccd78a01e | ||
|
|
fb05409c5d | ||
|
|
1c9b94341a | ||
|
|
d3e208a332 | ||
|
|
6b8cfb4256 | ||
|
|
f60f26065b | ||
|
|
2ed14a7688 | ||
|
|
071b91f414 | ||
|
|
0ad99cb0f5 | ||
|
|
e51aabddae | ||
|
|
9390699114 | ||
|
|
93d2c2e8b0 | ||
|
|
50d969f08f | ||
|
|
44e87948c7 | ||
|
|
dea011213a | ||
|
|
5b2500637b | ||
|
|
82ede4dac2 | ||
|
|
032ffe75f4 | ||
|
|
ce9c6d1f52 | ||
|
|
8be145127d | ||
|
|
0ce928349c | ||
|
|
79e4f4a142 | ||
|
|
4bd8fc476c | ||
|
|
5b82cdacda | ||
|
|
4106a6261b | ||
|
|
6b006958a6 | ||
|
|
068b92ebac | ||
|
|
4cf2b8a83d | ||
|
|
333043ccae | ||
|
|
0ff1753aa2 | ||
|
|
9ad917e508 | ||
|
|
f3ac31ce1b | ||
|
|
7fdf671273 | ||
|
|
d5dee49f6b | ||
|
|
acdc13efa1 | ||
|
|
8446980919 | ||
|
|
e5e7bf49fc | ||
|
|
8b73ffc4a2 | ||
|
|
ce6ed1e01b | ||
|
|
bc0cd60fc1 | ||
|
|
17f850ecb2 | ||
|
|
ad8a623f16 | ||
|
|
b025898d7b | ||
|
|
b604aefd5e | ||
|
|
1656b50029 | ||
|
|
572b8cfa6b | ||
|
|
c5cd623e75 | ||
|
|
ff2dbd7b81 | ||
|
|
19cedfc5e8 | ||
|
|
3df93fb59d | ||
|
|
62ffd3f6d3 | ||
|
|
69994774f5 | ||
|
|
3a1fc93aac | ||
|
|
6f8d27b9c4 | ||
|
|
42680b9915 | ||
|
|
9033f3a798 | ||
|
|
717590bf41 | ||
|
|
4f48ccc4c6 | ||
|
|
ca59d71e7d | ||
|
|
9207627fb0 | ||
|
|
216c6de970 | ||
|
|
cebbeb264f | ||
|
|
e971ee8550 | ||
|
|
76029d02ea | ||
|
|
0cdf2fc520 | ||
|
|
5ac0055e16 | ||
|
|
7b7e8912a5 | ||
|
|
e055572c67 | ||
|
|
c4d981350f | ||
|
|
5035f2dcc2 | ||
|
|
7c41fe0933 | ||
|
|
2b4fa33e81 | ||
|
|
e8f50a84b8 | ||
|
|
7c0923881e | ||
|
|
eeacb7b3b2 | ||
|
|
d3039af3e1 | ||
|
|
eaa77dbeed | ||
|
|
55696f1f47 | ||
|
|
7d22341d2f | ||
|
|
53c6e47fa8 | ||
|
|
7b7da4db1f | ||
|
|
b9d8e0c125 | ||
|
|
1e2f1280be | ||
|
|
3339ff1c14 | ||
|
|
1e729459a6 | ||
|
|
2d547bd67f | ||
|
|
2bb854e7a5 | ||
|
|
b8e923207f | ||
|
|
3d96379aba | ||
|
|
8c5437983a | ||
|
|
7cad841f39 | ||
|
|
b4e04314a7 | ||
|
|
f1506b284c | ||
|
|
3fde773018 | ||
|
|
2fb8613a85 | ||
|
|
94d59242b1 | ||
|
|
09179810ee | ||
|
|
2061af06c1 | ||
|
|
075a95ef4c | ||
|
|
c8a402ee64 | ||
|
|
a5d7b218b7 | ||
|
|
ebb83a6a1e | ||
|
|
0c327872b5 | ||
|
|
6ef9debac4 | ||
|
|
10c7906e9d | ||
|
|
b922857578 | ||
|
|
dca5235a4a | ||
|
|
07e747f7d3 | ||
|
|
da67c58727 | ||
|
|
0524ad7ac2 | ||
|
|
2a16be2c07 | ||
|
|
a5a048fcb0 | ||
|
|
b2ffa2025b | ||
|
|
0d11e03507 | ||
|
|
c72aeb7f58 | ||
|
|
86eca8dee7 | ||
|
|
5e5360441a | ||
|
|
5392afbf06 | ||
|
|
c7c700e567 | ||
|
|
8c0bbfbf10 | ||
|
|
e7baa7d33f | ||
|
|
724b1b6719 | ||
|
|
ab88f8ffaa | ||
|
|
6feda0e69d | ||
|
|
d704cec97b | ||
|
|
9fe815676f | ||
|
|
129a7ba63f | ||
|
|
4617401e8b | ||
|
|
3cb037b5af | ||
|
|
49b70b7ae1 | ||
|
|
4eb346632a | ||
|
|
56fffb0ed9 | ||
|
|
8adde6f8d5 | ||
|
|
eacd60562c | ||
|
|
f6df7e96c1 | ||
|
|
0e37025150 | ||
|
|
4e338d56cd | ||
|
|
c26253007d | ||
|
|
66b4bb4eb2 | ||
|
|
034494558e | ||
|
|
cc7116a623 | ||
|
|
011ca670e0 | ||
|
|
956d8efcf7 | ||
|
|
ee4e77b208 | ||
|
|
8eff11f0ae | ||
|
|
8d4f22a1c4 | ||
|
|
3829ee1bbe | ||
|
|
61060e98df | ||
|
|
7f061f22e0 | ||
|
|
e72336a835 | ||
|
|
886a0a4f07 | ||
|
|
093435e7b0 | ||
|
|
59a427963d | ||
|
|
19d6006aff | ||
|
|
617b0ba2c5 | ||
|
|
195c83499c | ||
|
|
e5b02c27a8 | ||
|
|
c7b6b08397 | ||
|
|
da6b2f0e24 | ||
|
|
c50c3edcc5 | ||
|
|
d628b2a0dd | ||
|
|
f6baaa6f5e | ||
|
|
b05c82e903 | ||
|
|
65f472c4c9 | ||
|
|
104dd4348b | ||
|
|
2337a2ed86 | ||
|
|
2ce632f8b4 | ||
|
|
ce917f4f61 | ||
|
|
d029cf4164 | ||
|
|
74d52c2f3b | ||
|
|
785786c3a9 | ||
|
|
466d8f58b0 | ||
|
|
bc690614e6 | ||
|
|
d44798b27c | ||
|
|
595cd0d60f | ||
|
|
68fd5a2aa0 | ||
|
|
6da98aa65c | ||
|
|
d8d149446f | ||
|
|
4d0f48be10 | ||
|
|
8a048c8a57 | ||
|
|
d51db072fc | ||
|
|
468c9937da | ||
|
|
206ac76633 | ||
|
|
339b0d93d1 | ||
|
|
fd5da5de74 | ||
|
|
42146f991d | ||
|
|
f3f05eee48 | ||
|
|
61bf2f69aa | ||
|
|
546aa70b69 | ||
|
|
65cd1cede3 | ||
|
|
dffa16139a | ||
|
|
98bacf11fc | ||
|
|
ee0ccecfb2 | ||
|
|
a0825f276b | ||
|
|
66d61e20de | ||
|
|
6455ebd434 | ||
|
|
f4436fddfa | ||
|
|
317777cf93 | ||
|
|
da6dbe136e | ||
|
|
13d7cf8124 | ||
|
|
bb8fea625b | ||
|
|
15a0659867 | ||
|
|
988a5f6d2b | ||
|
|
1941639473 | ||
|
|
d1772f743e | ||
|
|
870c2d1cec | ||
|
|
f7f6ae1eee | ||
|
|
dd9e527592 | ||
|
|
e1122fa976 | ||
|
|
8a44fa3355 | ||
|
|
51a9e3005f | ||
|
|
413b6da24b | ||
|
|
172a0fb5dc | ||
|
|
83a189a5d3 | ||
|
|
60c27ec89b | ||
|
|
51733557cd | ||
|
|
93d964c603 | ||
|
|
2925f2262b | ||
|
|
5b211a7345 | ||
|
|
ed4bd24fcb | ||
|
|
8a7761753b | ||
|
|
1b8cca9999 | ||
|
|
b75391b1c6 | ||
|
|
e9c2fd9245 | ||
|
|
fb24bbd8a5 | ||
|
|
4e3083c8e6 | ||
|
|
05738b7c11 | ||
|
|
f963db67b1 | ||
|
|
de64631c00 | ||
|
|
c8adef78c2 | ||
|
|
7b116e7a04 | ||
|
|
fb7b6ff1be | ||
|
|
7fb8e44c31 | ||
|
|
239ad4c4bc | ||
|
|
9834d0ea3e | ||
|
|
a35c13bd10 | ||
|
|
5e1777a7c7 | ||
|
|
66570300df | ||
|
|
4ac1fb201e | ||
|
|
cba8daa010 | ||
|
|
ba24a4b21a | ||
|
|
91c6fdac82 | ||
|
|
416656c457 | ||
|
|
fdd75818c4 | ||
|
|
ac302626c2 | ||
|
|
428f3cc547 | ||
|
|
66fc36fe3c | ||
|
|
9dddf1c9b6 | ||
|
|
5dbb955d26 | ||
|
|
2f2958bdea | ||
|
|
c91f6ebbce | ||
|
|
22fdd036eb | ||
|
|
3f12c6acb9 | ||
|
|
1dbae18da6 | ||
|
|
6370e2dd6a | ||
|
|
0c8879bc66 | ||
|
|
6be34414fe | ||
|
|
f15fc989c8 | ||
|
|
0fc53cb534 | ||
|
|
dc0909808a | ||
|
|
00401d1282 | ||
|
|
b9d0d5d8f6 | ||
|
|
22a6b77d27 | ||
|
|
bc4fe17fab | ||
|
|
4b4027f285 | ||
|
|
d28257b2b7 | ||
|
|
669ef47f32 | ||
|
|
be224800bc | ||
|
|
8dbb589d42 | ||
|
|
7b2fd5bf35 | ||
|
|
95fa651074 | ||
|
|
a0a155eb9b | ||
|
|
72339b18df | ||
|
|
95c9c7706d | ||
|
|
135bb43cdf | ||
|
|
cfc75ca84d | ||
|
|
33c35b63d7 | ||
|
|
851a43d46f | ||
|
|
a88bef481d | ||
|
|
781fec2b57 | ||
|
|
ee96367a45 | ||
|
|
9f9bfc0888 | ||
|
|
c6cc697320 | ||
|
|
5e3f7f740b | ||
|
|
e17a8f4708 | ||
|
|
ff4771a74a | ||
|
|
426717102d | ||
|
|
126bae33a4 | ||
|
|
11b8dd44bb | ||
|
|
cbbb8aaa8c | ||
|
|
9ee7cd7fd7 | ||
|
|
324c1fcee3 | ||
|
|
06776a6093 | ||
|
|
43a079bb28 | ||
|
|
d45345d338 | ||
|
|
1ff0340cae | ||
|
|
278c86f9f4 | ||
|
|
00089b799c | ||
|
|
0f98f03999 | ||
|
|
22f6f39a91 | ||
|
|
e9a9011dbd | ||
|
|
40bbb3d1c8 | ||
|
|
a48dad817b | ||
|
|
9f76dcc5fd | ||
|
|
4356561a8a | ||
|
|
347c522d62 | ||
|
|
998ecec261 | ||
|
|
ab8e775df0 | ||
|
|
246e6b8bfd | ||
|
|
c7f69de18f | ||
|
|
d4a98d7712 | ||
|
|
2983266e8a | ||
|
|
1baef4440a | ||
|
|
7cd25dae1c | ||
|
|
38f9b7234b | ||
|
|
2d7ea1bed9 | ||
|
|
806a69c280 | ||
|
|
a92159b8cb | ||
|
|
9451629461 | ||
|
|
51a1f0cc8e | ||
|
|
2830641b8a | ||
|
|
7c87a22dcc | ||
|
|
dd5b5d4c7d | ||
|
|
bc5e73d371 | ||
|
|
f47a55b723 | ||
|
|
c4d014e480 | ||
|
|
69b1d2f7ad | ||
|
|
7c295ca2f4 | ||
|
|
5af3aad68a | ||
|
|
f150483e84 | ||
|
|
92ef962f42 | ||
|
|
859e53f843 | ||
|
|
e70d70ca22 | ||
|
|
c2cf8147d3 | ||
|
|
cf32f38c0e | ||
|
|
1f92ff08d6 | ||
|
|
6aaf076434 | ||
|
|
6865b23aa7 | ||
|
|
e1c13982bd | ||
|
|
9cddcc2eae | ||
|
|
33932fad47 | ||
|
|
470e5c69fe | ||
|
|
3aae2990a3 | ||
|
|
503933e67f | ||
|
|
1a99fd9e71 | ||
|
|
affc175bda | ||
|
|
fe4c88d3ad | ||
|
|
9c830c9755 | ||
|
|
fc300465f8 | ||
|
|
de1032a099 | ||
|
|
aa22b9fbff | ||
|
|
a41f0d6237 | ||
|
|
9d5dfaaa68 | ||
|
|
7f08684e9a | ||
|
|
8c2ad6eca5 | ||
|
|
dad108de52 | ||
|
|
df3bf1f7c5 | ||
|
|
0e355b906c | ||
|
|
1d472bf777 | ||
|
|
a7e0ac0806 | ||
|
|
5a208926a5 | ||
|
|
d812ea7e2b | ||
|
|
f19111a1b0 | ||
|
|
a36f7d7df4 | ||
|
|
c5e8de6c1a | ||
|
|
6ebcca104f | ||
|
|
3f048c5243 | ||
|
|
dffebc5d43 | ||
|
|
37f2cf5bab | ||
|
|
9865f88a6f | ||
|
|
90d4d0d029 | ||
|
|
68c3d7c4fa | ||
|
|
503a6a8cdc | ||
|
|
c10b3d28bd | ||
|
|
d349ef8a9d | ||
|
|
3137a543a7 | ||
|
|
7b832049e8 | ||
|
|
6566db5913 | ||
|
|
8c70f19959 | ||
|
|
898069c799 | ||
|
|
01e991c5fd | ||
|
|
3b21fa62a0 | ||
|
|
12a13a2ffa | ||
|
|
074d2c031c | ||
|
|
e33588451d | ||
|
|
f2ba433859 | ||
|
|
b266467c33 | ||
|
|
8eece24d9a | ||
|
|
bb644e9a8b | ||
|
|
c07ca9f39c | ||
|
|
bb92c43b35 | ||
|
|
b9d6a13e20 | ||
|
|
891499710f | ||
|
|
1328a373ea | ||
|
|
4a59ce1d90 | ||
|
|
7a74042aef | ||
|
|
2f7abee51b | ||
|
|
a63c844ed1 | ||
|
|
91a0e85e24 | ||
|
|
c9a67b1b51 | ||
|
|
3d932705bc | ||
|
|
80cde96614 | ||
|
|
aae81035c1 | ||
|
|
d08716045a | ||
|
|
f34999e308 | ||
|
|
028f7d5788 | ||
|
|
c34aeb6e45 | ||
|
|
bdb367c2c9 | ||
|
|
63e6ce121a | ||
|
|
ac072618c4 | ||
|
|
7a640c58ee | ||
|
|
5ad75c80d1 | ||
|
|
78d648d90b | ||
|
|
d415a8f161 | ||
|
|
87ba8d573d | ||
|
|
55a84fc911 | ||
|
|
f9351ff058 | ||
|
|
e0482aad78 | ||
|
|
9243020cd6 | ||
|
|
616f3624b7 | ||
|
|
aff981171a | ||
|
|
4816c5ab6a | ||
|
|
77f9b048fb | ||
|
|
846db2f602 | ||
|
|
6a21ca9f86 | ||
|
|
9613cae204 | ||
|
|
59102a8330 | ||
|
|
52f51cf1ab | ||
|
|
98ae16f7ae | ||
|
|
c0d8a87c44 | ||
|
|
7a120d155a | ||
|
|
d99da089ef | ||
|
|
d76cd346d4 | ||
|
|
5082ca57c4 | ||
|
|
c31eeb001a | ||
|
|
bef4bf175c | ||
|
|
ac744a1e6d | ||
|
|
13d7d83dbb | ||
|
|
7608c08e7c | ||
|
|
c5c180a9c6 | ||
|
|
9bce6aea1a | ||
|
|
7cd84e2e9a | ||
|
|
b8d7bbc72e | ||
|
|
a60f11135e | ||
|
|
c2664a1d2d | ||
|
|
e5632634d0 | ||
|
|
daa3261c16 | ||
|
|
dbf7150a31 | ||
|
|
893fd34d36 | ||
|
|
e1961612c0 | ||
|
|
0f1b23056c | ||
|
|
26254e6b32 | ||
|
|
505fbf2567 | ||
|
|
1bb38ea987 | ||
|
|
a3144b1537 | ||
|
|
ad90e2b6f9 | ||
|
|
705060fa70 | ||
|
|
f8e8c02fcf | ||
|
|
eacee24d45 | ||
|
|
d980fffa09 | ||
|
|
853b8689b4 | ||
|
|
7e4089f79c | ||
|
|
54ee2829f1 | ||
|
|
f89cac5400 | ||
|
|
b003203aef | ||
|
|
4e5c9a242e | ||
|
|
5edb70745a | ||
|
|
f474b339ac | ||
|
|
bb9a344938 | ||
|
|
75ad9eae28 | ||
|
|
2b3b029545 | ||
|
|
9843644dfc | ||
|
|
54103a1d7e | ||
|
|
5da277ae64 | ||
|
|
51461a958d | ||
|
|
6d1fd9d47d | ||
|
|
6b6f888dc3 | ||
|
|
1c6a9da9c8 | ||
|
|
c335cd2869 | ||
|
|
dbe521b719 | ||
|
|
9486cdeedb | ||
|
|
2b9b186be0 | ||
|
|
73a78c786f | ||
|
|
786f2177bd | ||
|
|
ddaf5e35f3 | ||
|
|
b39542b651 | ||
|
|
4479733421 | ||
|
|
6907e5b6ac | ||
|
|
81f672ca42 | ||
|
|
611c33f302 | ||
|
|
9cffc80982 | ||
|
|
3ba4db8f0a | ||
|
|
26daa46486 | ||
|
|
51b14874c7 | ||
|
|
a6014e1b58 | ||
|
|
e4237fedef | ||
|
|
8d334b7228 | ||
|
|
bb95112559 | ||
|
|
6e798aa565 | ||
|
|
94f8d9709a | ||
|
|
37a2e5c957 | ||
|
|
e163b174ac | ||
|
|
db92acfdcc | ||
|
|
26e65b428b | ||
|
|
03c55216ca | ||
|
|
70ae5dd787 | ||
|
|
e2a5cf968d | ||
|
|
60f43de605 | ||
|
|
4205a0baef | ||
|
|
a52ac9f7b5 | ||
|
|
346dab0899 | ||
|
|
c3bfd02310 | ||
|
|
d688fc6975 | ||
|
|
521b8d656b | ||
|
|
9456301168 | ||
|
|
fad425da29 | ||
|
|
6b177c618d | ||
|
|
ca26307dbf | ||
|
|
8a7079a159 | ||
|
|
c4814fc950 | ||
|
|
7deaa9e7af | ||
|
|
1ad4738b60 | ||
|
|
4a82baa5d1 | ||
|
|
1c1740010d | ||
|
|
955fc4b8a0 | ||
|
|
fad9fa5f72 | ||
|
|
9dc976e423 | ||
|
|
c2c92b54d9 | ||
|
|
77ccdb0032 | ||
|
|
4e3046fadd | ||
|
|
70114ee59e | ||
|
|
4bb02b88fc | ||
|
|
f97e293ad2 | ||
|
|
2a040effde | ||
|
|
862e676590 | ||
|
|
bffa70bcc9 | ||
|
|
bb596c49f4 | ||
|
|
917986530b | ||
|
|
14bc7609c5 | ||
|
|
a2361c34bc | ||
|
|
3d29eeb3c3 | ||
|
|
c908a55ce6 | ||
|
|
c2b3932363 | ||
|
|
b4d47aea37 | ||
|
|
f8d3ae7bc7 | ||
|
|
9f50277888 | ||
|
|
96f826994a | ||
|
|
eda3c97465 | ||
|
|
ff380451db | ||
|
|
a9ee6667d0 | ||
|
|
54415241d2 | ||
|
|
79d2957ede | ||
|
|
0b5d52da7d | ||
|
|
274ad9fc9a | ||
|
|
a2217b536b | ||
|
|
43e7883ac9 | ||
|
|
c37d098eee | ||
|
|
17c2ca6fa8 | ||
|
|
4b2d30bc01 | ||
|
|
ec8b65a7fa | ||
|
|
ec5611f5ff | ||
|
|
3e350b666b | ||
|
|
e83f69fc3e | ||
|
|
6ecbbb6978 | ||
|
|
771483ac14 | ||
|
|
ccde878286 | ||
|
|
e0ab3e048b | ||
|
|
cf2ae163c4 | ||
|
|
5025a3e91a | ||
|
|
dab774dab3 | ||
|
|
04c6131d28 | ||
|
|
47561baee8 | ||
|
|
a8b1a8342d | ||
|
|
7b8ef00d59 | ||
|
|
65cc502a94 | ||
|
|
d38b465b08 | ||
|
|
783c323fd0 | ||
|
|
04af8807e5 | ||
|
|
1260dfdff2 | ||
|
|
e5b883fb73 | ||
|
|
1c08451487 | ||
|
|
29b483f805 | ||
|
|
2eff4a7488 | ||
|
|
5e94d02503 | ||
|
|
ccf2166b72 | ||
|
|
024394bbec | ||
|
|
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 |
4
.editorconfig
Normal file
4
.editorconfig
Normal file
@@ -0,0 +1,4 @@
|
||||
[*.cs]
|
||||
|
||||
# SYSLIB1045: Convert to 'GeneratedRegexAttribute'.
|
||||
dotnet_diagnostic.SYSLIB1045.severity = silent
|
||||
5
.github/ISSUE_TEMPLATE/feature-request.md
vendored
5
.github/ISSUE_TEMPLATE/feature-request.md
vendored
@@ -8,8 +8,9 @@ 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](https://github.com/mnadareski/BurnOutSharp/issues) instead.
|
||||
|
||||
- Remember to try the [latest WIP build](https://github.com/SabreTools/MPF/releases/tag/rolling) to see if the feature already exists.
|
||||
- Is it copy protection related? If so, report the issue [here](https://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...
|
||||
|
||||
7
.github/ISSUE_TEMPLATE/informational.md
vendored
7
.github/ISSUE_TEMPLATE/informational.md
vendored
@@ -8,8 +8,9 @@ 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](https://github.com/mnadareski/BurnOutSharp/issues) instead.
|
||||
|
||||
- Remember to try the [latest WIP build](https://github.com/SabreTools/MPF/releases/tag/rolling) to see if the feature already exists.
|
||||
- Is it copy protection related? If so, report the issue [here](https://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...
|
||||
@@ -18,4 +19,4 @@ If none of those apply, then continue...
|
||||
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.
|
||||
Add any other context or screenshots about the information here.
|
||||
|
||||
12
.github/ISSUE_TEMPLATE/issue-report.md
vendored
12
.github/ISSUE_TEMPLATE/issue-report.md
vendored
@@ -8,15 +8,16 @@ 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](https://github.com/mnadareski/BurnOutSharp/issues) instead.
|
||||
|
||||
- Remember to try the [latest WIP build](https://github.com/SabreTools/MPF/releases/tag/rolling) to see if the issue has already been addressed.
|
||||
- Is it copy protection related? If so, report the issue [here](https://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?
|
||||
What version are you using?
|
||||
|
||||
- [ ] Stable release (version here)
|
||||
- [ ] WIP release (version here)
|
||||
@@ -24,15 +25,14 @@ What version are you using?
|
||||
**Build**
|
||||
What runtime version are you using?
|
||||
|
||||
- [ ] .NET Framework 4.8 running on (Operating System)
|
||||
- [ ] .NET 6.0 running on (Operating System)
|
||||
- [ ] .NET 7.0 running on (Operating System)
|
||||
- [ ] .NET 10 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 '....'
|
||||
|
||||
59
.github/workflows/build_and_test.yml
vendored
Normal file
59
.github/workflows/build_and_test.yml
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
name: Build and Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["master"]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Free Disk Space (Ubuntu)
|
||||
uses: jlumbroso/free-disk-space@v1.3.1
|
||||
with:
|
||||
dotnet: false
|
||||
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: |
|
||||
8.0.x
|
||||
9.0.x
|
||||
10.0.x
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
|
||||
- name: Run publish script
|
||||
run: ./publish-nix.sh -dp
|
||||
|
||||
- name: Update rolling tag
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git tag -f rolling
|
||||
git push origin :refs/tags/rolling || true
|
||||
git push origin rolling --force
|
||||
|
||||
- name: Upload to rolling
|
||||
uses: ncipollo/release-action@v1.20.0
|
||||
with:
|
||||
allowUpdates: True
|
||||
artifacts: "*.nupkg,*.snupkg,*.zip"
|
||||
body: "Last built commit: ${{ github.sha }}
|
||||
|
||||
## UI Builds
|
||||
|
||||
[Windows x64 UI Release](https://github.com/SabreTools/MPF/releases/download/rolling/MPF.UI_net10.0-windows_win-x64_release.zip)
|
||||
|
||||
[Windows x64 UI Debug](https://github.com/SabreTools/MPF/releases/download/rolling/MPF.UI_net10.0-windows_win-x64_debug.zip)"
|
||||
name: "Rolling Release"
|
||||
prerelease: True
|
||||
replacesArtifacts: True
|
||||
tag: "rolling"
|
||||
updateOnlyUnreleased: True
|
||||
31
.github/workflows/check_pr.yml
vendored
Normal file
31
.github/workflows/check_pr.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: Build PR
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Free Disk Space (Ubuntu)
|
||||
uses: jlumbroso/free-disk-space@v1.3.1
|
||||
with:
|
||||
dotnet: false
|
||||
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: |
|
||||
8.0.x
|
||||
9.0.x
|
||||
10.0.x
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
|
||||
- name: Build
|
||||
run: dotnet build
|
||||
|
||||
- name: Test
|
||||
run: dotnet test
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -68,7 +68,6 @@ artifacts/
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
|
||||
0
.gitmodules
vendored
0
.gitmodules
vendored
35
.vscode/launch.json
vendored
35
.vscode/launch.json
vendored
@@ -5,17 +5,46 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": ".NET Core Launch (console)",
|
||||
"name": ".NET Core Launch (Check)",
|
||||
"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",
|
||||
"program": "${workspaceFolder}/MPF.Check/bin/Debug/net10.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
|
||||
"stopAtEntry": false,
|
||||
"justMyCode": false
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Launch (CLI)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/MPF.CLI/bin/Debug/net10.0/MPF.CLI.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/MPF.CLI",
|
||||
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false,
|
||||
"justMyCode": false
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Launch (UI)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/MPF.UI/bin/Debug/net10.0-windows/MPF.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/MPF.UI",
|
||||
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false,
|
||||
"justMyCode": false
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Attach",
|
||||
|
||||
1155
CHANGELIST.md
1155
CHANGELIST.md
File diff suppressed because it is too large
Load Diff
276
MPF.CLI/Features/BaseFeature.cs
Normal file
276
MPF.CLI/Features/BaseFeature.cs
Normal file
@@ -0,0 +1,276 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
#if NET40
|
||||
using System.Threading.Tasks;
|
||||
#endif
|
||||
using MPF.Frontend;
|
||||
using MPF.Frontend.Tools;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
using SabreTools.RedumpLib.Web;
|
||||
using LogCompression = MPF.Processors.LogCompression;
|
||||
|
||||
namespace MPF.CLI.Features
|
||||
{
|
||||
internal abstract class BaseFeature : SabreTools.CommandLine.Feature
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// User-defined options
|
||||
/// </summary>
|
||||
public Options Options { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Currently-selected system
|
||||
/// </summary>
|
||||
public RedumpSystem? System { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Media type to dump
|
||||
/// </summary>
|
||||
/// <remarks>Required for DIC and if custom parameters not set</remarks>
|
||||
public MediaType? MediaType { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Path to the device to dump
|
||||
/// </summary>
|
||||
/// <remarks>Required if custom parameters are not set</remarks>
|
||||
public string? DevicePath { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Path to the mounted filesystem to check
|
||||
/// </summary>
|
||||
/// <remarks>Should only be used when the device path is not readable</remarks>
|
||||
public string? MountedPath { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Path to the output file
|
||||
/// </summary>
|
||||
/// <remarks>Required if custom parameters are not set</remarks>
|
||||
public string? FilePath { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Override drive speed
|
||||
/// </summary>
|
||||
public int? DriveSpeed { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Custom parameters for dumping
|
||||
/// </summary>
|
||||
public string? CustomParams { get; protected set; }
|
||||
|
||||
#endregion
|
||||
|
||||
protected BaseFeature(string name, string[] flags, string description, string? detailed = null)
|
||||
: base(name, flags, description, detailed)
|
||||
{
|
||||
Options = new Options()
|
||||
{
|
||||
// Internal Program
|
||||
InternalProgram = InternalProgram.NONE,
|
||||
|
||||
// Extra Dumping Options
|
||||
ScanForProtection = false,
|
||||
AddPlaceholders = true,
|
||||
PullAllInformation = false,
|
||||
AddFilenameSuffix = false,
|
||||
OutputSubmissionJSON = false,
|
||||
IncludeArtifacts = false,
|
||||
CompressLogFiles = false,
|
||||
LogCompression = LogCompression.DeflateMaximum,
|
||||
DeleteUnnecessaryFiles = false,
|
||||
CreateIRDAfterDumping = false,
|
||||
|
||||
// Protection Scanning Options
|
||||
ScanArchivesForProtection = true,
|
||||
IncludeDebugProtectionInformation = false,
|
||||
HideDriveLetters = false,
|
||||
|
||||
// Redump Login Information
|
||||
RetrieveMatchInformation = true,
|
||||
RedumpUsername = null,
|
||||
RedumpPassword = null,
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Execute()
|
||||
{
|
||||
// Validate the supplied credentials
|
||||
if (Options.RetrieveMatchInformation
|
||||
&& !string.IsNullOrEmpty(Options.RedumpUsername)
|
||||
&& !string.IsNullOrEmpty(Options.RedumpPassword))
|
||||
{
|
||||
bool? validated = RedumpClient.ValidateCredentials(Options.RedumpUsername!, Options.RedumpPassword!).GetAwaiter().GetResult();
|
||||
string message = validated switch
|
||||
{
|
||||
true => "Redump username and password accepted!",
|
||||
false => "Redump username and password denied!",
|
||||
null => "An error occurred validating your credentials!",
|
||||
};
|
||||
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
|
||||
// Validate the internal program
|
||||
switch (Options.InternalProgram)
|
||||
{
|
||||
case InternalProgram.Aaru:
|
||||
if (!File.Exists(Options.AaruPath))
|
||||
{
|
||||
Console.Error.WriteLine("A path needs to be supplied in config.json for Aaru, exiting...");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case InternalProgram.DiscImageCreator:
|
||||
if (!File.Exists(Options.DiscImageCreatorPath))
|
||||
{
|
||||
Console.Error.WriteLine("A path needs to be supplied in config.json for DIC, exiting...");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case InternalProgram.Redumper:
|
||||
if (!File.Exists(Options.RedumperPath))
|
||||
{
|
||||
Console.Error.WriteLine("A path needs to be supplied in config.json for Redumper, exiting...");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Console.Error.WriteLine($"{Options.InternalProgram} is not a supported dumping program, exiting...");
|
||||
break;
|
||||
}
|
||||
|
||||
// Ensure we have the values we need
|
||||
if (CustomParams == null && DevicePath == null)
|
||||
{
|
||||
Console.Error.WriteLine("Either custom parameters or a device path need to be provided, exiting...");
|
||||
return false;
|
||||
}
|
||||
if (Options.InternalProgram == InternalProgram.DiscImageCreator
|
||||
&& CustomParams == null
|
||||
&& (MediaType == null || MediaType == SabreTools.RedumpLib.Data.MediaType.NONE))
|
||||
{
|
||||
Console.Error.WriteLine("Media type is required for DiscImageCreator, exiting...");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Normalize the file path
|
||||
if (DevicePath != null && FilePath == null)
|
||||
{
|
||||
FilePath = $"track_{DateTime.Now:yyyyMMdd-HHmm}.bin";
|
||||
if (Options.DefaultOutputPath != null)
|
||||
FilePath = Path.Combine(Options.DefaultOutputPath, FilePath);
|
||||
}
|
||||
if (FilePath != null)
|
||||
FilePath = FrontendTool.NormalizeOutputPaths(FilePath, getFullPath: true);
|
||||
|
||||
// Get the speed from the options
|
||||
int speed = DriveSpeed ?? FrontendTool.GetDefaultSpeedForMediaType(MediaType, Options);
|
||||
|
||||
// Populate an environment
|
||||
var drive = Drive.Create(null, DevicePath ?? string.Empty);
|
||||
var env = new DumpEnvironment(Options,
|
||||
FilePath,
|
||||
drive,
|
||||
System,
|
||||
Options.InternalProgram);
|
||||
env.SetExecutionContext(MediaType, null);
|
||||
env.SetProcessor();
|
||||
|
||||
// Process the parameters
|
||||
string? paramStr = CustomParams ?? env.GetFullParameters(MediaType, speed);
|
||||
if (string.IsNullOrEmpty(paramStr))
|
||||
{
|
||||
Console.Error.WriteLine("No valid environment could be created, exiting...");
|
||||
return false;
|
||||
}
|
||||
|
||||
env.SetExecutionContext(MediaType, paramStr);
|
||||
|
||||
// Invoke the dumping program
|
||||
Console.WriteLine($"Invoking {Options.InternalProgram} using '{paramStr}'");
|
||||
var dumpResult = env.Run(MediaType).GetAwaiter().GetResult();
|
||||
Console.WriteLine(dumpResult.Message);
|
||||
if (!dumpResult)
|
||||
return false;
|
||||
|
||||
// If it was not a dumping command
|
||||
if (!env.IsDumpingCommand())
|
||||
{
|
||||
Console.Error.WriteLine();
|
||||
Console.WriteLine("Execution not recognized as dumping command, skipping processing...");
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we have a mounted path, replace the environment
|
||||
if (MountedPath != null && Directory.Exists(MountedPath))
|
||||
{
|
||||
drive = Drive.Create(null, MountedPath);
|
||||
env = new DumpEnvironment(Options,
|
||||
FilePath,
|
||||
drive,
|
||||
System,
|
||||
internalProgram: null);
|
||||
env.SetExecutionContext(MediaType, null);
|
||||
env.SetProcessor();
|
||||
}
|
||||
|
||||
// Finally, attempt to do the output dance
|
||||
var verifyResult = env.VerifyAndSaveDumpOutput()
|
||||
.ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
Console.WriteLine(verifyResult.Message);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display help for MPF.CLI
|
||||
/// </summary>
|
||||
/// <param name="error">Error string to prefix the help text with</param>
|
||||
public static void DisplayHelp()
|
||||
{
|
||||
Console.WriteLine("Usage:");
|
||||
Console.WriteLine("MPF.CLI <system> [options]");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Standalone Options:");
|
||||
Console.WriteLine("?, h, help Show this help text");
|
||||
Console.WriteLine("version Print the program version");
|
||||
Console.WriteLine("lc, listcodes List supported comment/content site codes");
|
||||
Console.WriteLine("lo, listconfig List current configuration values");
|
||||
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("i, interactive Enable interactive mode");
|
||||
Console.WriteLine();
|
||||
|
||||
Console.WriteLine("CLI Options:");
|
||||
Console.WriteLine("-u, --use <program> Override configured dumping program name");
|
||||
Console.WriteLine("-t, --mediatype <mediatype> Set media type for dumping (Required for DIC)");
|
||||
Console.WriteLine("-d, --device <devicepath> Physical drive path (Required if no custom parameters set)");
|
||||
Console.WriteLine("-m, --mounted <dirpath> Mounted filesystem path for additional checks");
|
||||
Console.WriteLine("-f, --file \"<filepath>\" Output file path (Recommended, uses defaults otherwise)");
|
||||
Console.WriteLine("-s, --speed <speed> Override default dumping speed");
|
||||
Console.WriteLine("-c, --custom \"<params>\" Custom parameters to use");
|
||||
Console.WriteLine();
|
||||
|
||||
Console.WriteLine("Dumping program paths and other settings can be found in the config.json file");
|
||||
Console.WriteLine("generated next to the program by default. Ensure that all settings are to user");
|
||||
Console.WriteLine("preference before running MPF.CLI.");
|
||||
Console.WriteLine();
|
||||
|
||||
Console.WriteLine("Custom dumping parameters, if used, will fully replace the default parameters.");
|
||||
Console.WriteLine("All dumping parameters need to be supplied if doing this.");
|
||||
Console.WriteLine("Otherwise, a drive path is required.");
|
||||
Console.WriteLine();
|
||||
|
||||
Console.WriteLine("Mounted filesystem path is only recommended on OSes that require block");
|
||||
Console.WriteLine("device dumping, usually Linux and macOS.");
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
190
MPF.CLI/Features/InteractiveFeature.cs
Normal file
190
MPF.CLI/Features/InteractiveFeature.cs
Normal file
@@ -0,0 +1,190 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using MPF.Frontend;
|
||||
using MPF.Frontend.Tools;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.CLI.Features
|
||||
{
|
||||
internal sealed class InteractiveFeature : BaseFeature
|
||||
{
|
||||
#region Feature Definition
|
||||
|
||||
public const string DisplayName = "interactive";
|
||||
|
||||
private static readonly string[] _flags = ["i", "interactive"];
|
||||
|
||||
private const string _description = "Enable interactive mode";
|
||||
|
||||
#endregion
|
||||
|
||||
public InteractiveFeature()
|
||||
: base(DisplayName, _flags, _description)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool ProcessArgs(string[] args, int index)
|
||||
{
|
||||
// Cache all args as inputs
|
||||
for (int i = 1; i < args.Length; i++)
|
||||
{
|
||||
Inputs.Add(args[i]);
|
||||
}
|
||||
|
||||
// Read the options from config, if possible
|
||||
Options = OptionsLoader.LoadFromConfig();
|
||||
|
||||
// Create return values
|
||||
MediaType = SabreTools.RedumpLib.Data.MediaType.NONE;
|
||||
FilePath = Path.Combine(Options.DefaultOutputPath ?? "ISO", $"track_{DateTime.Now:yyyyMMdd-HHmm}.bin");
|
||||
System = Options.DefaultSystem;
|
||||
|
||||
// Create state values
|
||||
string? result;
|
||||
|
||||
root:
|
||||
Console.Clear();
|
||||
Console.WriteLine("MPF.CLI Interactive Mode - Main Menu");
|
||||
Console.WriteLine("-------------------------");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"1) Set system (Currently '{System}')");
|
||||
Console.WriteLine($"2) Set dumping program (Currently '{Options.InternalProgram}')");
|
||||
Console.WriteLine($"3) Set media type (Currently '{MediaType}')");
|
||||
Console.WriteLine($"4) Set device path (Currently '{DevicePath}')");
|
||||
Console.WriteLine($"5) Set mounted path (Currently '{MountedPath}')");
|
||||
Console.WriteLine($"6) Set file path (Currently '{FilePath}')");
|
||||
Console.WriteLine($"7) Set override speed (Currently '{DriveSpeed}')");
|
||||
Console.WriteLine($"8) Set custom parameters (Currently '{CustomParams}')");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"Q) Exit the program");
|
||||
Console.WriteLine($"X) Start dumping");
|
||||
Console.Write("> ");
|
||||
|
||||
result = Console.ReadLine();
|
||||
switch (result)
|
||||
{
|
||||
case "1":
|
||||
goto system;
|
||||
case "2":
|
||||
goto dumpingProgram;
|
||||
case "3":
|
||||
goto mediaType;
|
||||
case "4":
|
||||
goto devicePath;
|
||||
case "5":
|
||||
goto mountedPath;
|
||||
case "6":
|
||||
goto filePath;
|
||||
case "7":
|
||||
goto overrideSpeed;
|
||||
case "8":
|
||||
goto customParams;
|
||||
|
||||
case "q":
|
||||
case "Q":
|
||||
Environment.Exit(0);
|
||||
break;
|
||||
case "x":
|
||||
case "X":
|
||||
Console.Clear();
|
||||
goto exit;
|
||||
case "z":
|
||||
case "Z":
|
||||
Console.WriteLine("It is pitch black. You are likely to be eaten by a grue.");
|
||||
Console.Write("> ");
|
||||
Console.ReadLine();
|
||||
goto root;
|
||||
default:
|
||||
Console.WriteLine($"Invalid selection: {result}");
|
||||
Console.ReadLine();
|
||||
goto root;
|
||||
}
|
||||
|
||||
system:
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("For possible inputs, use the List Systems commandline option");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Input the system and press Enter:");
|
||||
Console.Write("> ");
|
||||
result = Console.ReadLine();
|
||||
System = result.ToRedumpSystem();
|
||||
goto root;
|
||||
|
||||
dumpingProgram:
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Options:");
|
||||
Console.WriteLine($"{InternalProgram.Redumper.ToString().ToLowerInvariant(),-15} => {InternalProgram.Redumper.LongName()}");
|
||||
Console.WriteLine($"{InternalProgram.DiscImageCreator.ToString().ToLowerInvariant(),-15} => {InternalProgram.DiscImageCreator.LongName()}");
|
||||
Console.WriteLine($"{InternalProgram.Aaru.ToString().ToLowerInvariant(),-15} => {InternalProgram.Aaru.LongName()}");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Input the dumping program and press Enter:");
|
||||
Console.Write("> ");
|
||||
result = Console.ReadLine();
|
||||
Options.InternalProgram = result.ToInternalProgram();
|
||||
goto root;
|
||||
|
||||
mediaType:
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("For possible inputs, use the List Media commandline option");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Input the media type and press Enter:");
|
||||
Console.Write("> ");
|
||||
result = Console.ReadLine();
|
||||
MediaType = OptionsLoader.ToMediaType(result);
|
||||
goto root;
|
||||
|
||||
devicePath:
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Input the device path and press Enter:");
|
||||
Console.Write("> ");
|
||||
DevicePath = Console.ReadLine();
|
||||
goto root;
|
||||
|
||||
mountedPath:
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Input the mounted path and press Enter:");
|
||||
Console.Write("> ");
|
||||
MountedPath = Console.ReadLine();
|
||||
goto root;
|
||||
|
||||
filePath:
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Input the file path and press Enter:");
|
||||
Console.Write("> ");
|
||||
|
||||
result = Console.ReadLine();
|
||||
if (!string.IsNullOrEmpty(result))
|
||||
result = Path.GetFullPath(result!);
|
||||
|
||||
FilePath = result;
|
||||
goto root;
|
||||
|
||||
overrideSpeed:
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Input the override speed and press Enter:");
|
||||
Console.Write("> ");
|
||||
|
||||
result = Console.ReadLine();
|
||||
if (!int.TryParse(result, out int speed))
|
||||
speed = -1;
|
||||
|
||||
DriveSpeed = speed;
|
||||
goto root;
|
||||
|
||||
customParams:
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Input the custom parameters and press Enter:");
|
||||
Console.Write("> ");
|
||||
CustomParams = Console.ReadLine();
|
||||
goto root;
|
||||
|
||||
exit:
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool VerifyInputs() => true;
|
||||
}
|
||||
}
|
||||
115
MPF.CLI/Features/MainFeature.cs
Normal file
115
MPF.CLI/Features/MainFeature.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
|
||||
using MPF.Frontend;
|
||||
using MPF.Frontend.Tools;
|
||||
using SabreTools.CommandLine.Inputs;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.CLI.Features
|
||||
{
|
||||
internal sealed class MainFeature : BaseFeature
|
||||
{
|
||||
#region Feature Definition
|
||||
|
||||
public const string DisplayName = "main";
|
||||
|
||||
/// <remarks>Flags are unused</remarks>
|
||||
private static readonly string[] _flags = [];
|
||||
|
||||
/// <remarks>Description is unused</remarks>
|
||||
private const string _description = "";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Inputs
|
||||
|
||||
private const string _customName = "custom";
|
||||
internal readonly StringInput CustomInput = new(_customName, ["-c", "--custom"], "Custom parameters to use");
|
||||
|
||||
private const string _deviceName = "device";
|
||||
internal readonly StringInput DeviceInput = new(_deviceName, ["-d", "--device"], "Physical drive path (Required if no custom parameters set)");
|
||||
|
||||
private const string _fileName = "file";
|
||||
internal readonly StringInput FileInput = new(_fileName, ["-f", "--file"], "Output file path (Required if no custom parameters set)");
|
||||
|
||||
private const string _mediaTypeName = "media-type";
|
||||
internal readonly StringInput MediaTypeInput = new(_mediaTypeName, ["-t", "--mediatype"], "Set media type for dumping (Required for DIC)");
|
||||
|
||||
private const string _mountedName = "mounted";
|
||||
internal readonly StringInput MountedInput = new(_mountedName, ["-m", "--mounted"], "Mounted filesystem path for additional checks");
|
||||
|
||||
private const string _speedName = "speed";
|
||||
internal readonly Int32Input SpeedInput = new(_speedName, ["-s", "--speed"], "Override default dumping speed");
|
||||
|
||||
private const string _useName = "use";
|
||||
internal readonly StringInput UseInput = new(_useName, ["-u", "--use"], "Override configured dumping program name");
|
||||
|
||||
#endregion
|
||||
|
||||
public MainFeature()
|
||||
: base(DisplayName, _flags, _description)
|
||||
{
|
||||
Add(UseInput);
|
||||
Add(MediaTypeInput);
|
||||
Add(DeviceInput);
|
||||
Add(MountedInput);
|
||||
Add(FileInput);
|
||||
Add(SpeedInput);
|
||||
Add(CustomInput);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool ProcessArgs(string[] args, int index)
|
||||
{
|
||||
// If we have no arguments, just return
|
||||
if (args == null || args.Length == 0)
|
||||
return true;
|
||||
|
||||
// Read the options from config, if possible
|
||||
Options = OptionsLoader.LoadFromConfig();
|
||||
|
||||
// The first argument is the system type
|
||||
System = args[0].Trim('"').ToRedumpSystem();
|
||||
|
||||
// Loop through the arguments and parse out values
|
||||
for (index = 1; index < args.Length; index++)
|
||||
{
|
||||
// Use specific program
|
||||
if (UseInput.ProcessInput(args, ref index))
|
||||
Options.InternalProgram = UseInput.Value.ToInternalProgram();
|
||||
|
||||
// Set a media type
|
||||
else if (MediaTypeInput.ProcessInput(args, ref index))
|
||||
MediaType = OptionsLoader.ToMediaType(MediaTypeInput.Value?.Trim('"'));
|
||||
|
||||
// Use a device path
|
||||
else if (DeviceInput.ProcessInput(args, ref index))
|
||||
DevicePath = DeviceInput.Value;
|
||||
|
||||
// Use a mounted path for physical checks
|
||||
else if (MountedInput.ProcessInput(args, ref index))
|
||||
MountedPath = MountedInput.Value;
|
||||
|
||||
// Use a file path
|
||||
else if (FileInput.ProcessInput(args, ref index))
|
||||
FilePath = FileInput.Value;
|
||||
|
||||
// Set an override speed
|
||||
else if (SpeedInput.ProcessInput(args, ref index))
|
||||
DriveSpeed = SpeedInput.Value;
|
||||
|
||||
// Use a custom parameters
|
||||
else if (CustomInput.ProcessInput(args, ref index))
|
||||
CustomParams = CustomInput.Value;
|
||||
|
||||
// Default, add to inputs
|
||||
else
|
||||
Inputs.Add(args[index]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool VerifyInputs() => true;
|
||||
}
|
||||
}
|
||||
50
MPF.CLI/MPF.CLI.csproj
Normal file
50
MPF.CLI/MPF.CLI.csproj
Normal file
@@ -0,0 +1,50 @@
|
||||
<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;net9.0;net10.0</TargetFrameworks>
|
||||
<OutputType>Exe</OutputType>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<NoWarn>NU1902;NU1903</NoWarn>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<VersionPrefix>3.6.0</VersionPrefix>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Title>MPF CLI</Title>
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
<Description>CLI frontend for various dumping programs</Description>
|
||||
<Copyright>Copyright (c) Matt Nadareski 2019-2025</Copyright>
|
||||
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Support All Frameworks -->
|
||||
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net4`))">
|
||||
<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$(TargetFramework.StartsWith(`netcoreapp`)) OR $(TargetFramework.StartsWith(`net5`))">
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net6`)) OR $(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`)) OR $(TargetFramework.StartsWith(`net9`)) OR $(TargetFramework.StartsWith(`net10`))">
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$(RuntimeIdentifier.StartsWith(`osx-arm`))">
|
||||
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MPF.Frontend\MPF.Frontend.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SabreTools.CommandLine" Version="[1.4.0]" />
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="[1.9.0]" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
141
MPF.CLI/Program.cs
Normal file
141
MPF.CLI/Program.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
#if NET40
|
||||
using System.Threading.Tasks;
|
||||
#endif
|
||||
using MPF.CLI.Features;
|
||||
using MPF.Frontend.Features;
|
||||
using MPF.Frontend.Tools;
|
||||
using SabreTools.CommandLine;
|
||||
using SabreTools.CommandLine.Features;
|
||||
|
||||
namespace MPF.CLI
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// Load options from the config file
|
||||
var options = OptionsLoader.LoadFromConfig();
|
||||
if (options.FirstRun)
|
||||
{
|
||||
// Reset first run
|
||||
options.FirstRun = false;
|
||||
OptionsLoader.SaveToConfig(options);
|
||||
|
||||
// Display non-error message
|
||||
Console.WriteLine("First-run detected! Please verify the generated config.json and run again.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the command set
|
||||
var mainFeature = new MainFeature();
|
||||
var commandSet = CreateCommands(mainFeature);
|
||||
|
||||
// If we have no args, show the help and quit
|
||||
if (args == null || args.Length == 0)
|
||||
{
|
||||
BaseFeature.DisplayHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the first argument as a feature flag
|
||||
string featureName = args[0];
|
||||
|
||||
// Try processing the standalone arguments
|
||||
var topLevel = commandSet.GetTopLevel(featureName);
|
||||
switch (topLevel)
|
||||
{
|
||||
// Standalone Options
|
||||
case Help: BaseFeature.DisplayHelp(); return;
|
||||
case VersionFeature version: version.Execute(); return;
|
||||
case ListCodesFeature lc: lc.Execute(); return;
|
||||
case ListConfigFeature lc: lc.Execute(); return;
|
||||
case ListMediaTypesFeature lm: lm.Execute(); return;
|
||||
case ListProgramsFeature lp: lp.Execute(); return;
|
||||
case ListSystemsFeature ls: ls.Execute(); return;
|
||||
|
||||
// Interactive Mode
|
||||
case InteractiveFeature interactive:
|
||||
if (!interactive.ProcessArgs(args, 0))
|
||||
{
|
||||
BaseFeature.DisplayHelp();
|
||||
return;
|
||||
}
|
||||
if (!interactive.Execute())
|
||||
{
|
||||
BaseFeature.DisplayHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Default Behavior
|
||||
default:
|
||||
if (!mainFeature.ProcessArgs(args, 0))
|
||||
{
|
||||
BaseFeature.DisplayHelp();
|
||||
return;
|
||||
}
|
||||
if (!mainFeature.Execute())
|
||||
{
|
||||
BaseFeature.DisplayHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the command set for the program
|
||||
/// </summary>
|
||||
private static CommandSet CreateCommands(MainFeature mainFeature)
|
||||
{
|
||||
List<string> header = [
|
||||
"MPF.CLI [standalone|system] [options] <path> ...",
|
||||
string.Empty,
|
||||
];
|
||||
|
||||
List<string> footer = [
|
||||
string.Empty,
|
||||
"Dumping program paths and other settings can be found in the config.json file",
|
||||
"generated next to the program by default. Ensure that all settings are to user",
|
||||
"preference before running MPF.CLI.",
|
||||
string.Empty,
|
||||
|
||||
"Custom dumping parameters, if used, will fully replace the default parameters.",
|
||||
"All dumping parameters need to be supplied if doing this.",
|
||||
"Otherwise, both a drive path and output file path are required.",
|
||||
string.Empty,
|
||||
|
||||
"Mounted filesystem path is only recommended on OSes that require block",
|
||||
"device dumping, usually Linux and macOS.",
|
||||
string.Empty,
|
||||
];
|
||||
|
||||
var commandSet = new CommandSet(header, footer);
|
||||
|
||||
// Standalone Options
|
||||
commandSet.Add(new Help());
|
||||
commandSet.Add(new VersionFeature());
|
||||
commandSet.Add(new ListCodesFeature());
|
||||
commandSet.Add(new ListConfigFeature());
|
||||
commandSet.Add(new ListMediaTypesFeature());
|
||||
commandSet.Add(new ListSystemsFeature());
|
||||
commandSet.Add(new ListProgramsFeature());
|
||||
commandSet.Add(new InteractiveFeature());
|
||||
|
||||
// CLI Options
|
||||
commandSet.Add(mainFeature.UseInput);
|
||||
commandSet.Add(mainFeature.MediaTypeInput);
|
||||
commandSet.Add(mainFeature.DeviceInput);
|
||||
commandSet.Add(mainFeature.MountedInput);
|
||||
commandSet.Add(mainFeature.FileInput);
|
||||
commandSet.Add(mainFeature.SpeedInput);
|
||||
commandSet.Add(mainFeature.CustomInput);
|
||||
|
||||
return commandSet;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/>
|
||||
</startup>
|
||||
</configuration>
|
||||
176
MPF.Check/Features/BaseFeature.cs
Normal file
176
MPF.Check/Features/BaseFeature.cs
Normal file
@@ -0,0 +1,176 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
#if NET40
|
||||
using System.Threading.Tasks;
|
||||
#endif
|
||||
using MPF.Frontend;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
using SabreTools.RedumpLib.Web;
|
||||
using LogCompression = MPF.Processors.LogCompression;
|
||||
|
||||
namespace MPF.Check.Features
|
||||
{
|
||||
internal abstract class BaseFeature : SabreTools.CommandLine.Feature
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// User-defined options
|
||||
/// </summary>
|
||||
public Options Options { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Currently-selected system
|
||||
/// </summary>
|
||||
public RedumpSystem? System { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Seed submission info from an input file
|
||||
/// </summary>
|
||||
public SubmissionInfo? Seed { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Path to the device to scan
|
||||
/// </summary>
|
||||
public string? DevicePath { get; protected set; }
|
||||
|
||||
#endregion
|
||||
|
||||
protected BaseFeature(string name, string[] flags, string description, string? detailed = null)
|
||||
: base(name, flags, description, detailed)
|
||||
{
|
||||
Options = new Options()
|
||||
{
|
||||
// Internal Program
|
||||
InternalProgram = InternalProgram.NONE,
|
||||
|
||||
// Extra Dumping Options
|
||||
ScanForProtection = false,
|
||||
AddPlaceholders = true,
|
||||
PullAllInformation = false,
|
||||
AddFilenameSuffix = false,
|
||||
OutputSubmissionJSON = false,
|
||||
IncludeArtifacts = false,
|
||||
CompressLogFiles = false,
|
||||
LogCompression = LogCompression.DeflateMaximum,
|
||||
DeleteUnnecessaryFiles = false,
|
||||
CreateIRDAfterDumping = false,
|
||||
|
||||
// Protection Scanning Options
|
||||
ScanArchivesForProtection = true,
|
||||
IncludeDebugProtectionInformation = false,
|
||||
HideDriveLetters = false,
|
||||
|
||||
// Redump Login Information
|
||||
RetrieveMatchInformation = true,
|
||||
RedumpUsername = null,
|
||||
RedumpPassword = null,
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Execute()
|
||||
{
|
||||
if (Options.InternalProgram == InternalProgram.NONE)
|
||||
{
|
||||
Console.Error.WriteLine("A program name needs to be provided");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate the supplied credentials
|
||||
if (Options.RetrieveMatchInformation
|
||||
&& !string.IsNullOrEmpty(Options.RedumpUsername)
|
||||
&& !string.IsNullOrEmpty(Options.RedumpPassword))
|
||||
{
|
||||
bool? validated = RedumpClient.ValidateCredentials(Options.RedumpUsername!, Options.RedumpPassword!).GetAwaiter().GetResult();
|
||||
string message = validated switch
|
||||
{
|
||||
true => "Redump username and password accepted!",
|
||||
false => "Redump username and password denied!",
|
||||
null => "An error occurred validating your credentials!",
|
||||
};
|
||||
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
|
||||
// Loop through all the rest of the args
|
||||
for (int i = 0; i < Inputs.Count; i++)
|
||||
{
|
||||
// Get the full file path
|
||||
string filepath = Path.GetFullPath(Inputs[i].Trim('"'));
|
||||
|
||||
// Now populate an environment
|
||||
Drive? drive = null;
|
||||
if (!string.IsNullOrEmpty(DevicePath))
|
||||
drive = Drive.Create(null, DevicePath!);
|
||||
|
||||
var env = new DumpEnvironment(Options,
|
||||
filepath,
|
||||
drive,
|
||||
System,
|
||||
internalProgram: null);
|
||||
env.SetProcessor();
|
||||
|
||||
// Finally, attempt to do the output dance
|
||||
var result = env.VerifyAndSaveDumpOutput(seedInfo: Seed)
|
||||
.ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
Console.WriteLine(result.Message);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display help for MPF.Check
|
||||
/// </summary>
|
||||
/// <param name="error">Error string to prefix the help text with</param>
|
||||
public static void DisplayHelp()
|
||||
{
|
||||
Console.WriteLine("Usage:");
|
||||
Console.WriteLine("MPF.Check <system> [options] </path/to/output.cue|iso|_logs.zip> ...");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Standalone Options:");
|
||||
Console.WriteLine("?, h, help Show this help text");
|
||||
Console.WriteLine("version Print the program version");
|
||||
Console.WriteLine("lc, listcodes List supported comment/content site codes");
|
||||
Console.WriteLine("lo, listconfig List current configuration values");
|
||||
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("i, interactive Enable interactive mode");
|
||||
Console.WriteLine();
|
||||
|
||||
Console.WriteLine("Check Options:");
|
||||
Console.WriteLine("-u, --use <program> Dumping program output type [REQUIRED]");
|
||||
Console.WriteLine(" --load-seed <path> Load a seed submission JSON for user information");
|
||||
Console.WriteLine(" --no-placeholders Disable placeholder values in submission info");
|
||||
Console.WriteLine(" --create-ird Create IRD from output files (PS3 only)");
|
||||
Console.WriteLine(" --no-retrieve Disable retrieving match information from Redump");
|
||||
Console.WriteLine("-c, --credentials <user> <pw> Redump username and password (incompatible with --no-retrieve) [WILL BE REMOVED]");
|
||||
Console.WriteLine("-U, --username <user> Redump username (incompatible with --no-retrieve)");
|
||||
Console.WriteLine("-P, --password <pw> Redump password (incompatible with --no-retrieve)");
|
||||
Console.WriteLine(" --pull-all Pull all information from Redump (requires --username and --password)");
|
||||
Console.WriteLine("-p, --path <drivepath> Physical drive path for additional checks");
|
||||
Console.WriteLine("-s, --scan Enable copy protection scan (requires --path)");
|
||||
Console.WriteLine(" --disable-archives Disable scanning archives (requires --scan)");
|
||||
Console.WriteLine(" --enable-debug Enable debug protection information (requires --scan)");
|
||||
Console.WriteLine(" --hide-drive-letters Hide drive letters from scan output (requires --scan)");
|
||||
Console.WriteLine("-x, --suffix Enable adding filename suffix");
|
||||
Console.WriteLine("-j, --json Enable submission JSON output");
|
||||
Console.WriteLine(" --include-artifacts Include artifacts in JSON (requires --json)");
|
||||
Console.WriteLine("-z, --zip Enable log file compression");
|
||||
Console.WriteLine(" --log-compression Set the log compression type (requires compression enabled)");
|
||||
Console.WriteLine("-d, --delete Enable unnecessary file deletion");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("WARNING: If using a configuration file alongside any of the above options");
|
||||
Console.WriteLine("then flag options will act as toggles instead of always enabling.");
|
||||
Console.WriteLine("For example, if log compression is enabled in your configuration file, then");
|
||||
Console.WriteLine("providing the --zip option would disable compression.");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("WARNING: Check will overwrite both any existing submission information files as well");
|
||||
Console.WriteLine("as any log archives. Please make backups of those if you need to before running Check.");
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
288
MPF.Check/Features/InteractiveFeature.cs
Normal file
288
MPF.Check/Features/InteractiveFeature.cs
Normal file
@@ -0,0 +1,288 @@
|
||||
|
||||
using System;
|
||||
using MPF.Frontend;
|
||||
using MPF.Frontend.Tools;
|
||||
using SabreTools.RedumpLib;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
using LogCompression = MPF.Processors.LogCompression;
|
||||
|
||||
namespace MPF.Check.Features
|
||||
{
|
||||
internal sealed class InteractiveFeature : BaseFeature
|
||||
{
|
||||
#region Feature Definition
|
||||
|
||||
public const string DisplayName = "interactive";
|
||||
|
||||
private static readonly string[] _flags = ["i", "interactive"];
|
||||
|
||||
private const string _description = "Enable interactive mode";
|
||||
|
||||
#endregion
|
||||
|
||||
public InteractiveFeature()
|
||||
: base(DisplayName, _flags, _description)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool ProcessArgs(string[] args, int index)
|
||||
{
|
||||
// Cache all args as inputs
|
||||
for (int i = 1; i < args.Length; i++)
|
||||
{
|
||||
Inputs.Add(args[i]);
|
||||
}
|
||||
|
||||
// Read the options from config, if possible
|
||||
Options = OptionsLoader.LoadFromConfig();
|
||||
if (Options.FirstRun)
|
||||
{
|
||||
Options = new Options()
|
||||
{
|
||||
// Internal Program
|
||||
InternalProgram = InternalProgram.NONE,
|
||||
|
||||
// Extra Dumping Options
|
||||
ScanForProtection = false,
|
||||
AddPlaceholders = true,
|
||||
PullAllInformation = false,
|
||||
AddFilenameSuffix = false,
|
||||
OutputSubmissionJSON = false,
|
||||
IncludeArtifacts = false,
|
||||
CompressLogFiles = false,
|
||||
LogCompression = LogCompression.DeflateMaximum,
|
||||
DeleteUnnecessaryFiles = false,
|
||||
CreateIRDAfterDumping = false,
|
||||
|
||||
// Protection Scanning Options
|
||||
ScanArchivesForProtection = true,
|
||||
IncludeDebugProtectionInformation = false,
|
||||
HideDriveLetters = false,
|
||||
|
||||
// Redump Login Information
|
||||
RetrieveMatchInformation = true,
|
||||
RedumpUsername = null,
|
||||
RedumpPassword = null,
|
||||
};
|
||||
}
|
||||
|
||||
// Create return values
|
||||
System = null;
|
||||
|
||||
// These values require multiple parts to be active
|
||||
bool scan = false,
|
||||
enableArchives = true,
|
||||
enableDebug = false,
|
||||
hideDriveLetters = false;
|
||||
|
||||
// Create state values
|
||||
string? result;
|
||||
|
||||
root:
|
||||
Console.Clear();
|
||||
Console.WriteLine("MPF.Check Interactive Mode - Main Menu");
|
||||
Console.WriteLine("-------------------------");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"1) Set system (Currently '{System}')");
|
||||
Console.WriteLine($"2) Set dumping program (Currently '{Options.InternalProgram}')");
|
||||
Console.WriteLine($"3) Set seed path (Currently '{Seed}')");
|
||||
Console.WriteLine($"4) Add placeholders (Currently '{Options.AddPlaceholders}')");
|
||||
Console.WriteLine($"5) Create IRD (Currently '{Options.CreateIRDAfterDumping}')");
|
||||
Console.WriteLine($"6) Attempt Redump matches (Currently '{Options.RetrieveMatchInformation}')");
|
||||
Console.WriteLine($"7) Redump credentials (Currently '{Options.RedumpUsername}')");
|
||||
Console.WriteLine($"8) Pull all information (Currently '{Options.PullAllInformation}')");
|
||||
Console.WriteLine($"9) Set device path (Currently '{DevicePath}')");
|
||||
Console.WriteLine($"A) Scan for protection (Currently '{scan}')");
|
||||
Console.WriteLine($"B) Scan archives for protection (Currently '{enableArchives}')");
|
||||
Console.WriteLine($"C) Debug protection scan output (Currently '{enableDebug}')");
|
||||
Console.WriteLine($"D) Hide drive letters in protection output (Currently '{hideDriveLetters}')");
|
||||
Console.WriteLine($"E) Hide filename suffix (Currently '{Options.AddFilenameSuffix}')");
|
||||
Console.WriteLine($"F) Output submission JSON (Currently '{Options.OutputSubmissionJSON}')");
|
||||
Console.WriteLine($"G) Include JSON artifacts (Currently '{Options.IncludeArtifacts}')");
|
||||
Console.WriteLine($"H) Compress logs (Currently '{Options.CompressLogFiles}')");
|
||||
Console.WriteLine($"I) Log compression (Currently '{Options.LogCompression.LongName()}')");
|
||||
Console.WriteLine($"J) Delete unnecessary files (Currently '{Options.DeleteUnnecessaryFiles}')");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"Q) Exit the program");
|
||||
Console.WriteLine($"X) Start checking");
|
||||
Console.Write("> ");
|
||||
|
||||
result = Console.ReadLine();
|
||||
switch (result)
|
||||
{
|
||||
case "1":
|
||||
goto system;
|
||||
case "2":
|
||||
goto dumpingProgram;
|
||||
case "3":
|
||||
goto seedPath;
|
||||
case "4":
|
||||
Options.AddPlaceholders = !Options.AddPlaceholders;
|
||||
goto root;
|
||||
case "5":
|
||||
Options.CreateIRDAfterDumping = !Options.CreateIRDAfterDumping;
|
||||
goto root;
|
||||
case "6":
|
||||
Options.RetrieveMatchInformation = !Options.RetrieveMatchInformation;
|
||||
goto root;
|
||||
case "7":
|
||||
goto redumpCredentials;
|
||||
case "8":
|
||||
Options.PullAllInformation = !Options.PullAllInformation;
|
||||
goto root;
|
||||
case "9":
|
||||
goto devicePath;
|
||||
case "a":
|
||||
case "A":
|
||||
scan = !scan;
|
||||
goto root;
|
||||
case "b":
|
||||
case "B":
|
||||
enableArchives = !enableArchives;
|
||||
goto root;
|
||||
case "c":
|
||||
case "C":
|
||||
enableDebug = !enableDebug;
|
||||
goto root;
|
||||
case "d":
|
||||
case "D":
|
||||
hideDriveLetters = !hideDriveLetters;
|
||||
goto root;
|
||||
case "e":
|
||||
case "E":
|
||||
Options.AddFilenameSuffix = !Options.AddFilenameSuffix;
|
||||
goto root;
|
||||
case "f":
|
||||
case "F":
|
||||
Options.OutputSubmissionJSON = !Options.OutputSubmissionJSON;
|
||||
goto root;
|
||||
case "g":
|
||||
case "G":
|
||||
Options.IncludeArtifacts = !Options.IncludeArtifacts;
|
||||
goto root;
|
||||
case "h":
|
||||
case "H":
|
||||
Options.CompressLogFiles = !Options.CompressLogFiles;
|
||||
goto root;
|
||||
case "i":
|
||||
case "I":
|
||||
goto logCompression;
|
||||
case "j":
|
||||
case "J":
|
||||
Options.DeleteUnnecessaryFiles = !Options.DeleteUnnecessaryFiles;
|
||||
goto root;
|
||||
|
||||
case "q":
|
||||
case "Q":
|
||||
Environment.Exit(0);
|
||||
break;
|
||||
case "x":
|
||||
case "X":
|
||||
Console.Clear();
|
||||
goto exit;
|
||||
case "z":
|
||||
case "Z":
|
||||
Console.WriteLine("It is pitch black. You are likely to be eaten by a grue.");
|
||||
Console.Write("> ");
|
||||
Console.ReadLine();
|
||||
goto root;
|
||||
default:
|
||||
Console.WriteLine($"Invalid selection: {result}");
|
||||
Console.ReadLine();
|
||||
goto root;
|
||||
}
|
||||
|
||||
system:
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("For possible inputs, use the List Systems commandline option");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Input the system and press Enter:");
|
||||
Console.Write("> ");
|
||||
result = Console.ReadLine();
|
||||
System = result.ToRedumpSystem();
|
||||
goto root;
|
||||
|
||||
dumpingProgram:
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Options:");
|
||||
foreach (var program in (InternalProgram[])Enum.GetValues(typeof(InternalProgram)))
|
||||
{
|
||||
// Skip the placeholder values
|
||||
if (program == InternalProgram.NONE)
|
||||
continue;
|
||||
|
||||
Console.WriteLine($"{program.ToString().ToLowerInvariant(),-15} => {program.LongName()}");
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Input the dumping program and press Enter:");
|
||||
Console.Write("> ");
|
||||
result = Console.ReadLine();
|
||||
Options.InternalProgram = result.ToInternalProgram();
|
||||
goto root;
|
||||
|
||||
seedPath:
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Input the seed path and press Enter:");
|
||||
Console.Write("> ");
|
||||
result = Console.ReadLine();
|
||||
Seed = Builder.CreateFromFile(result);
|
||||
goto root;
|
||||
|
||||
redumpCredentials:
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Enter your Redump username and press Enter:");
|
||||
Console.Write("> ");
|
||||
Options.RedumpUsername = Console.ReadLine();
|
||||
|
||||
Console.WriteLine("Enter your Redump password (hidden) and press Enter:");
|
||||
Console.Write("> ");
|
||||
Options.RedumpPassword = string.Empty;
|
||||
while (true)
|
||||
{
|
||||
var key = Console.ReadKey(true);
|
||||
if (key.Key == ConsoleKey.Enter)
|
||||
break;
|
||||
|
||||
Options.RedumpPassword += key.KeyChar;
|
||||
}
|
||||
|
||||
goto root;
|
||||
|
||||
devicePath:
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Input the device path and press Enter:");
|
||||
Console.Write("> ");
|
||||
DevicePath = Console.ReadLine();
|
||||
goto root;
|
||||
|
||||
logCompression:
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Options:");
|
||||
foreach (var compressionType in (LogCompression[])Enum.GetValues(typeof(LogCompression)))
|
||||
{
|
||||
Console.WriteLine($"{compressionType.ToString().ToLowerInvariant(),-15} => {compressionType.LongName()}");
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Input the log compression type and press Enter:");
|
||||
Console.Write("> ");
|
||||
result = Console.ReadLine();
|
||||
Options.LogCompression = result.ToLogCompression();
|
||||
goto root;
|
||||
|
||||
exit:
|
||||
// Now deal with the complex options
|
||||
Options.ScanForProtection = scan && !string.IsNullOrEmpty(DevicePath);
|
||||
Options.ScanArchivesForProtection = enableArchives && scan && !string.IsNullOrEmpty(DevicePath);
|
||||
Options.IncludeDebugProtectionInformation = enableDebug && scan && !string.IsNullOrEmpty(DevicePath);
|
||||
Options.HideDriveLetters = hideDriveLetters && scan && !string.IsNullOrEmpty(DevicePath);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool VerifyInputs() => Inputs.Count > 0;
|
||||
}
|
||||
}
|
||||
272
MPF.Check/Features/MainFeature.cs
Normal file
272
MPF.Check/Features/MainFeature.cs
Normal file
@@ -0,0 +1,272 @@
|
||||
using System;
|
||||
using MPF.Frontend;
|
||||
using MPF.Frontend.Tools;
|
||||
using SabreTools.CommandLine.Inputs;
|
||||
using SabreTools.RedumpLib;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
using LogCompression = MPF.Processors.LogCompression;
|
||||
|
||||
namespace MPF.Check.Features
|
||||
{
|
||||
internal sealed class MainFeature : BaseFeature
|
||||
{
|
||||
#region Feature Definition
|
||||
|
||||
public const string DisplayName = "main";
|
||||
|
||||
/// <remarks>Flags are unused</remarks>
|
||||
private static readonly string[] _flags = [];
|
||||
|
||||
/// <remarks>Description is unused</remarks>
|
||||
private const string _description = "";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Inputs
|
||||
|
||||
private const string _createIrdName = "create-ird";
|
||||
internal readonly FlagInput CreateIrdInput = new(_createIrdName, "--create-ird", "Create IRD from output files (PS3 only)");
|
||||
|
||||
private const string _deleteName = "delete";
|
||||
internal readonly FlagInput DeleteInput = new(_deleteName, ["-d", "--delete"], "Enable unnecessary file deletion");
|
||||
|
||||
private const string _disableArchivesName = "disable-archives";
|
||||
internal readonly FlagInput DisableArchivesInput = new(_disableArchivesName, "--disable-archives", "Disable scanning archives (requires --scan)");
|
||||
|
||||
private const string _enableDebugName = "enable-debug";
|
||||
internal readonly FlagInput EnableDebugInput = new(_enableDebugName, "--enable-debug", "Enable debug protection information (requires --scan)");
|
||||
|
||||
private const string _hideDriveLettersName = "hide-drive-letters";
|
||||
internal readonly FlagInput HideDriveLettersInput = new(_hideDriveLettersName, "--hide-drive-letters", "Hide drive letters from scan output (requires --scan)");
|
||||
|
||||
private const string _includeArtifactsName = "include-artifacts";
|
||||
internal readonly FlagInput IncludeArtifactsInput = new(_includeArtifactsName, "--include-artifacts", "Include artifacts in JSON (requires --json)");
|
||||
|
||||
private const string _jsonName = "json";
|
||||
internal readonly FlagInput JsonInput = new(_jsonName, ["-j", "--json"], "Enable submission JSON output");
|
||||
|
||||
private const string _loadSeedName = "load-seed";
|
||||
internal readonly StringInput LoadSeedInput = new(_loadSeedName, "--load-seed", "Load a seed submission JSON for user information");
|
||||
|
||||
private const string _logCompressionName = "log-compression";
|
||||
internal readonly StringInput LogCompressionInput = new(_logCompressionName, "--log-compression", "Set the log compression type (requires compression enabled)");
|
||||
|
||||
private const string _noPlaceholdersName = "no-placeholders";
|
||||
internal readonly FlagInput NoPlaceholdersInput = new(_noPlaceholdersName, "--no-placeholders", "Disable placeholder values in submission info");
|
||||
|
||||
private const string _noRetrieveName = "no-retrieve";
|
||||
internal readonly FlagInput NoRetrieveInput = new(_noRetrieveName, "--no-retrieve", "Disable retrieving match information from Redump");
|
||||
|
||||
private const string _passwordName = "password";
|
||||
internal readonly StringInput PasswordInput = new(_passwordName, ["-P", "--password"], "Redump password (incompatible with --no-retrieve)");
|
||||
|
||||
private const string _pathName = "path";
|
||||
internal readonly StringInput PathInput = new(_pathName, ["-p", "--path"], "Physical drive path for additional checks");
|
||||
|
||||
private const string _pullAllName = "pull-all";
|
||||
internal readonly FlagInput PullAllInput = new(_pullAllName, "--pull-all", "Pull all information from Redump (requires --username and --password)");
|
||||
|
||||
private const string _scanName = "scan";
|
||||
internal readonly FlagInput ScanInput = new(_scanName, ["-s", "--scan"], "Enable copy protection scan (requires --path)");
|
||||
|
||||
private const string _suffixName = "suffix";
|
||||
internal readonly FlagInput SuffixInput = new(_suffixName, ["-x", "--suffix"], "Enable adding filename suffix");
|
||||
|
||||
private const string _useName = "use";
|
||||
internal readonly StringInput UseInput = new(_useName, ["-u", "--use"], "Override configured dumping program name");
|
||||
|
||||
private const string _usernameName = "username";
|
||||
internal readonly StringInput UsernameInput = new(_usernameName, ["-U", "--username"], "Redump username (incompatible with --no-retrieve)");
|
||||
|
||||
private const string _zipName = "zip";
|
||||
internal readonly FlagInput ZipInput = new(_zipName, ["-z", "--zip"], "Enable log file compression");
|
||||
|
||||
#endregion
|
||||
|
||||
public MainFeature()
|
||||
: base(DisplayName, _flags, _description)
|
||||
{
|
||||
Add(UseInput);
|
||||
Add(LoadSeedInput);
|
||||
Add(NoPlaceholdersInput);
|
||||
Add(CreateIrdInput);
|
||||
Add(NoRetrieveInput);
|
||||
// TODO: Figure out how to work with the credentials input
|
||||
Add(PullAllInput);
|
||||
Add(PathInput);
|
||||
Add(ScanInput);
|
||||
Add(DisableArchivesInput);
|
||||
Add(EnableDebugInput);
|
||||
Add(HideDriveLettersInput);
|
||||
Add(SuffixInput);
|
||||
Add(JsonInput);
|
||||
Add(IncludeArtifactsInput);
|
||||
Add(ZipInput);
|
||||
Add(LogCompressionInput);
|
||||
Add(DeleteInput);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool ProcessArgs(string[] args, int index)
|
||||
{
|
||||
// These values require multiple parts to be active
|
||||
bool scan = false,
|
||||
enableArchives = true,
|
||||
enableDebug = false,
|
||||
hideDriveLetters = false;
|
||||
|
||||
// If we have no arguments, just return
|
||||
if (args == null || args.Length == 0)
|
||||
return true;
|
||||
|
||||
// Read the options from config, if possible
|
||||
Options = OptionsLoader.LoadFromConfig();
|
||||
if (Options.FirstRun)
|
||||
{
|
||||
Options = new Options()
|
||||
{
|
||||
// Internal Program
|
||||
InternalProgram = InternalProgram.NONE,
|
||||
|
||||
// Extra Dumping Options
|
||||
ScanForProtection = false,
|
||||
AddPlaceholders = true,
|
||||
PullAllInformation = false,
|
||||
AddFilenameSuffix = false,
|
||||
OutputSubmissionJSON = false,
|
||||
IncludeArtifacts = false,
|
||||
CompressLogFiles = false,
|
||||
LogCompression = LogCompression.DeflateMaximum,
|
||||
DeleteUnnecessaryFiles = false,
|
||||
CreateIRDAfterDumping = false,
|
||||
|
||||
// Protection Scanning Options
|
||||
ScanArchivesForProtection = true,
|
||||
IncludeDebugProtectionInformation = false,
|
||||
HideDriveLetters = false,
|
||||
|
||||
// Redump Login Information
|
||||
RetrieveMatchInformation = true,
|
||||
RedumpUsername = null,
|
||||
RedumpPassword = null,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Options will be loaded from found configuration file!");
|
||||
}
|
||||
|
||||
// The first argument is the system type
|
||||
System = args[0].Trim('"').ToRedumpSystem();
|
||||
|
||||
// Loop through the arguments and parse out values
|
||||
for (index = 1; index < args.Length; index++)
|
||||
{
|
||||
// Use specific program
|
||||
if (UseInput.ProcessInput(args, ref index))
|
||||
Options.InternalProgram = UseInput.Value.ToInternalProgram();
|
||||
|
||||
// Include seed info file
|
||||
else if (LoadSeedInput.ProcessInput(args, ref index))
|
||||
Seed = Builder.CreateFromFile(LoadSeedInput.Value);
|
||||
|
||||
// Disable placeholder values in submission info
|
||||
else if (NoPlaceholdersInput.ProcessInput(args, ref index))
|
||||
Options.AddPlaceholders = !Options.AddPlaceholders;
|
||||
|
||||
// Create IRD from output files (PS3 only)
|
||||
else if (CreateIrdInput.ProcessInput(args, ref index))
|
||||
Options.CreateIRDAfterDumping = !Options.CreateIRDAfterDumping;
|
||||
|
||||
// Set the log compression type (requires compression enabled)
|
||||
else if (LogCompressionInput.ProcessInput(args, ref index))
|
||||
Options.LogCompression = LogCompressionInput.Value.ToLogCompression();
|
||||
|
||||
// Retrieve Redump match information
|
||||
else if (NoRetrieveInput.ProcessInput(args, ref index))
|
||||
Options.RetrieveMatchInformation = !Options.RetrieveMatchInformation;
|
||||
|
||||
// Redump login
|
||||
else if (args[index].StartsWith("-c=") || args[index].StartsWith("--credentials="))
|
||||
{
|
||||
string[] credentials = args[index].Split('=')[1].Split(';');
|
||||
Options.RedumpUsername = credentials[0];
|
||||
Options.RedumpPassword = credentials[1];
|
||||
}
|
||||
else if (args[index] == "-c" || args[index] == "--credentials")
|
||||
{
|
||||
Options.RedumpUsername = args[index + 1];
|
||||
Options.RedumpPassword = args[index + 2];
|
||||
index += 2;
|
||||
}
|
||||
|
||||
// Redump username
|
||||
else if (UsernameInput.ProcessInput(args, ref index))
|
||||
Options.RedumpUsername = UsernameInput.Value;
|
||||
|
||||
// Redump password
|
||||
else if (PasswordInput.ProcessInput(args, ref index))
|
||||
Options.RedumpPassword = PasswordInput.Value;
|
||||
|
||||
// Pull all information (requires Redump login)
|
||||
else if (PullAllInput.ProcessInput(args, ref index))
|
||||
Options.PullAllInformation = !Options.PullAllInformation;
|
||||
|
||||
// Use a device path for physical checks
|
||||
else if (PathInput.ProcessInput(args, ref index))
|
||||
DevicePath = PathInput.Value;
|
||||
|
||||
// Scan for protection (requires device path)
|
||||
else if (ScanInput.ProcessInput(args, ref index))
|
||||
scan = true;
|
||||
|
||||
// Disable scanning archives (requires --scan)
|
||||
else if (ScanInput.ProcessInput(args, ref index))
|
||||
enableArchives = false;
|
||||
|
||||
// Enable debug protection information (requires --scan)
|
||||
else if (EnableDebugInput.ProcessInput(args, ref index))
|
||||
enableDebug = true;
|
||||
|
||||
// Hide drive letters from scan output (requires --scan)
|
||||
else if (HideDriveLettersInput.ProcessInput(args, ref index))
|
||||
hideDriveLetters = true;
|
||||
|
||||
// Add filename suffix
|
||||
else if (SuffixInput.ProcessInput(args, ref index))
|
||||
Options.AddFilenameSuffix = !Options.AddFilenameSuffix;
|
||||
|
||||
// Output submission JSON
|
||||
else if (JsonInput.ProcessInput(args, ref index))
|
||||
Options.OutputSubmissionJSON = !Options.OutputSubmissionJSON;
|
||||
|
||||
// Include JSON artifacts
|
||||
else if (IncludeArtifactsInput.ProcessInput(args, ref index))
|
||||
Options.IncludeArtifacts = !Options.IncludeArtifacts;
|
||||
|
||||
// Compress log and extraneous files
|
||||
else if (ZipInput.ProcessInput(args, ref index))
|
||||
Options.CompressLogFiles = !Options.CompressLogFiles;
|
||||
|
||||
// Delete unnecessary files
|
||||
else if (DeleteInput.ProcessInput(args, ref index))
|
||||
Options.DeleteUnnecessaryFiles = !Options.DeleteUnnecessaryFiles;
|
||||
|
||||
// Default, add to inputs
|
||||
else
|
||||
Inputs.Add(args[index]);
|
||||
}
|
||||
|
||||
// Now deal with the complex options
|
||||
Options.ScanForProtection = scan && !string.IsNullOrEmpty(DevicePath);
|
||||
Options.ScanArchivesForProtection = enableArchives && scan && !string.IsNullOrEmpty(DevicePath);
|
||||
Options.IncludeDebugProtectionInformation = enableDebug && scan && !string.IsNullOrEmpty(DevicePath);
|
||||
Options.HideDriveLetters = hideDriveLetters && scan && !string.IsNullOrEmpty(DevicePath);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool VerifyInputs() => Inputs.Count > 0;
|
||||
}
|
||||
}
|
||||
@@ -1,37 +1,50 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net48;net6.0;net7.0</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<OutputType>Exe</OutputType>
|
||||
<Title>MPF Check</Title>
|
||||
<Description>Validator for various dumping programs</Description>
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
<Copyright>Copyright (c)2019-2023</Copyright>
|
||||
<VersionPrefix>2.7.5</VersionPrefix>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<OutputType>Exe</OutputType>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<NoWarn>NU1902;NU1903</NoWarn>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<VersionPrefix>3.6.0</VersionPrefix>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)'!='net48'">
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<!-- 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-2025</Copyright>
|
||||
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<!-- Support All Frameworks -->
|
||||
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net4`))">
|
||||
<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$(TargetFramework.StartsWith(`netcoreapp`)) OR $(TargetFramework.StartsWith(`net5`))">
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net6`)) OR $(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`)) OR $(TargetFramework.StartsWith(`net9`)) OR $(TargetFramework.StartsWith(`net10`))">
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$(RuntimeIdentifier.StartsWith(`osx-arm`))">
|
||||
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MPF.Frontend\MPF.Frontend.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="2.9.0" GeneratePathProperty="true">
|
||||
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="1.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="$(PkgBurnOutSharp)\content\**" PackagePath="contentFiles\any\any;content" CopyToOutputDirectory="Always" PackageCopyToOutput="true" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SabreTools.CommandLine" Version="[1.4.0]" />
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="[1.9.0]" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,11 +1,12 @@
|
||||
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;
|
||||
using System.Collections.Generic;
|
||||
#if NET40
|
||||
using System.Threading.Tasks;
|
||||
#endif
|
||||
using MPF.Check.Features;
|
||||
using MPF.Frontend.Features;
|
||||
using SabreTools.CommandLine;
|
||||
using SabreTools.CommandLine.Features;
|
||||
|
||||
namespace MPF.Check
|
||||
{
|
||||
@@ -13,106 +14,128 @@ namespace MPF.Check
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// Create the command set
|
||||
var mainFeature = new MainFeature();
|
||||
var commandSet = CreateCommands(mainFeature);
|
||||
|
||||
// If we have no args, show the help and quit
|
||||
if (args == null || args.Length == 0)
|
||||
{
|
||||
BaseFeature.DisplayHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the first argument as a feature flag
|
||||
string featureName = args[0];
|
||||
|
||||
// Try processing the standalone arguments
|
||||
bool? standaloneProcessed = OptionsLoader.ProcessStandaloneArguments(args);
|
||||
if (standaloneProcessed != false)
|
||||
var topLevel = commandSet.GetTopLevel(featureName);
|
||||
switch (topLevel)
|
||||
{
|
||||
if (standaloneProcessed == null)
|
||||
DisplayHelp();
|
||||
return;
|
||||
}
|
||||
// Standalone Options
|
||||
case Help: BaseFeature.DisplayHelp(); return;
|
||||
case VersionFeature version: version.Execute(); return;
|
||||
case ListCodesFeature lc: lc.Execute(); return;
|
||||
case ListConfigFeature lc: lc.Execute(); return;
|
||||
case ListMediaTypesFeature lm: lm.Execute(); return;
|
||||
case ListProgramsFeature lp: lp.Execute(); return;
|
||||
case ListSystemsFeature ls: ls.Execute(); return;
|
||||
|
||||
// Try processing the common arguments
|
||||
(bool success, MediaType mediaType, RedumpSystem? knownSystem, var error) = OptionsLoader.ProcessCommonArguments(args);
|
||||
if (!success)
|
||||
{
|
||||
DisplayHelp(error);
|
||||
return;
|
||||
}
|
||||
// Interactive Mode
|
||||
case InteractiveFeature interactive:
|
||||
if (!interactive.ProcessArgs(args, 0))
|
||||
{
|
||||
BaseFeature.DisplayHelp();
|
||||
return;
|
||||
}
|
||||
if (!interactive.VerifyInputs())
|
||||
{
|
||||
Console.Error.WriteLine("At least one input is required");
|
||||
BaseFeature.DisplayHelp();
|
||||
return;
|
||||
}
|
||||
if (!interactive.Execute())
|
||||
{
|
||||
BaseFeature.DisplayHelp();
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
||||
// Make new Progress objects
|
||||
var resultProgress = new Progress<Result>();
|
||||
resultProgress.ProgressChanged += ConsoleLogger.ProgressUpdated;
|
||||
var protectionProgress = new Progress<ProtectionProgress>();
|
||||
protectionProgress.ProgressChanged += ConsoleLogger.ProgressUpdated;
|
||||
// Default Behavior
|
||||
default:
|
||||
if (!mainFeature.ProcessArgs(args, 0))
|
||||
{
|
||||
BaseFeature.DisplayHelp();
|
||||
return;
|
||||
}
|
||||
if (!mainFeature.VerifyInputs())
|
||||
{
|
||||
Console.Error.WriteLine("At least one input is required");
|
||||
BaseFeature.DisplayHelp();
|
||||
return;
|
||||
}
|
||||
if (!mainFeature.Execute())
|
||||
{
|
||||
BaseFeature.DisplayHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate the supplied credentials
|
||||
#if NET48
|
||||
(bool? _, string message) = RedumpWebClient.ValidateCredentials(options?.RedumpUsername, options?.RedumpPassword);
|
||||
#else
|
||||
(bool? _, string? message) = RedumpHttpClient.ValidateCredentials(options.RedumpUsername ?? string.Empty, options.RedumpPassword ?? string.Empty).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
#endif
|
||||
if (!string.IsNullOrWhiteSpace(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
|
||||
#if NET48
|
||||
Drive drive = null;
|
||||
#else
|
||||
Drive? drive = null;
|
||||
#endif
|
||||
if (!string.IsNullOrWhiteSpace(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
|
||||
var result = env.VerifyAndSaveDumpOutput(resultProgress, protectionProgress).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
Console.WriteLine(result.Message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display help for MPF.Check
|
||||
/// Create the command set for the program
|
||||
/// </summary>
|
||||
/// <param name="error">Error string to prefix the help text with</param>
|
||||
#if NET48
|
||||
private static void DisplayHelp(string error = null)
|
||||
#else
|
||||
private static void DisplayHelp(string? error = null)
|
||||
#endif
|
||||
private static CommandSet CreateCommands(MainFeature mainFeature)
|
||||
{
|
||||
if (error != null)
|
||||
Console.WriteLine(error);
|
||||
List<string> header = [
|
||||
"MPF.CLI [standalone|system] [options] <path> ...",
|
||||
string.Empty,
|
||||
];
|
||||
|
||||
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();
|
||||
List<string> footer = [
|
||||
string.Empty,
|
||||
"WARNING: Check will overwrite both any existing submission information files as well",
|
||||
"as any log archives. Please make backups of those if you need to before running Check.",
|
||||
string.Empty,
|
||||
];
|
||||
|
||||
Console.WriteLine("Check Options:");
|
||||
var supportedArguments = OptionsLoader.PrintSupportedArguments();
|
||||
foreach (string argument in supportedArguments)
|
||||
{
|
||||
Console.WriteLine(argument);
|
||||
}
|
||||
Console.WriteLine();
|
||||
var commandSet = new CommandSet(header, footer);
|
||||
|
||||
// Standalone Options
|
||||
commandSet.Add(new Help());
|
||||
commandSet.Add(new VersionFeature());
|
||||
commandSet.Add(new ListCodesFeature());
|
||||
commandSet.Add(new ListConfigFeature());
|
||||
commandSet.Add(new ListMediaTypesFeature());
|
||||
commandSet.Add(new ListSystemsFeature());
|
||||
commandSet.Add(new ListProgramsFeature());
|
||||
commandSet.Add(new InteractiveFeature());
|
||||
|
||||
// Check Options
|
||||
commandSet.Add(mainFeature.UseInput);
|
||||
commandSet.Add(mainFeature.LoadSeedInput);
|
||||
commandSet.Add(mainFeature.NoPlaceholdersInput);
|
||||
commandSet.Add(mainFeature.CreateIrdInput);
|
||||
commandSet.Add(mainFeature.NoRetrieveInput);
|
||||
commandSet.Add(mainFeature.UsernameInput);
|
||||
commandSet.Add(mainFeature.PasswordInput);
|
||||
commandSet.Add(mainFeature.PullAllInput);
|
||||
commandSet.Add(mainFeature.PathInput);
|
||||
commandSet.Add(mainFeature.ScanInput);
|
||||
commandSet.Add(mainFeature.DisableArchivesInput);
|
||||
commandSet.Add(mainFeature.EnableDebugInput);
|
||||
commandSet.Add(mainFeature.HideDriveLettersInput);
|
||||
commandSet.Add(mainFeature.SuffixInput);
|
||||
commandSet.Add(mainFeature.JsonInput);
|
||||
commandSet.Add(mainFeature.IncludeArtifactsInput);
|
||||
commandSet.Add(mainFeature.ZipInput);
|
||||
commandSet.Add(mainFeature.LogCompressionInput);
|
||||
commandSet.Add(mainFeature.DeleteInput);
|
||||
|
||||
return commandSet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"profiles": {
|
||||
"MPF.Check": {
|
||||
"commandName": "Project"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,345 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
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)
|
||||
{
|
||||
switch (driveType)
|
||||
{
|
||||
case DriveType.CDRom:
|
||||
return InternalDriveType.Optical;
|
||||
case DriveType.Fixed:
|
||||
return InternalDriveType.HardDisk;
|
||||
case DriveType.Removable:
|
||||
return InternalDriveType.Removable;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Convert to Long Name
|
||||
|
||||
/// <summary>
|
||||
/// Long name method cache
|
||||
/// </summary>
|
||||
#if NET48
|
||||
private static readonly ConcurrentDictionary<Type, MethodInfo> LongNameMethods = new ConcurrentDictionary<Type, MethodInfo>();
|
||||
#else
|
||||
private static readonly ConcurrentDictionary<Type, MethodInfo?> LongNameMethods = new ConcurrentDictionary<Type, MethodInfo?>();
|
||||
#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", new[] { typeof(Nullable<>).MakeGenericType(sourceType) });
|
||||
if (method == null)
|
||||
method = typeof(EnumConverter).GetMethod("LongName", new[] { typeof(Nullable<>).MakeGenericType(sourceType) });
|
||||
|
||||
LongNameMethods.TryAdd(sourceType, method);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
switch (prog)
|
||||
{
|
||||
#region Dumping support
|
||||
|
||||
case InternalProgram.Aaru:
|
||||
return "Aaru";
|
||||
case InternalProgram.DiscImageCreator:
|
||||
return "DiscImageCreator";
|
||||
case InternalProgram.Redumper:
|
||||
return "Redumper";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Verification support only
|
||||
|
||||
case InternalProgram.CleanRip:
|
||||
return "CleanRip";
|
||||
|
||||
case InternalProgram.DCDumper:
|
||||
return "DCDumper";
|
||||
|
||||
case InternalProgram.UmdImageCreator:
|
||||
return "UmdImageCreator";
|
||||
|
||||
#endregion
|
||||
|
||||
case InternalProgram.NONE:
|
||||
default:
|
||||
return "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>
|
||||
#if NET48
|
||||
public static InternalProgram ToInternalProgram(string internalProgram)
|
||||
#else
|
||||
public static InternalProgram ToInternalProgram(string? internalProgram)
|
||||
#endif
|
||||
{
|
||||
switch (internalProgram?.ToLowerInvariant())
|
||||
{
|
||||
// Dumping support
|
||||
case "aaru":
|
||||
case "chef":
|
||||
case "dichef":
|
||||
case "discimagechef":
|
||||
return InternalProgram.Aaru;
|
||||
case "creator":
|
||||
case "dic":
|
||||
case "dicreator":
|
||||
case "discimagecreator":
|
||||
return InternalProgram.DiscImageCreator;
|
||||
case "rd":
|
||||
case "redumper":
|
||||
return InternalProgram.Redumper;
|
||||
|
||||
// Verification support only
|
||||
case "cleanrip":
|
||||
case "cr":
|
||||
return InternalProgram.CleanRip;
|
||||
case "dc":
|
||||
case "dcd":
|
||||
case "dcdumper":
|
||||
return InternalProgram.DCDumper;
|
||||
case "uic":
|
||||
case "umd":
|
||||
case "umdcreator":
|
||||
case "umdimagecreator":
|
||||
return InternalProgram.UmdImageCreator;
|
||||
|
||||
default:
|
||||
return 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)
|
||||
{
|
||||
switch (type.ToLowerInvariant())
|
||||
{
|
||||
#region Punched Media
|
||||
|
||||
case "aperture":
|
||||
case "aperturecard":
|
||||
case "aperture card":
|
||||
return MediaType.ApertureCard;
|
||||
case "jacquardloom":
|
||||
case "jacquardloomcard":
|
||||
case "jacquard loom card":
|
||||
return MediaType.JacquardLoomCard;
|
||||
case "magneticstripe":
|
||||
case "magneticstripecard":
|
||||
case "magnetic stripe card":
|
||||
return MediaType.MagneticStripeCard;
|
||||
case "opticalphone":
|
||||
case "opticalphonecard":
|
||||
case "optical phonecard":
|
||||
return MediaType.OpticalPhonecard;
|
||||
case "punchcard":
|
||||
case "punchedcard":
|
||||
case "punched card":
|
||||
return MediaType.PunchedCard;
|
||||
case "punchtape":
|
||||
case "punchedtape":
|
||||
case "punched tape":
|
||||
return MediaType.PunchedTape;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tape
|
||||
|
||||
case "openreel":
|
||||
case "openreeltape":
|
||||
case "open reel tape":
|
||||
return MediaType.OpenReel;
|
||||
case "datacart":
|
||||
case "datacartridge":
|
||||
case "datatapecartridge":
|
||||
case "data tape cartridge":
|
||||
return MediaType.DataCartridge;
|
||||
case "cassette":
|
||||
case "cassettetape":
|
||||
case "cassette tape":
|
||||
return MediaType.Cassette;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Disc / Disc
|
||||
|
||||
case "bd":
|
||||
case "bdrom":
|
||||
case "bd-rom":
|
||||
case "bluray":
|
||||
return MediaType.BluRay;
|
||||
case "cd":
|
||||
case "cdrom":
|
||||
case "cd-rom":
|
||||
return MediaType.CDROM;
|
||||
case "dvd":
|
||||
case "dvd5":
|
||||
case "dvd-5":
|
||||
case "dvd9":
|
||||
case "dvd-9":
|
||||
case "dvdrom":
|
||||
case "dvd-rom":
|
||||
return MediaType.DVD;
|
||||
case "fd":
|
||||
case "floppy":
|
||||
case "floppydisk":
|
||||
case "floppy disk":
|
||||
case "floppy diskette":
|
||||
return MediaType.FloppyDisk;
|
||||
case "floptical":
|
||||
return MediaType.Floptical;
|
||||
case "gd":
|
||||
case "gdrom":
|
||||
case "gd-rom":
|
||||
return MediaType.GDROM;
|
||||
case "hddvd":
|
||||
case "hd-dvd":
|
||||
case "hddvdrom":
|
||||
case "hd-dvd-rom":
|
||||
return MediaType.HDDVD;
|
||||
case "hdd":
|
||||
case "harddisk":
|
||||
case "hard disk":
|
||||
return MediaType.HardDisk;
|
||||
case "bernoullidisk":
|
||||
case "iomegabernoullidisk":
|
||||
case "bernoulli disk":
|
||||
case "iomega bernoulli disk":
|
||||
return MediaType.IomegaBernoulliDisk;
|
||||
case "jaz":
|
||||
case "iomegajaz":
|
||||
case "iomega jaz":
|
||||
return MediaType.IomegaJaz;
|
||||
case "zip":
|
||||
case "zipdisk":
|
||||
case "iomegazip":
|
||||
case "iomega zip":
|
||||
return MediaType.IomegaZip;
|
||||
case "ldrom":
|
||||
case "lvrom":
|
||||
case "ld-rom":
|
||||
case "lv-rom":
|
||||
case "laserdisc":
|
||||
case "laservision":
|
||||
case "ld-rom / lv-rom":
|
||||
return MediaType.LaserDisc;
|
||||
case "64dd":
|
||||
case "n64dd":
|
||||
case "64dddisk":
|
||||
case "n64dddisk":
|
||||
case "64dd disk":
|
||||
case "n64dd disk":
|
||||
return MediaType.Nintendo64DD;
|
||||
case "fds":
|
||||
case "famicom":
|
||||
case "nfds":
|
||||
case "nintendofamicom":
|
||||
case "famicomdisksystem":
|
||||
case "famicom disk system":
|
||||
case "famicom disk system disk":
|
||||
return MediaType.NintendoFamicomDiskSystem;
|
||||
case "gc":
|
||||
case "gamecube":
|
||||
case "nintendogamecube":
|
||||
case "nintendo gamecube":
|
||||
case "gamecube disc":
|
||||
case "gamecube game disc":
|
||||
return MediaType.NintendoGameCubeGameDisc;
|
||||
case "wii":
|
||||
case "nintendowii":
|
||||
case "nintendo wii":
|
||||
case "nintendo wii disc":
|
||||
case "wii optical disc":
|
||||
return MediaType.NintendoWiiOpticalDisc;
|
||||
case "wiiu":
|
||||
case "nintendowiiu":
|
||||
case "nintendo wiiu":
|
||||
case "nintendo wiiu disc":
|
||||
case "wiiu optical disc":
|
||||
case "wii u optical disc":
|
||||
return MediaType.NintendoWiiUOpticalDisc;
|
||||
case "umd":
|
||||
return MediaType.UMD;
|
||||
|
||||
#endregion
|
||||
|
||||
// Unsorted Formats
|
||||
case "cartridge":
|
||||
return MediaType.Cartridge;
|
||||
case "ced":
|
||||
case "rcaced":
|
||||
case "rca ced":
|
||||
case "videodisc":
|
||||
case "rca videodisc":
|
||||
return MediaType.CED;
|
||||
|
||||
default:
|
||||
return MediaType.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
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 = new byte[] { 0x53, 0x45, 0x47, 0x41, 0x20, 0x53, 0x45, 0x47, 0x41, 0x53, 0x41, 0x54, 0x55, 0x52, 0x4E, 0x20 };
|
||||
|
||||
// Lists of known drive speed ranges
|
||||
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 };
|
||||
|
||||
/// <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.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return DVD;
|
||||
case MediaType.HDDVD:
|
||||
return HDDVD;
|
||||
case MediaType.BluRay:
|
||||
return BD;
|
||||
default:
|
||||
return Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 DumpingProgramField = "Dumping Program";
|
||||
public const string DumpingDateField = "Date";
|
||||
public const string DumpingDriveManufacturer = "Manufacturer";
|
||||
public const string DumpingDriveModel = "Model";
|
||||
public const string DumpingDriveFirmware = "Firmware";
|
||||
public const string ReportedDiscType = "Reported Disc Type";
|
||||
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 FullyMatchingIDField = "Fully Matching ID";
|
||||
public const string PartiallyMatchingIDsField = "Partially 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 XBOXSSRanges = "Security Sector Ranges";
|
||||
|
||||
// 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,602 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Management.Infrastructure;
|
||||
using Microsoft.Management.Infrastructure.Generic;
|
||||
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>
|
||||
#if NET48
|
||||
public string DriveFormat { get; private set; } = null;
|
||||
#else
|
||||
public string? DriveFormat { get; private set; } = null;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Windows drive path
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string Name { get; private set; } = null;
|
||||
#else
|
||||
public string? Name { get; private set; } = null;
|
||||
#endif
|
||||
|
||||
/// <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>
|
||||
#if NET48
|
||||
public string VolumeLabel { get; private set; } = null;
|
||||
#else
|
||||
public string? VolumeLabel { get; private set; } = null;
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region Derived Fields
|
||||
|
||||
/// <summary>
|
||||
/// Media label as read by Windows, formatted to avoid odd outputs
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string FormattedVolumeLabel
|
||||
#else
|
||||
public string? FormattedVolumeLabel
|
||||
#endif
|
||||
{
|
||||
get
|
||||
{
|
||||
string volumeLabel = Template.DiscNotDetected;
|
||||
if (this.MarkedActive)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(this.VolumeLabel))
|
||||
volumeLabel = "track";
|
||||
else
|
||||
volumeLabel = this.VolumeLabel;
|
||||
}
|
||||
|
||||
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>
|
||||
#if NET48
|
||||
public static Drive Create(InternalDriveType? driveType, string devicePath)
|
||||
#else
|
||||
public static Drive? Create(InternalDriveType? driveType, string devicePath)
|
||||
#endif
|
||||
{
|
||||
// Create a new, empty drive object
|
||||
var drive = new Drive()
|
||||
{
|
||||
InternalDriveType = driveType,
|
||||
};
|
||||
|
||||
// If we have an invalid device path, return null
|
||||
if (string.IsNullOrWhiteSpace(devicePath))
|
||||
return null;
|
||||
|
||||
// Sanitize a Windows-formatted long device path
|
||||
if (devicePath.StartsWith("\\\\.\\"))
|
||||
#if NET48
|
||||
devicePath = devicePath.Substring("\\\\.\\".Length);
|
||||
#else
|
||||
devicePath = devicePath["\\\\.\\".Length..];
|
||||
#endif
|
||||
|
||||
// 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>
|
||||
#if NET48
|
||||
private void PopulateFromDriveInfo(DriveInfo driveInfo)
|
||||
#else
|
||||
private void PopulateFromDriveInfo(DriveInfo? driveInfo)
|
||||
#endif
|
||||
{
|
||||
// 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).ToList();
|
||||
return drives;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current media type from drive letter
|
||||
/// </summary>
|
||||
/// <param name="system"></param>
|
||||
/// <returns></returns>
|
||||
#if NET48
|
||||
public (MediaType?, string) GetMediaType(RedumpSystem? system)
|
||||
#else
|
||||
public (MediaType?, string?) GetMediaType(RedumpSystem? system)
|
||||
#endif
|
||||
{
|
||||
// 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 (!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();
|
||||
if (systemFromLabel != null)
|
||||
return systemFromLabel;
|
||||
|
||||
// Get a list of files for quicker checking
|
||||
#region Consoles
|
||||
|
||||
// Bandai Playdia Quick Interactive System
|
||||
try
|
||||
{
|
||||
List<string> files = Directory.EnumerateFiles(this.Name, "*", SearchOption.TopDirectoryOnly).ToList();
|
||||
|
||||
if (files.Any(f => f.EndsWith(".AJS", StringComparison.OrdinalIgnoreCase))
|
||||
&& files.Any(f => f.EndsWith(".GLB", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return RedumpSystem.BandaiPlaydiaQuickInteractiveSystem;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Mattel Fisher-Price iXL
|
||||
if (File.Exists(Path.Combine(this.Name, "iXL", "iXLUpdater.exe")))
|
||||
{
|
||||
return RedumpSystem.MattelFisherPriceiXL;
|
||||
}
|
||||
|
||||
// Microsoft Xbox 360
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(this.Name, "$SystemUpdate"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(this.Name, "$SystemUpdate")).Any()
|
||||
&& this.TotalSize <= 500_000_000)
|
||||
{
|
||||
return RedumpSystem.MicrosoftXbox360;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Microsoft Xbox One
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(this.Name, "MSXC"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(this.Name, "MSXC")).Any())
|
||||
{
|
||||
return RedumpSystem.MicrosoftXboxOne;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Sega Dreamcast
|
||||
if (File.Exists(Path.Combine(this.Name, "IP.BIN")))
|
||||
{
|
||||
return RedumpSystem.SegaDreamcast;
|
||||
}
|
||||
|
||||
// Sega Mega-CD / Sega-CD
|
||||
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")))
|
||||
{
|
||||
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 (File.Exists(Path.Combine(this.Name, "PS4", "UPDATE", "PS4UPDATE.PUP")))
|
||||
{
|
||||
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"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(this.Name, "AUDIO_TS")).Any())
|
||||
{
|
||||
return RedumpSystem.DVDAudio;
|
||||
}
|
||||
|
||||
else if (Directory.Exists(Path.Combine(this.Name, "VIDEO_TS"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(this.Name, "VIDEO_TS")).Any())
|
||||
{
|
||||
return RedumpSystem.DVDVideo;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// HD-DVD-Video
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(this.Name, "HVDVD_TS"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(this.Name, "HVDVD_TS")).Any())
|
||||
{
|
||||
return RedumpSystem.HDDVDVideo;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// VCD
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(this.Name, "VCD"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(this.Name, "VCD")).Any())
|
||||
{
|
||||
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 RedumpSystem? GetRedumpSystemFromVolumeLabel()
|
||||
{
|
||||
// If the volume label is empty, we can't do anything
|
||||
if (string.IsNullOrWhiteSpace(this.VolumeLabel))
|
||||
return null;
|
||||
|
||||
// Audio CD
|
||||
if (this.VolumeLabel.Equals("Audio CD", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.AudioCD;
|
||||
|
||||
// Microsoft Xbox
|
||||
if (this.VolumeLabel.Equals("SEP13011042", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.MicrosoftXbox;
|
||||
else if (this.VolumeLabel.Equals("SEP13011042072", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.MicrosoftXbox;
|
||||
|
||||
// Microsoft Xbox 360
|
||||
if (this.VolumeLabel.Equals("XBOX360", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.MicrosoftXbox360;
|
||||
else if (this.VolumeLabel.Equals("XGD2DVD_NTSC", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.MicrosoftXbox360;
|
||||
|
||||
// Microsoft Xbox 360 - Too overly broad even if a lot of discs use this
|
||||
//if (this.VolumeLabel.Equals("CD_ROM", StringComparison.OrdinalIgnoreCase))
|
||||
// return RedumpSystem.MicrosoftXbox360; // Also for Xbox One?
|
||||
//if (this.VolumeLabel.Equals("DVD_ROM", StringComparison.OrdinalIgnoreCase))
|
||||
// return RedumpSystem.MicrosoftXbox360;
|
||||
|
||||
// Sega Mega-CD / Sega-CD
|
||||
if (this.VolumeLabel.Equals("Sega_CD", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.SegaMegaCDSegaCD;
|
||||
|
||||
// Sony PlayStation 3
|
||||
if (this.VolumeLabel.Equals("PS3VOLUME", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.SonyPlayStation3;
|
||||
|
||||
// Sony PlayStation 4
|
||||
if (this.VolumeLabel.Equals("PS4VOLUME", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.SonyPlayStation4;
|
||||
|
||||
// Sony PlayStation 5
|
||||
if (this.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
|
||||
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
|
||||
}
|
||||
|
||||
return drives;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,320 +0,0 @@
|
||||
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>
|
||||
{
|
||||
#if NET48
|
||||
private Dictionary<string, string> _keyValuePairs = new Dictionary<string, string>();
|
||||
#else
|
||||
private Dictionary<string, string> _keyValuePairs = new();
|
||||
#endif
|
||||
|
||||
public string this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
#if NET48
|
||||
if (_keyValuePairs == null)
|
||||
_keyValuePairs = new Dictionary<string, string>();
|
||||
#else
|
||||
_keyValuePairs ??= new Dictionary<string, string>();
|
||||
#endif
|
||||
|
||||
key = key.ToLowerInvariant();
|
||||
if (_keyValuePairs.ContainsKey(key))
|
||||
return _keyValuePairs[key];
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
set
|
||||
{
|
||||
#if NET48
|
||||
if (_keyValuePairs == null)
|
||||
_keyValuePairs = new Dictionary<string, string>();
|
||||
#else
|
||||
_keyValuePairs ??= new Dictionary<string, string>();
|
||||
#endif
|
||||
|
||||
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.IsNullOrWhiteSpace(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
|
||||
#if NET48
|
||||
else if (line.Contains("="))
|
||||
#else
|
||||
else if (line.Contains('='))
|
||||
#endif
|
||||
{
|
||||
// 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)).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
|
||||
{
|
||||
using (var sw = new StreamWriter(stream))
|
||||
{
|
||||
// Order the dictionary by keys to link sections together
|
||||
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)).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
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
public class ProcessingQueue<T> : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Internal queue to hold data to process
|
||||
/// </summary>
|
||||
private readonly ConcurrentQueue<T> InternalQueue;
|
||||
|
||||
/// <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)
|
||||
{
|
||||
this.InternalQueue = new ConcurrentQueue<T>();
|
||||
this.CustomProcessing = customProcessing;
|
||||
this.TokenSource = new CancellationTokenSource();
|
||||
Task.Run(() => ProcessQueue(), this.TokenSource.Token);
|
||||
}
|
||||
|
||||
/// <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 (this.InternalQueue.Count == 0)
|
||||
{
|
||||
if (this.TokenSource.IsCancellationRequested)
|
||||
break;
|
||||
|
||||
Thread.Sleep(10);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the next item from the queue
|
||||
if (!this.InternalQueue.TryDequeue(out var nextItem))
|
||||
continue;
|
||||
|
||||
// Invoke the lambda, if possible
|
||||
this.CustomProcessing?.Invoke(nextItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,651 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BinaryObjectScanner;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.Modules;
|
||||
using MPF.Core.Utilities;
|
||||
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>
|
||||
#if NET48
|
||||
public Drive Drive { get; private set; }
|
||||
#else
|
||||
public Drive? Drive { get; private set; }
|
||||
#endif
|
||||
|
||||
/// <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>
|
||||
#if NET48
|
||||
public BaseParameters Parameters { get; private set; }
|
||||
#else
|
||||
public BaseParameters? Parameters { get; private set; }
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Generic way of reporting a message
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public EventHandler<string> ReportStatus;
|
||||
#else
|
||||
public EventHandler<string>? ReportStatus;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Queue of items that need to be logged
|
||||
/// </summary>
|
||||
#if NET48
|
||||
private ProcessingQueue<string> outputQueue;
|
||||
#else
|
||||
private ProcessingQueue<string>? outputQueue;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Event handler for data returned from a process
|
||||
/// </summary>
|
||||
#if NET48
|
||||
private void OutputToLog(object proc, string args) => outputQueue?.Enqueue(args);
|
||||
#else
|
||||
private void OutputToLog(object? proc, string args) => outputQueue?.Enqueue(args);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Process the outputs in the queue
|
||||
/// </summary>
|
||||
private void ProcessOutputs(string nextOutput) => ReportStatus?.Invoke(this, nextOutput);
|
||||
|
||||
#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,
|
||||
#if NET48
|
||||
Drive drive,
|
||||
#else
|
||||
Drive? drive,
|
||||
#endif
|
||||
RedumpSystem? system,
|
||||
MediaType? type,
|
||||
InternalProgram? internalProgram,
|
||||
#if NET48
|
||||
string parameters)
|
||||
#else
|
||||
string? parameters)
|
||||
#endif
|
||||
{
|
||||
// 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>
|
||||
#if NET48
|
||||
public void SetParameters(string parameters)
|
||||
#else
|
||||
public void SetParameters(string? parameters)
|
||||
#endif
|
||||
{
|
||||
#if NET48
|
||||
switch (InternalProgram)
|
||||
{
|
||||
// Dumping support
|
||||
case InternalProgram.Aaru:
|
||||
Parameters = new Modules.Aaru.Parameters(parameters) { ExecutablePath = Options.AaruPath };
|
||||
break;
|
||||
|
||||
case InternalProgram.DiscImageCreator:
|
||||
Parameters = new Modules.DiscImageCreator.Parameters(parameters) { ExecutablePath = Options.DiscImageCreatorPath };
|
||||
break;
|
||||
|
||||
case InternalProgram.Redumper:
|
||||
Parameters = new Modules.Redumper.Parameters(parameters) { ExecutablePath = Options.RedumperPath };
|
||||
break;
|
||||
|
||||
// Verification support only
|
||||
case InternalProgram.CleanRip:
|
||||
Parameters = new Modules.CleanRip.Parameters(parameters) { ExecutablePath = null };
|
||||
break;
|
||||
|
||||
case InternalProgram.DCDumper:
|
||||
Parameters = null; // TODO: Create correct parameter type when supported
|
||||
break;
|
||||
|
||||
case InternalProgram.UmdImageCreator:
|
||||
Parameters = new Modules.UmdImageCreator.Parameters(parameters) { ExecutablePath = null };
|
||||
break;
|
||||
|
||||
// This should never happen, but it needs a fallback
|
||||
default:
|
||||
Parameters = new Modules.DiscImageCreator.Parameters(parameters) { ExecutablePath = Options.DiscImageCreatorPath };
|
||||
break;
|
||||
}
|
||||
#else
|
||||
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.UmdImageCreator => new Modules.UmdImageCreator.Parameters(parameters) { ExecutablePath = null },
|
||||
|
||||
// This should never happen, but it needs a fallback
|
||||
_ => new Modules.DiscImageCreator.Parameters(parameters) { ExecutablePath = Options.DiscImageCreatorPath },
|
||||
};
|
||||
#endif
|
||||
|
||||
// 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>
|
||||
#if NET48
|
||||
public string GetFullParameters(int? driveSpeed)
|
||||
#else
|
||||
public string? GetFullParameters(int? driveSpeed)
|
||||
#endif
|
||||
{
|
||||
// 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
|
||||
#if NET48
|
||||
switch (InternalProgram)
|
||||
{
|
||||
case InternalProgram.Aaru:
|
||||
Parameters = new Modules.Aaru.Parameters(System, Type, Drive.Name, OutputPath, driveSpeed, Options);
|
||||
break;
|
||||
|
||||
case InternalProgram.DiscImageCreator:
|
||||
Parameters = new Modules.DiscImageCreator.Parameters(System, Type, Drive.Name, OutputPath, driveSpeed, Options);
|
||||
break;
|
||||
|
||||
case InternalProgram.Redumper:
|
||||
Parameters = new Modules.Redumper.Parameters(System, Type, Drive.Name, OutputPath, driveSpeed, Options);
|
||||
break;
|
||||
|
||||
// This should never happen, but it needs a fallback
|
||||
default:
|
||||
Parameters = new Modules.DiscImageCreator.Parameters(System, Type, Drive.Name, OutputPath, driveSpeed, Options);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
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),
|
||||
|
||||
// This should never happen, but it needs a fallback
|
||||
_ => new Modules.DiscImageCreator.Parameters(System, Type, Drive.Name, OutputPath, driveSpeed, Options),
|
||||
};
|
||||
#endif
|
||||
|
||||
// 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>
|
||||
#if NET48
|
||||
public async Task<string> EjectDisc() =>
|
||||
#else
|
||||
public async Task<string?> EjectDisc() =>
|
||||
#endif
|
||||
await RunStandaloneDiscImageCreatorCommand(Modules.DiscImageCreator.CommandStrings.Eject);
|
||||
|
||||
/// <summary>
|
||||
/// Reset the current drive using DiscImageCreator
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public async Task<string> ResetDrive() =>
|
||||
#else
|
||||
public async Task<string?> ResetDrive() =>
|
||||
#endif
|
||||
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 NET48
|
||||
public async Task<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.IsNullOrWhiteSpace(directoryName))
|
||||
Directory.CreateDirectory(directoryName);
|
||||
|
||||
await Task.Run(() => Parameters.ExecuteInternalProgram(Options.ToolsInSeparateWindow));
|
||||
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(
|
||||
#if NET48
|
||||
IProgress<Result> resultProgress = null,
|
||||
IProgress<ProtectionProgress> protectionProgress = null,
|
||||
Func<SubmissionInfo, (bool?, SubmissionInfo)> processUserInfo = null,
|
||||
SubmissionInfo seedInfo = null)
|
||||
#else
|
||||
IProgress<Result>? resultProgress = null,
|
||||
IProgress<ProtectionProgress>? protectionProgress = null,
|
||||
Func<SubmissionInfo?, (bool?, SubmissionInfo?)>? processUserInfo = null,
|
||||
SubmissionInfo? seedInfo = null)
|
||||
#endif
|
||||
{
|
||||
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) = InfoTool.FoundAllFiles(outputDirectory, outputFilename, Parameters, 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..."));
|
||||
SubmissionInfoTool.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..."));
|
||||
InfoTool.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) = InfoTool.FormatOutputData(submissionInfo, Options);
|
||||
if (formattedValues == null)
|
||||
resultProgress?.Report(Result.Success(formatResult));
|
||||
else
|
||||
resultProgress?.Report(Result.Failure(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);
|
||||
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));
|
||||
}
|
||||
|
||||
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;
|
||||
string output = await Task.Run(() =>
|
||||
{
|
||||
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.IsNullOrWhiteSpace(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>
|
||||
#if NET48
|
||||
private async Task<string> RunStandaloneDiscImageCreatorCommand(string command)
|
||||
#else
|
||||
private async Task<string?> RunStandaloneDiscImageCreatorCommand(string command)
|
||||
#endif
|
||||
{
|
||||
// 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
|
||||
}
|
||||
}
|
||||
@@ -1,401 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Hashing;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
using MPF.Core.Data;
|
||||
|
||||
namespace MPF.Core.Hashing
|
||||
{
|
||||
public sealed class Hasher : IDisposable
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Hash type associated with the current state
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public Hash HashType { get; private set; }
|
||||
#else
|
||||
public Hash HashType { get; init; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Current hash in bytes
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public byte[] CurrentHashBytes
|
||||
#else
|
||||
public byte[]? CurrentHashBytes
|
||||
#endif
|
||||
{
|
||||
get
|
||||
{
|
||||
#if NET48
|
||||
switch (_hasher)
|
||||
{
|
||||
case HashAlgorithm ha:
|
||||
return ha.Hash;
|
||||
case NonCryptographicHashAlgorithm ncha:
|
||||
return ncha.GetCurrentHash().Reverse().ToArray();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
#else
|
||||
return (_hasher) switch
|
||||
{
|
||||
HashAlgorithm ha => ha.Hash,
|
||||
NonCryptographicHashAlgorithm ncha => ncha.GetCurrentHash().Reverse().ToArray(),
|
||||
_ => null,
|
||||
};
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Current hash as a string
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string CurrentHashString => ByteArrayToString(CurrentHashBytes);
|
||||
#else
|
||||
public string? CurrentHashString => ByteArrayToString(CurrentHashBytes);
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Internal hasher being used for processing
|
||||
/// </summary>
|
||||
/// <remarks>May be either a HashAlgorithm or NonCryptographicHashAlgorithm</remarks>
|
||||
#if NET48
|
||||
private object _hasher;
|
||||
#else
|
||||
private object? _hasher;
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="hashType">Hash type to instantiate</param>
|
||||
public Hasher(Hash hashType)
|
||||
{
|
||||
this.HashType = hashType;
|
||||
GetHasher();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the correct hashing class based on the hash type
|
||||
/// </summary>
|
||||
private void GetHasher()
|
||||
{
|
||||
#if NET48
|
||||
switch (HashType)
|
||||
{
|
||||
case Hash.CRC32:
|
||||
_hasher = new Crc32();
|
||||
break;
|
||||
case Hash.CRC64:
|
||||
_hasher = new Crc64();
|
||||
break;
|
||||
case Hash.MD5:
|
||||
_hasher = MD5.Create();
|
||||
break;
|
||||
case Hash.SHA1:
|
||||
_hasher = SHA1.Create();
|
||||
break;
|
||||
case Hash.SHA256:
|
||||
_hasher = SHA256.Create();
|
||||
break;
|
||||
case Hash.SHA384:
|
||||
_hasher = SHA384.Create();
|
||||
break;
|
||||
case Hash.SHA512:
|
||||
_hasher = SHA512.Create();
|
||||
break;
|
||||
case Hash.XxHash32:
|
||||
_hasher = new XxHash32();
|
||||
break;
|
||||
case Hash.XxHash64:
|
||||
_hasher = new XxHash64();
|
||||
break;
|
||||
}
|
||||
#else
|
||||
_hasher = HashType switch
|
||||
{
|
||||
Hash.CRC32 => new Crc32(),
|
||||
Hash.CRC64 => new Crc64(),
|
||||
Hash.MD5 => MD5.Create(),
|
||||
Hash.SHA1 => SHA1.Create(),
|
||||
Hash.SHA256 => SHA256.Create(),
|
||||
Hash.SHA384 => SHA384.Create(),
|
||||
Hash.SHA512 => SHA512.Create(),
|
||||
Hash.XxHash32 => new XxHash32(),
|
||||
Hash.XxHash64 => new XxHash64(),
|
||||
_ => null,
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
if (_hasher is IDisposable disposable)
|
||||
disposable.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static Hashing
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input file path
|
||||
/// </summary>
|
||||
/// <param name="filename">Path to the input file</param>
|
||||
/// <returns>True if hashing was successful, false otherwise</returns>
|
||||
#if NET48
|
||||
public static bool GetFileHashes(string filename, out long size, out string crc32, out string md5, out string sha1)
|
||||
#else
|
||||
public static bool GetFileHashes(string filename, out long size, out string? crc32, out string? md5, out string? sha1)
|
||||
#endif
|
||||
{
|
||||
// Set all initial values
|
||||
crc32 = null; md5 = null; sha1 = null;
|
||||
|
||||
// Get all file hashes
|
||||
var fileHashes = GetFileHashes(filename, out size);
|
||||
if (fileHashes == null)
|
||||
return false;
|
||||
|
||||
// Assign the file hashes and return
|
||||
crc32 = fileHashes[Hash.CRC32];
|
||||
md5 = fileHashes[Hash.MD5];
|
||||
sha1 = fileHashes[Hash.SHA1];
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input file path
|
||||
/// </summary>
|
||||
/// <param name="filename">Path to the input file</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
#if NET48
|
||||
public static Dictionary<Hash, string> GetFileHashes(string filename, out long size)
|
||||
#else
|
||||
public static Dictionary<Hash, string?>? GetFileHashes(string filename, out long size)
|
||||
#endif
|
||||
{
|
||||
// If the file doesn't exist, we can't do anything
|
||||
if (!File.Exists(filename))
|
||||
{
|
||||
size = -1;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Set the file size
|
||||
size = new FileInfo(filename).Length;
|
||||
|
||||
// Create the output dictionary
|
||||
#if NET48
|
||||
var hashDict = new Dictionary<Hash, string>();
|
||||
#else
|
||||
var hashDict = new Dictionary<Hash, string?>();
|
||||
#endif
|
||||
|
||||
// Open the input file
|
||||
var input = File.OpenRead(filename);
|
||||
|
||||
// Return the hashes from the stream
|
||||
return GetStreamHashes(input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
#if NET48
|
||||
public static Dictionary<Hash, string> GetStreamHashes(Stream input)
|
||||
#else
|
||||
public static Dictionary<Hash, string?>? GetStreamHashes(Stream input)
|
||||
#endif
|
||||
{
|
||||
// Create the output dictionary
|
||||
#if NET48
|
||||
var hashDict = new Dictionary<Hash, string>();
|
||||
#else
|
||||
var hashDict = new Dictionary<Hash, string?>();
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
// Get a list of hashers to run over the buffer
|
||||
var hashers = new Dictionary<Hash, Hasher>
|
||||
{
|
||||
{ Hash.CRC32, new Hasher(Hash.CRC32) },
|
||||
{ Hash.CRC64, new Hasher(Hash.CRC64) },
|
||||
{ Hash.MD5, new Hasher(Hash.MD5) },
|
||||
{ Hash.SHA1, new Hasher(Hash.SHA1) },
|
||||
{ Hash.SHA256, new Hasher(Hash.SHA256) },
|
||||
{ Hash.SHA384, new Hasher(Hash.SHA384) },
|
||||
{ Hash.SHA512, new Hasher(Hash.SHA512) },
|
||||
{ Hash.XxHash32, new Hasher(Hash.XxHash32) },
|
||||
{ Hash.XxHash64, new Hasher(Hash.XxHash64) },
|
||||
};
|
||||
|
||||
// Initialize the hashing helpers
|
||||
var loadBuffer = new ThreadLoadBuffer(input);
|
||||
int buffersize = 3 * 1024 * 1024;
|
||||
byte[] buffer0 = new byte[buffersize];
|
||||
byte[] buffer1 = new byte[buffersize];
|
||||
|
||||
/*
|
||||
Please note that some of the following code is adapted from
|
||||
RomVault. This is a modified version of how RomVault does
|
||||
threaded hashing. As such, some of the terminology and code
|
||||
is the same, though variable names and comments may have
|
||||
been tweaked to better fit this code base.
|
||||
*/
|
||||
|
||||
// Pre load the first buffer
|
||||
long refsize = input.Length;
|
||||
int next = refsize > buffersize ? buffersize : (int)refsize;
|
||||
input.Read(buffer0, 0, next);
|
||||
int current = next;
|
||||
refsize -= next;
|
||||
bool bufferSelect = true;
|
||||
|
||||
while (current > 0)
|
||||
{
|
||||
// Trigger the buffer load on the second buffer
|
||||
next = refsize > buffersize ? buffersize : (int)refsize;
|
||||
if (next > 0)
|
||||
loadBuffer.Trigger(bufferSelect ? buffer1 : buffer0, next);
|
||||
|
||||
byte[] buffer = bufferSelect ? buffer0 : buffer1;
|
||||
|
||||
// Run hashes in parallel
|
||||
Parallel.ForEach(hashers, h => h.Value.Process(buffer, current));
|
||||
|
||||
// Wait for the load buffer worker, if needed
|
||||
if (next > 0)
|
||||
loadBuffer.Wait();
|
||||
|
||||
// Setup for the next hashing step
|
||||
current = next;
|
||||
refsize -= next;
|
||||
bufferSelect = !bufferSelect;
|
||||
}
|
||||
|
||||
// Finalize all hashing helpers
|
||||
loadBuffer.Finish();
|
||||
Parallel.ForEach(hashers, h => h.Value.Terminate());
|
||||
|
||||
// Get the results
|
||||
hashDict[Hash.CRC32] = hashers[Hash.CRC32].CurrentHashString;
|
||||
hashDict[Hash.CRC64] = hashers[Hash.CRC64].CurrentHashString;
|
||||
hashDict[Hash.MD5] = hashers[Hash.MD5].CurrentHashString;
|
||||
hashDict[Hash.SHA1] = hashers[Hash.SHA1].CurrentHashString;
|
||||
hashDict[Hash.SHA256] = hashers[Hash.SHA256].CurrentHashString;
|
||||
hashDict[Hash.SHA384] = hashers[Hash.SHA384].CurrentHashString;
|
||||
hashDict[Hash.SHA512] = hashers[Hash.SHA512].CurrentHashString;
|
||||
hashDict[Hash.XxHash32] = hashers[Hash.XxHash32].CurrentHashString;
|
||||
hashDict[Hash.XxHash64] = hashers[Hash.XxHash64].CurrentHashString;
|
||||
hashDict[Hash.CRC64] = hashers[Hash.CRC64].CurrentHashString;
|
||||
|
||||
// Dispose of the hashers
|
||||
loadBuffer.Dispose();
|
||||
foreach (var hasher in hashers.Values)
|
||||
{
|
||||
hasher.Dispose();
|
||||
}
|
||||
|
||||
return hashDict;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
input.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Hashing
|
||||
|
||||
/// <summary>
|
||||
/// Process a buffer of some length with the internal hash algorithm
|
||||
/// </summary>
|
||||
public void Process(byte[] buffer, int size)
|
||||
{
|
||||
switch (_hasher)
|
||||
{
|
||||
case HashAlgorithm ha:
|
||||
ha.TransformBlock(buffer, 0, size, null, 0);
|
||||
break;
|
||||
case NonCryptographicHashAlgorithm ncha:
|
||||
var bufferSpan = new ReadOnlySpan<byte>(buffer, 0, size);
|
||||
ncha.Append(bufferSpan);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalize the internal hash algorigthm
|
||||
/// </summary>
|
||||
/// <remarks>NonCryptographicHashAlgorithm implementations do not need finalization</remarks>
|
||||
public void Terminate()
|
||||
{
|
||||
byte[] emptyBuffer = Array.Empty<byte>();
|
||||
switch (_hasher)
|
||||
{
|
||||
case HashAlgorithm ha:
|
||||
ha.TransformFinalBlock(emptyBuffer, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Convert a byte array to a hex string
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte array to convert</param>
|
||||
/// <returns>Hex string representing the byte array</returns>
|
||||
/// <link>http://stackoverflow.com/questions/311165/how-do-you-convert-byte-array-to-hexadecimal-string-and-vice-versa</link>
|
||||
#if NET48
|
||||
private static string ByteArrayToString(byte[] bytes)
|
||||
#else
|
||||
private static string? ByteArrayToString(byte[]? bytes)
|
||||
#endif
|
||||
{
|
||||
// If we get null in, we send null out
|
||||
if (bytes == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
string hex = BitConverter.ToString(bytes);
|
||||
return hex.Replace("-", string.Empty).ToLowerInvariant();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
//namespace Compress.ThreadReaders
|
||||
namespace MPF.Core.Hashing
|
||||
{
|
||||
public class ThreadLoadBuffer : IDisposable
|
||||
{
|
||||
private readonly AutoResetEvent _waitEvent;
|
||||
private readonly AutoResetEvent _outEvent;
|
||||
private readonly Thread _tWorker;
|
||||
|
||||
#if NET48
|
||||
private byte[] _buffer;
|
||||
#else
|
||||
private byte[]? _buffer;
|
||||
#endif
|
||||
private int _size;
|
||||
private readonly Stream _ds;
|
||||
private bool _finished;
|
||||
public bool errorState;
|
||||
|
||||
public int SizeRead;
|
||||
|
||||
public ThreadLoadBuffer(Stream ds)
|
||||
{
|
||||
_waitEvent = new AutoResetEvent(false);
|
||||
_outEvent = new AutoResetEvent(false);
|
||||
_finished = false;
|
||||
_ds = ds;
|
||||
errorState = false;
|
||||
|
||||
_tWorker = new Thread(MainLoop);
|
||||
_tWorker.Start();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_waitEvent.Close();
|
||||
_outEvent.Close();
|
||||
}
|
||||
|
||||
private void MainLoop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
_waitEvent.WaitOne();
|
||||
if (_finished)
|
||||
{
|
||||
break;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (_buffer != null)
|
||||
SizeRead = _ds.Read(_buffer, 0, _size);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorState = true;
|
||||
}
|
||||
_outEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
public void Trigger(byte[] buffer, int size)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_size = size;
|
||||
_waitEvent.Set();
|
||||
}
|
||||
|
||||
public void Wait()
|
||||
{
|
||||
_outEvent.WaitOne();
|
||||
}
|
||||
|
||||
public void Finish()
|
||||
{
|
||||
_finished = true;
|
||||
_waitEvent.Set();
|
||||
_tWorker.Join();
|
||||
}
|
||||
}
|
||||
}
|
||||
2885
MPF.Core/InfoTool.cs
2885
MPF.Core/InfoTool.cs
File diff suppressed because it is too large
Load Diff
@@ -1,35 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net48;net6.0;net7.0</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
<Copyright>Copyright (c)2019-2023</Copyright>
|
||||
<VersionPrefix>2.7.5</VersionPrefix>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)'!='net48'">
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="MPF.Test" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="2.9.0" GeneratePathProperty="true">
|
||||
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="psxt001z" Version="0.21.0-beta1" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.1.5" />
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="1.1.1" />
|
||||
<PackageReference Include="SabreTools.Serialization" Version="1.1.7" />
|
||||
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
|
||||
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
|
||||
<PackageReference Include="System.IO.Hashing" Version="7.0.0" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,491 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,474 +0,0 @@
|
||||
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.Data;
|
||||
|
||||
#pragma warning disable IDE0051 // Remove unused private members
|
||||
|
||||
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/>
|
||||
#if NET48
|
||||
public Parameters(string parameters) : base(parameters) { }
|
||||
#else
|
||||
public Parameters(string? parameters) : base(parameters) { }
|
||||
#endif
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public Parameters(RedumpSystem? system, MediaType? type, string drivePath, string filename, int? driveSpeed, Options options)
|
||||
#else
|
||||
public Parameters(RedumpSystem? system, MediaType? type, string? drivePath, string filename, int? driveSpeed, Options options)
|
||||
#endif
|
||||
: 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/>
|
||||
#if NET48
|
||||
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive drive, bool includeArtifacts)
|
||||
#else
|
||||
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive? drive, bool includeArtifacts)
|
||||
#endif
|
||||
{
|
||||
// Ensure that required sections exist
|
||||
info = SubmissionInfoTool.EnsureAllSections(info);
|
||||
|
||||
// TODO: Determine if there's a CleanRip version anywhere
|
||||
#if NET48
|
||||
info.DumpingInfo.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
|
||||
#else
|
||||
info.DumpingInfo!.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
|
||||
#endif
|
||||
info.DumpingInfo.DumpingDate = InfoTool.GetFileModifiedDate(basePath + "-dumpinfo.txt")?.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
var datafile = GenerateCleanripDatafile(basePath + ".iso", basePath + "-dumpinfo.txt");
|
||||
|
||||
// Get the individual hash data, as per internal
|
||||
if (InfoTool.GetISOHashValues(datafile, out long size, out var crc32, out var md5, out var sha1))
|
||||
{
|
||||
#if NET48
|
||||
info.SizeAndChecksums.Size = size;
|
||||
#else
|
||||
info.SizeAndChecksums!.Size = size;
|
||||
#endif
|
||||
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"))
|
||||
#if NET48
|
||||
info.Extras.BCA = GetBCA(basePath + ".bca");
|
||||
#else
|
||||
info.Extras!.BCA = GetBCA(basePath + ".bca");
|
||||
#endif
|
||||
|
||||
if (GetGameCubeWiiInformation(basePath + "-dumpinfo.txt", out Region? gcRegion, out var gcVersion, out var gcName))
|
||||
{
|
||||
#if NET48
|
||||
info.CommonDiscInfo.Region = gcRegion ?? info.CommonDiscInfo.Region;
|
||||
info.VersionAndEditions.Version = gcVersion ?? info.VersionAndEditions.Version;
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalName] = gcName ?? string.Empty;
|
||||
#else
|
||||
info.CommonDiscInfo!.Region = gcRegion ?? info.CommonDiscInfo.Region;
|
||||
info.VersionAndEditions!.Version = gcVersion ?? info.VersionAndEditions.Version;
|
||||
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalName] = gcName ?? string.Empty;
|
||||
#endif
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill in any artifacts that exist, Base64-encoded, if we need to
|
||||
if (includeArtifacts)
|
||||
{
|
||||
#if NET48
|
||||
if (info.Artifacts == null) info.Artifacts = new Dictionary<string, string>();
|
||||
#else
|
||||
info.Artifacts ??= new Dictionary<string, string>();
|
||||
#endif
|
||||
|
||||
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>
|
||||
#if NET48
|
||||
private static Datafile GenerateCleanripDatafile(string iso, string dumpinfo)
|
||||
#else
|
||||
private static Datafile? GenerateCleanripDatafile(string iso, string dumpinfo)
|
||||
#endif
|
||||
{
|
||||
// If the file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(dumpinfo))
|
||||
return null;
|
||||
|
||||
using (var sr = File.OpenText(dumpinfo))
|
||||
{
|
||||
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
|
||||
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.IsNullOrWhiteSpace(line))
|
||||
continue;
|
||||
#if NET48
|
||||
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);
|
||||
#else
|
||||
else if (line.StartsWith("CRC32"))
|
||||
crc = line[7..].ToLowerInvariant();
|
||||
else if (line.StartsWith("MD5"))
|
||||
md5 = line[5..];
|
||||
else if (line.StartsWith("SHA-1"))
|
||||
sha1 = line[7..];
|
||||
#endif
|
||||
}
|
||||
|
||||
return new Datafile
|
||||
{
|
||||
Games = new Game[]
|
||||
{
|
||||
new Game
|
||||
{
|
||||
Roms = new Rom[]
|
||||
{
|
||||
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>
|
||||
#if NET48
|
||||
private static string GetBCA(string bcaPath)
|
||||
#else
|
||||
private static string? GetBCA(string bcaPath)
|
||||
#endif
|
||||
{
|
||||
// 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>
|
||||
#if NET48
|
||||
private static string GetCleanripDatfile(string iso, string dumpinfo)
|
||||
#else
|
||||
private static string? GetCleanripDatfile(string iso, string dumpinfo)
|
||||
#endif
|
||||
{
|
||||
// If the file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(dumpinfo))
|
||||
return null;
|
||||
|
||||
using (var sr = File.OpenText(dumpinfo))
|
||||
{
|
||||
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
|
||||
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.IsNullOrWhiteSpace(line))
|
||||
continue;
|
||||
#if NET48
|
||||
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);
|
||||
#else
|
||||
else if (line.StartsWith("CRC32"))
|
||||
crc = line[7..].ToLowerInvariant();
|
||||
else if (line.StartsWith("MD5"))
|
||||
md5 = line[5..];
|
||||
else if (line.StartsWith("SHA-1"))
|
||||
sha1 = line[7..];
|
||||
#endif
|
||||
}
|
||||
|
||||
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>
|
||||
/// <returns></returns>
|
||||
#if NET48
|
||||
private static bool GetGameCubeWiiInformation(string dumpinfo, out Region? region, out string version, out string name)
|
||||
#else
|
||||
private static bool GetGameCubeWiiInformation(string dumpinfo, out Region? region, out string? version, out string? name)
|
||||
#endif
|
||||
{
|
||||
region = null; version = null; name = null;
|
||||
|
||||
// If the file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(dumpinfo))
|
||||
return false;
|
||||
|
||||
using (var sr = File.OpenText(dumpinfo))
|
||||
{
|
||||
try
|
||||
{
|
||||
// Make sure this file is a 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.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (line.StartsWith("Version"))
|
||||
{
|
||||
#if NET48
|
||||
version = line.Substring("Version: ".Length);
|
||||
#else
|
||||
version = line["Version: ".Length..];
|
||||
#endif
|
||||
}
|
||||
else if (line.StartsWith("Internal Name"))
|
||||
{
|
||||
#if NET48
|
||||
name = line.Substring("Internal Name: ".Length);
|
||||
#else
|
||||
name = line["Internal Name: ".Length..];
|
||||
#endif
|
||||
}
|
||||
else if (line.StartsWith("Filename"))
|
||||
{
|
||||
#if NET48
|
||||
string serial = line.Substring("Filename: ".Length);
|
||||
#else
|
||||
string serial = line["Filename: ".Length..];
|
||||
#endif
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace MPF.Core.Modules
|
||||
{
|
||||
[XmlRoot("datafile")]
|
||||
public class Datafile
|
||||
{
|
||||
[XmlElement("header")]
|
||||
#if NET48
|
||||
public Header Header;
|
||||
#else
|
||||
public Header? Header;
|
||||
#endif
|
||||
|
||||
[XmlElement("game")]
|
||||
#if NET48
|
||||
public Game[] Games;
|
||||
#else
|
||||
public Game[]? Games;
|
||||
#endif
|
||||
}
|
||||
|
||||
public class Header
|
||||
{
|
||||
[XmlElement("name")]
|
||||
#if NET48
|
||||
public string Name;
|
||||
#else
|
||||
public string? Name;
|
||||
#endif
|
||||
|
||||
[XmlElement("description")]
|
||||
#if NET48
|
||||
public string Description;
|
||||
#else
|
||||
public string? Description;
|
||||
#endif
|
||||
|
||||
[XmlElement("version")]
|
||||
#if NET48
|
||||
public string Version;
|
||||
#else
|
||||
public string? Version;
|
||||
#endif
|
||||
|
||||
[XmlElement("date")]
|
||||
#if NET48
|
||||
public string Date;
|
||||
#else
|
||||
public string? Date;
|
||||
#endif
|
||||
|
||||
[XmlElement("author")]
|
||||
#if NET48
|
||||
public string Author;
|
||||
#else
|
||||
public string? Author;
|
||||
#endif
|
||||
|
||||
[XmlElement("homepage")]
|
||||
#if NET48
|
||||
public string Homepage;
|
||||
#else
|
||||
public string? Homepage;
|
||||
#endif
|
||||
|
||||
[XmlElement("url")]
|
||||
#if NET48
|
||||
public string Url;
|
||||
#else
|
||||
public string? Url;
|
||||
#endif
|
||||
}
|
||||
|
||||
public class Game
|
||||
{
|
||||
[XmlAttribute("name")]
|
||||
#if NET48
|
||||
public string Name;
|
||||
#else
|
||||
public string? Name;
|
||||
#endif
|
||||
|
||||
[XmlElement("category")]
|
||||
#if NET48
|
||||
public string Category;
|
||||
#else
|
||||
public string? Category;
|
||||
#endif
|
||||
|
||||
[XmlElement("description")]
|
||||
#if NET48
|
||||
public string Description;
|
||||
#else
|
||||
public string? Description;
|
||||
#endif
|
||||
|
||||
[XmlElement("rom")]
|
||||
#if NET48
|
||||
public Rom[] Roms;
|
||||
#else
|
||||
public Rom[]? Roms;
|
||||
#endif
|
||||
}
|
||||
|
||||
public class Rom
|
||||
{
|
||||
[XmlAttribute("name")]
|
||||
#if NET48
|
||||
public string Name;
|
||||
#else
|
||||
public string? Name;
|
||||
#endif
|
||||
|
||||
[XmlAttribute("size")]
|
||||
#if NET48
|
||||
public string Size;
|
||||
#else
|
||||
public string? Size;
|
||||
#endif
|
||||
|
||||
[XmlAttribute("crc")]
|
||||
#if NET48
|
||||
public string Crc;
|
||||
#else
|
||||
public string? Crc;
|
||||
#endif
|
||||
|
||||
[XmlAttribute("md5")]
|
||||
#if NET48
|
||||
public string Md5;
|
||||
#else
|
||||
public string? Md5;
|
||||
#endif
|
||||
|
||||
[XmlAttribute("sha1")]
|
||||
#if NET48
|
||||
public string Sha1;
|
||||
#else
|
||||
public string? Sha1;
|
||||
#endif
|
||||
|
||||
// TODO: Add extended hashes here
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
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)
|
||||
{
|
||||
switch (baseCommand)
|
||||
{
|
||||
case CommandStrings.Audio:
|
||||
return RedumpSystem.AudioCD;
|
||||
case CommandStrings.CompactDisc:
|
||||
case CommandStrings.Data:
|
||||
case CommandStrings.DigitalVideoDisc:
|
||||
case CommandStrings.Disk:
|
||||
case CommandStrings.Floppy:
|
||||
case CommandStrings.Tape:
|
||||
return RedumpSystem.IBMPCcompatible;
|
||||
case CommandStrings.GDROM:
|
||||
case CommandStrings.Swap:
|
||||
return RedumpSystem.SegaDreamcast;
|
||||
case CommandStrings.BluRay:
|
||||
return RedumpSystem.SonyPlayStation3;
|
||||
case CommandStrings.SACD:
|
||||
return RedumpSystem.SuperAudioCD;
|
||||
case CommandStrings.XBOX:
|
||||
case CommandStrings.XBOXSwap:
|
||||
return RedumpSystem.MicrosoftXbox;
|
||||
case CommandStrings.XGD2Swap:
|
||||
case CommandStrings.XGD3Swap:
|
||||
return RedumpSystem.MicrosoftXbox360;
|
||||
default:
|
||||
return 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>
|
||||
#if NET48
|
||||
public static MediaType? ToMediaType(string baseCommand)
|
||||
#else
|
||||
public static MediaType? ToMediaType(string? baseCommand)
|
||||
#endif
|
||||
{
|
||||
switch (baseCommand)
|
||||
{
|
||||
case CommandStrings.Audio:
|
||||
case CommandStrings.CompactDisc:
|
||||
case CommandStrings.Data:
|
||||
case CommandStrings.SACD:
|
||||
return MediaType.CDROM;
|
||||
case CommandStrings.GDROM:
|
||||
case CommandStrings.Swap:
|
||||
return MediaType.GDROM;
|
||||
case CommandStrings.DigitalVideoDisc:
|
||||
case CommandStrings.XBOX:
|
||||
case CommandStrings.XBOXSwap:
|
||||
case CommandStrings.XGD2Swap:
|
||||
case CommandStrings.XGD3Swap:
|
||||
return MediaType.DVD;
|
||||
case CommandStrings.BluRay:
|
||||
return MediaType.BluRay;
|
||||
|
||||
// Non-optical
|
||||
case CommandStrings.Floppy:
|
||||
return MediaType.FloppyDisk;
|
||||
case CommandStrings.Disk:
|
||||
return MediaType.HardDisk;
|
||||
case CommandStrings.Tape:
|
||||
return MediaType.DataCartridge;
|
||||
default:
|
||||
return 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>
|
||||
#if NET48
|
||||
public static string Extension(MediaType? type)
|
||||
#else
|
||||
public static string? Extension(MediaType? type)
|
||||
#endif
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
case MediaType.GDROM:
|
||||
case MediaType.Cartridge:
|
||||
case MediaType.HardDisk:
|
||||
case MediaType.CompactFlash:
|
||||
case MediaType.MMC:
|
||||
case MediaType.SDCard:
|
||||
case MediaType.FlashDrive:
|
||||
return ".bin";
|
||||
case MediaType.DVD:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.BluRay:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return ".iso";
|
||||
case MediaType.LaserDisc:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
return ".raw";
|
||||
case MediaType.NintendoWiiUOpticalDisc:
|
||||
return ".wud";
|
||||
case MediaType.FloppyDisk:
|
||||
return ".img";
|
||||
case MediaType.Cassette:
|
||||
return ".wav";
|
||||
case MediaType.NONE:
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,36 +0,0 @@
|
||||
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>
|
||||
#if NET48
|
||||
public static string Extension(MediaType? type)
|
||||
#else
|
||||
public static string? Extension(MediaType? type)
|
||||
#endif
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
return ".bin";
|
||||
case MediaType.DVD:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.BluRay:
|
||||
return ".iso";
|
||||
case MediaType.NONE:
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,284 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.Hashing;
|
||||
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/>
|
||||
#if NET48
|
||||
public Parameters(string parameters) : base(parameters) { }
|
||||
#else
|
||||
public Parameters(string? parameters) : base(parameters) { }
|
||||
#endif
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public Parameters(RedumpSystem? system, MediaType? type, string drivePath, string filename, int? driveSpeed, Options options)
|
||||
#else
|
||||
public Parameters(RedumpSystem? system, MediaType? type, string? drivePath, string filename, int? driveSpeed, Options options)
|
||||
#endif
|
||||
: 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/>
|
||||
#if NET48
|
||||
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive drive, bool includeArtifacts)
|
||||
#else
|
||||
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive? drive, bool includeArtifacts)
|
||||
#endif
|
||||
{
|
||||
// Ensure that required sections exist
|
||||
info = SubmissionInfoTool.EnsureAllSections(info);
|
||||
|
||||
// TODO: Determine if there's a UMDImageCreator version anywhere
|
||||
#if NET48
|
||||
info.DumpingInfo.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
|
||||
#else
|
||||
info.DumpingInfo!.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
|
||||
#endif
|
||||
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:
|
||||
#if NET48
|
||||
info.Extras.PVD = GetPVD(basePath + "_mainInfo.txt") ?? string.Empty;
|
||||
#else
|
||||
info.Extras!.PVD = GetPVD(basePath + "_mainInfo.txt") ?? string.Empty;
|
||||
#endif
|
||||
|
||||
if (Hasher.GetFileHashes(basePath + ".iso", out long filesize, out var crc32, out var md5, out var sha1))
|
||||
{
|
||||
#if NET48
|
||||
info.SizeAndChecksums.Size = filesize;
|
||||
#else
|
||||
info.SizeAndChecksums!.Size = filesize;
|
||||
#endif
|
||||
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))
|
||||
{
|
||||
#if NET48
|
||||
info.CommonDiscInfo.Title = title ?? string.Empty;
|
||||
info.CommonDiscInfo.Category = umdcat ?? DiscCategory.Games;
|
||||
info.VersionAndEditions.Version = umdversion ?? string.Empty;
|
||||
info.SizeAndChecksums.Size = umdsize;
|
||||
#else
|
||||
info.CommonDiscInfo!.Title = title ?? string.Empty;
|
||||
info.CommonDiscInfo.Category = umdcat ?? DiscCategory.Games;
|
||||
info.VersionAndEditions!.Version = umdversion ?? string.Empty;
|
||||
info.SizeAndChecksums!.Size = umdsize;
|
||||
#endif
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(umdlayer))
|
||||
info.SizeAndChecksums.Layerbreak = Int64.Parse(umdlayer ?? "-1");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill in any artifacts that exist, Base64-encoded, if we need to
|
||||
if (includeArtifacts)
|
||||
{
|
||||
#if NET48
|
||||
if (info.Artifacts == null) info.Artifacts = new Dictionary<string, string>();
|
||||
#else
|
||||
info.Artifacts ??= new Dictionary<string, string>();
|
||||
#endif
|
||||
|
||||
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>
|
||||
#if NET48
|
||||
private static string GetPVD(string mainInfo)
|
||||
#else
|
||||
private static string? GetPVD(string mainInfo)
|
||||
#endif
|
||||
{
|
||||
// If the file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(mainInfo))
|
||||
return null;
|
||||
|
||||
using (var sr = File.OpenText(mainInfo))
|
||||
{
|
||||
try
|
||||
{
|
||||
// Make sure we're in the right sector
|
||||
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>
|
||||
#if NET48
|
||||
private static bool GetUMDAuxInfo(string disc, out string title, out DiscCategory? umdcat, out string umdversion, out string umdlayer, out long umdsize)
|
||||
#else
|
||||
private static bool GetUMDAuxInfo(string disc, out string? title, out DiscCategory? umdcat, out string? umdversion, out string? umdlayer, out long umdsize)
|
||||
#endif
|
||||
{
|
||||
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;
|
||||
|
||||
using (var sr = File.OpenText(disc))
|
||||
{
|
||||
try
|
||||
{
|
||||
// Loop through everything to get the first instance of each required field
|
||||
var line = string.Empty;
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
line = sr.ReadLine()?.Trim();
|
||||
if (line == null)
|
||||
break;
|
||||
|
||||
if (line.StartsWith("TITLE") && title == null)
|
||||
#if NET48
|
||||
title = line.Substring("TITLE: ".Length);
|
||||
#else
|
||||
title = line["TITLE: ".Length..];
|
||||
#endif
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -1,343 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using BinaryObjectScanner;
|
||||
using BinaryObjectScanner.Protection;
|
||||
using psxt001z;
|
||||
|
||||
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>
|
||||
#if NET48
|
||||
public static async Task<(Dictionary<string, List<string>>, string)> RunProtectionScanOnPath(string path, Data.Options options, IProgress<ProtectionProgress> progress = null)
|
||||
#else
|
||||
public static async Task<(Dictionary<string, List<string>>?, string?)> RunProtectionScanOnPath(string path, Data.Options options, IProgress<ProtectionProgress>? progress = null)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
var found = await Task.Run(() =>
|
||||
{
|
||||
var scanner = new 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);
|
||||
});
|
||||
|
||||
// If nothing was returned, return
|
||||
if (found == null || !found.Any())
|
||||
return (null, null);
|
||||
|
||||
// Filter out any empty protections
|
||||
var filteredProtections = found
|
||||
.Where(kvp => kvp.Value != null && kvp.Value.Any())
|
||||
.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>
|
||||
#if NET48
|
||||
public static string FormatProtections(Dictionary<string, List<string>> protections)
|
||||
#else
|
||||
public static string? FormatProtections(Dictionary<string, List<string>>? protections)
|
||||
#endif
|
||||
{
|
||||
// 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.IsNullOrWhiteSpace(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>
|
||||
#if NET48
|
||||
public static async Task<bool> GetPlayStationAntiModchipDetected(string path)
|
||||
#else
|
||||
public static async Task<bool> GetPlayStationAntiModchipDetected(string? path)
|
||||
#endif
|
||||
{
|
||||
// If there is no valid path
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return false;
|
||||
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var antiModchip = new 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.IsNullOrWhiteSpace(protection))
|
||||
return true;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/// <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.CheckSubfile(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"));
|
||||
foundProtections = foundProtections
|
||||
.Prepend("Exception occurred while scanning [RESCAN NEEDED]")
|
||||
.OrderBy(p => p);
|
||||
}
|
||||
|
||||
// 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")))
|
||||
foundProtections = foundProtections.Append("Cactus Data Shield 300");
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,64 +0,0 @@
|
||||
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/>
|
||||
#if NET48
|
||||
public bool Equals(Element<T> other)
|
||||
#else
|
||||
public bool Equals(Element<T>? other)
|
||||
#endif
|
||||
{
|
||||
if (other == null)
|
||||
return false;
|
||||
|
||||
return Name == other.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.UI.ComboBoxItems;
|
||||
using SabreTools.RedumpLib.Web;
|
||||
|
||||
namespace MPF.Core.UI.ViewModels
|
||||
{
|
||||
public class OptionsViewModel : INotifyPropertyChanged
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Title for the window
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string Title
|
||||
#else
|
||||
public string? Title
|
||||
#endif
|
||||
{
|
||||
get => _title;
|
||||
set
|
||||
{
|
||||
_title = value;
|
||||
TriggerPropertyChanged(nameof(Title));
|
||||
}
|
||||
}
|
||||
#if NET48
|
||||
private string _title;
|
||||
#else
|
||||
private string? _title;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Current set of options
|
||||
/// </summary>
|
||||
public Options Options { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Flag for if settings were saved or not
|
||||
/// </summary>
|
||||
public bool SavedSettings { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
#else
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region Lists
|
||||
|
||||
/// <summary>
|
||||
/// List of available internal programs
|
||||
/// </summary>
|
||||
public List<Element<InternalProgram>> InternalPrograms => PopulateInternalPrograms();
|
||||
|
||||
/// <summary>
|
||||
/// Current list of supported system profiles
|
||||
/// </summary>
|
||||
public List<RedumpSystemComboBoxItem> Systems => RedumpSystemComboBoxItem.GenerateElements().ToList();
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public OptionsViewModel(Options baseOptions)
|
||||
{
|
||||
Options = new Options(baseOptions);
|
||||
}
|
||||
|
||||
#region Population
|
||||
|
||||
/// <summary>
|
||||
/// Get a complete list of supported internal programs
|
||||
/// </summary>
|
||||
private static List<Element<InternalProgram>> PopulateInternalPrograms()
|
||||
{
|
||||
var internalPrograms = new List<InternalProgram> { InternalProgram.DiscImageCreator, InternalProgram.Aaru, InternalProgram.Redumper };
|
||||
return internalPrograms.Select(ip => new Element<InternalProgram>(ip)).ToList();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI Commands
|
||||
|
||||
/// <summary>
|
||||
/// Test Redump login credentials
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public (bool?, string) TestRedumpLogin(string username, string password)
|
||||
#else
|
||||
public async Task<(bool?, string?)> TestRedumpLogin(string username, string password)
|
||||
#endif
|
||||
{
|
||||
#if NET48
|
||||
return RedumpWebClient.ValidateCredentials(username, password);
|
||||
#else
|
||||
return await RedumpHttpClient.ValidateCredentials(username, password);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Property Updates
|
||||
|
||||
/// <summary>
|
||||
/// Trigger a property changed event
|
||||
/// </summary>
|
||||
private void TriggerPropertyChanged(string propertyName)
|
||||
{
|
||||
// If the property change event is initialized
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace MPF.Core.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Big endian reading overloads for BinaryReader
|
||||
/// </summary>
|
||||
public static class BinaryReaderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads the specified number of bytes from the stream, starting from a specified point in the byte array.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to read data into.</param>
|
||||
/// <param name="index">The starting point in the buffer at which to begin reading into the buffer.</param>
|
||||
/// <param name="count">The number of bytes to read.</param>
|
||||
/// <returns>The number of bytes read into buffer. This might be less than the number of bytes requested if that many bytes are not available, or it might be zero if the end of the stream is reached.</returns>
|
||||
public static int ReadBigEndian(this BinaryReader reader, byte[] buffer, int index, int count)
|
||||
{
|
||||
int retval = reader.Read(buffer, index, count);
|
||||
Array.Reverse(buffer);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of characters from the stream, starting from a specified point in the character array.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to read data into.</param>
|
||||
/// <param name="index">The starting point in the buffer at which to begin reading into the buffer.</param>
|
||||
/// <param name="count">The number of characters to read.</param>
|
||||
/// <returns>The total number of characters read into the buffer. This might be less than the number of characters requested if that many characters are not currently available, or it might be zero if the end of the stream is reached.</returns>
|
||||
public static int ReadBigEndian(this BinaryReader reader, char[] buffer, int index, int count)
|
||||
{
|
||||
int retval = reader.Read(buffer, index, count);
|
||||
Array.Reverse(buffer);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of bytes from the current stream into a byte array and advances the current position by that number of bytes.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of bytes to read. This value must be 0 or a non-negative number or an exception will occur.</param>
|
||||
/// <returns>A byte array containing data read from the underlying stream. This might be less than the number of bytes requested if the end of the stream is reached.</returns>
|
||||
public static byte[] ReadBytesBigEndian(this BinaryReader reader, int count)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(count);
|
||||
Array.Reverse(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of characters from the current stream, returns the data in a character array, and advances the current position in accordance with the Encoding used and the specific character being read from the stream.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of characters to read. This value must be 0 or a non-negative number or an exception will occur.</param>
|
||||
/// <returns>A character array containing data read from the underlying stream. This might be less than the number of bytes requested if the end of the stream is reached.</returns>
|
||||
public static char[] ReadCharsBigEndian(this BinaryReader reader, int count)
|
||||
{
|
||||
char[] retval = reader.ReadChars(count);
|
||||
Array.Reverse(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a decimal value from the current stream and advances the current position of the stream by sixteen bytes.
|
||||
/// </summary>
|
||||
/// <returns>A decimal value read from the current stream.</returns>
|
||||
public static decimal ReadDecimalBigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(16);
|
||||
Array.Reverse(retval);
|
||||
|
||||
int i1 = BitConverter.ToInt32(retval, 0);
|
||||
int i2 = BitConverter.ToInt32(retval, 4);
|
||||
int i3 = BitConverter.ToInt32(retval, 8);
|
||||
int i4 = BitConverter.ToInt32(retval, 12);
|
||||
|
||||
return new decimal(new int[] { i1, i2, i3, i4 });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// eads an 8-byte floating point value from the current stream and advances the current position of the stream by eight bytes.
|
||||
/// </summary>
|
||||
/// <returns>An 8-byte floating point value read from the current stream.</returns>
|
||||
public static double ReadDoubleBigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(8);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToDouble(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 2-byte signed integer from the current stream and advances the current position of the stream by two bytes.
|
||||
/// </summary>
|
||||
/// <returns>A 2-byte signed integer read from the current stream.</returns>
|
||||
public static short ReadInt16BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(2);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToInt16(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 4-byte signed integer from the current stream and advances the current position of the stream by four bytes.
|
||||
/// </summary>
|
||||
/// <returns>A 4-byte signed integer read from the current stream.</returns>
|
||||
public static int ReadInt32BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(4);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToInt32(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an 8-byte signed integer from the current stream and advances the current position of the stream by eight bytes.
|
||||
/// </summary>
|
||||
/// <returns>An 8-byte signed integer read from the current stream.</returns>
|
||||
public static long ReadInt64BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(8);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToInt64(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 4-byte floating point value from the current stream and advances the current position of the stream by four bytes.
|
||||
/// </summary>
|
||||
/// <returns>A 4-byte floating point value read from the current stream.</returns>
|
||||
public static float ReadSingleBigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(4);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToSingle(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 2-byte unsigned integer from the current stream using little-endian encoding and advances the position of the stream by two bytes.
|
||||
///
|
||||
/// This API is not CLS-compliant.
|
||||
/// </summary>
|
||||
/// <returns>A 2-byte unsigned integer read from this stream.</returns>
|
||||
public static ushort ReadUInt16BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(2);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToUInt16(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 4-byte unsigned integer from the current stream and advances the position of the stream by four bytes.
|
||||
///
|
||||
/// This API is not CLS-compliant.
|
||||
/// </summary>
|
||||
/// <returns>A 4-byte unsigned integer read from this stream.</returns>
|
||||
public static uint ReadUInt32BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(4);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToUInt32(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an 8-byte unsigned integer from the current stream and advances the position of the stream by eight bytes.
|
||||
///
|
||||
/// This API is not CLS-compliant.
|
||||
/// </summary>
|
||||
/// <returns>An 8-byte unsigned integer read from this stream.</returns>
|
||||
public static ulong ReadUInt64BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(8);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToUInt64(retval, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,400 +0,0 @@
|
||||
#if FALSE
|
||||
|
||||
using System;
|
||||
|
||||
namespace MPF.Core.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Methods to deal with outputting tones to the PC speaker
|
||||
/// </summary>
|
||||
public class Chime
|
||||
{
|
||||
/// <summary>
|
||||
/// Standard duration to play a single tone
|
||||
/// </summary>
|
||||
private const int standardDurationMs = 200;
|
||||
|
||||
#region Octave 0
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing C(0)
|
||||
/// </summary>
|
||||
private const int noteC0 = 16; // 16.35
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing D(0)
|
||||
/// </summary>
|
||||
private const int noteD0 = 18; // 18.35
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing E(0)
|
||||
/// </summary>
|
||||
private const int noteE0 = 21; // 20.60
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing F(0)
|
||||
/// </summary>
|
||||
private const int noteF0 = 22; // 21.83
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing G(0)
|
||||
/// </summary>
|
||||
private const int noteG0 = 25; // 24.50
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing A(0)
|
||||
/// </summary>
|
||||
private const int noteA0 = 28; // 27.50
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing B(0)
|
||||
/// </summary>
|
||||
private const int noteB0 = 31; // 30.87
|
||||
|
||||
#endregion
|
||||
|
||||
#region Octave 1
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing C(1)
|
||||
/// </summary>
|
||||
private const int noteC1 = 33; // 32.70
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing D(1)
|
||||
/// </summary>
|
||||
private const int noteD1 = 37; // 36.71
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing E(1)
|
||||
/// </summary>
|
||||
private const int noteE1 = 41; // 41.20
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing F(1)
|
||||
/// </summary>
|
||||
private const int noteF1 = 44; // 43.65
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing G(1)
|
||||
/// </summary>
|
||||
private const int noteG1 = 49; // 49.00
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing A(1)
|
||||
/// </summary>
|
||||
private const int noteA1 = 55; // 55.00
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing B(1)
|
||||
/// </summary>
|
||||
private const int noteB1 = 62; // 61.74
|
||||
|
||||
#endregion
|
||||
|
||||
#region Octave 2
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing C(2)
|
||||
/// </summary>
|
||||
private const int noteC2 = 65; // 65.41
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing D(2)
|
||||
/// </summary>
|
||||
private const int noteD2 = 73; // 73.42
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing E(2)
|
||||
/// </summary>
|
||||
private const int noteE2 = 82; // 82.41
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing F(2)
|
||||
/// </summary>
|
||||
private const int noteF2 = 87; // 87.31
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing G(2)
|
||||
/// </summary>
|
||||
private const int noteG2 = 98; // 98.00
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing A(2)
|
||||
/// </summary>
|
||||
private const int noteA2 = 110; // 110.00
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing B(2)
|
||||
/// </summary>
|
||||
private const int noteB2 = 123; // 123.47
|
||||
|
||||
#endregion
|
||||
|
||||
#region Octave 3
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing C(3)
|
||||
/// </summary>
|
||||
private const int noteC3 = 131; // 130.81
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing D(3)
|
||||
/// </summary>
|
||||
private const int noteD3 = 147; // 146.83
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing E(3)
|
||||
/// </summary>
|
||||
private const int noteE3 = 165; // 164.81
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing F(3)
|
||||
/// </summary>
|
||||
private const int noteF3 = 175; // 174.61
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing G(3)
|
||||
/// </summary>
|
||||
private const int noteG3 = 196; // 196.00
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing A(3)
|
||||
/// </summary>
|
||||
private const int noteA3 = 220; // 220.00
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing B(3)
|
||||
/// </summary>
|
||||
private const int noteB3 = 247; // 246.94
|
||||
|
||||
#endregion
|
||||
|
||||
#region Octave 4
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing C(4)
|
||||
/// </summary>
|
||||
private const int noteC4 = 262; // 261.63
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing D(4)
|
||||
/// </summary>
|
||||
private const int noteD4 = 294; // 293.66
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing E(4)
|
||||
/// </summary>
|
||||
private const int noteE4 = 330; // 329.63
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing F(4)
|
||||
/// </summary>
|
||||
private const int noteF4 = 349; // 349.23
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing G(4)
|
||||
/// </summary>
|
||||
private const int noteG4 = 392; // 392.00
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing A(4)
|
||||
/// </summary>
|
||||
private const int noteA4 = 440; // 440.00
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing B(4)
|
||||
/// </summary>
|
||||
private const int noteB4 = 494; // 493.88
|
||||
|
||||
#endregion
|
||||
|
||||
#region Octave 5
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing C(5)
|
||||
/// </summary>
|
||||
private const int noteC5 = 523; // 523.25
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing D(5)
|
||||
/// </summary>
|
||||
private const int noteD5 = 587; // 587.33
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing E(5)
|
||||
/// </summary>
|
||||
private const int noteE5 = 659; // 659.25
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing F(5)
|
||||
/// </summary>
|
||||
private const int noteF5 = 698; // 698.46
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing G(5)
|
||||
/// </summary>
|
||||
private const int noteG5 = 783; // 783.99
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing A(5)
|
||||
/// </summary>
|
||||
private const int noteA5 = 880; // 880.00
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing B(5)
|
||||
/// </summary>
|
||||
private const int noteB5 = 988; // 987.77
|
||||
|
||||
#endregion
|
||||
|
||||
#region Octave 6
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing C(6)
|
||||
/// </summary>
|
||||
private const int noteC6 = 1047; // 1046.50
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing D(6)
|
||||
/// </summary>
|
||||
private const int noteD6 = 1175; // 1174.66
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing E(6)
|
||||
/// </summary>
|
||||
private const int noteE6 = 1319; // 1318.51
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing F(6)
|
||||
/// </summary>
|
||||
private const int noteF6 = 1397; // 1396.91
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing G(6)
|
||||
/// </summary>
|
||||
private const int noteG6 = 1568; // 1567.98
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing A(6)
|
||||
/// </summary>
|
||||
private const int noteA6 = 1760; // 1760.00
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing B(6)
|
||||
/// </summary>
|
||||
private const int noteB6 = 1976; // 1975.53
|
||||
|
||||
#endregion
|
||||
|
||||
#region Octave 7
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing C(7)
|
||||
/// </summary>
|
||||
private const int noteC7 = 2093; // 2093.00
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing D(7)
|
||||
/// </summary>
|
||||
private const int noteD7 = 2349; // 2349.32
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing E(7)
|
||||
/// </summary>
|
||||
private const int noteE7 = 2637; // 2637.02
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing F(7)
|
||||
/// </summary>
|
||||
private const int noteF7 = 2794; // 2793.83
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing G(7)
|
||||
/// </summary>
|
||||
private const int noteG7 = 3136; // 3135.96
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing A(7)
|
||||
/// </summary>
|
||||
private const int noteA7 = 3520; // 3520.00
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing B(7)
|
||||
/// </summary>
|
||||
private const int noteB7 = 3951; // 3951.07
|
||||
|
||||
#endregion
|
||||
|
||||
#region Octave 8
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing C(8)
|
||||
/// </summary>
|
||||
private const int noteC8 = 4186; // 4186.01
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing D(8)
|
||||
/// </summary>
|
||||
private const int noteD8 = 4699; // 4698.63
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing E(8)
|
||||
/// </summary>
|
||||
private const int noteE8 = 5274; // 5274.04
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing F(8)
|
||||
/// </summary>
|
||||
private const int noteF8 = 5588; // 5587.65
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing G(8)
|
||||
/// </summary>
|
||||
private const int noteG8 = 6272; // 6271.93
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing A(8)
|
||||
/// </summary>
|
||||
private const int noteA8 = 7040; // 7040.00
|
||||
|
||||
/// <summary>
|
||||
/// Frequency representing B(8)
|
||||
/// </summary>
|
||||
private const int noteB8 = 7902; // 7902.13
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Output a series of beeps for completion, similar to DiscImageCreator
|
||||
/// </summary>
|
||||
/// <param name="success">True if the upward series should play, false otherwise</param>
|
||||
public static void StandardCompletion(bool success)
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
Console.Beep(noteC4, standardDurationMs);
|
||||
Console.Beep(noteD4, standardDurationMs);
|
||||
Console.Beep(noteE4, standardDurationMs);
|
||||
Console.Beep(noteF4, standardDurationMs);
|
||||
Console.Beep(noteG4, standardDurationMs);
|
||||
Console.Beep(noteA4, standardDurationMs);
|
||||
Console.Beep(noteB4, standardDurationMs);
|
||||
Console.Beep(noteC5, standardDurationMs);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Beep(noteC5, standardDurationMs);
|
||||
Console.Beep(noteB4, standardDurationMs);
|
||||
Console.Beep(noteA4, standardDurationMs);
|
||||
Console.Beep(noteG4, standardDurationMs);
|
||||
Console.Beep(noteF4, standardDurationMs);
|
||||
Console.Beep(noteE4, standardDurationMs);
|
||||
Console.Beep(noteD4, standardDurationMs);
|
||||
Console.Beep(noteC4, standardDurationMs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,149 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Data;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Utilities
|
||||
{
|
||||
public static class EnumExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Determine if a system is okay if it's not detected by Windows
|
||||
/// </summary>
|
||||
/// <param name="system">RedumpSystem value to check</param>
|
||||
/// <returns>True if Windows show see a disc when dumping, false otherwise</returns>
|
||||
public static bool DetectedByWindows(this RedumpSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case RedumpSystem.AmericanLaserGames3DO:
|
||||
case RedumpSystem.AppleMacintosh:
|
||||
case RedumpSystem.Atari3DO:
|
||||
case RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem:
|
||||
case RedumpSystem.NewJatreCDi:
|
||||
case RedumpSystem.NintendoGameCube:
|
||||
case RedumpSystem.NintendoWii:
|
||||
case RedumpSystem.NintendoWiiU:
|
||||
case RedumpSystem.PhilipsCDi:
|
||||
case RedumpSystem.PhilipsCDiDigitalVideo:
|
||||
case RedumpSystem.Panasonic3DOInteractiveMultiplayer:
|
||||
case RedumpSystem.PanasonicM2:
|
||||
case RedumpSystem.PioneerLaserActive:
|
||||
case RedumpSystem.SuperAudioCD:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if the media supports drive speeds
|
||||
/// </summary>
|
||||
/// <param name="type">MediaType value to check</param>
|
||||
/// <returns>True if the media has variable dumping speeds, false otherwise</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if a system has reversed ringcodes
|
||||
/// </summary>
|
||||
/// <param name="system">RedumpSystem value to check</param>
|
||||
/// <returns>True if the system has reversed ringcodes, false otherwise</returns>
|
||||
public static bool HasReversedRingcodes(this RedumpSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case RedumpSystem.SonyPlayStation2:
|
||||
case RedumpSystem.SonyPlayStation3:
|
||||
case RedumpSystem.SonyPlayStation4:
|
||||
//case RedumpSystem.SonyPlayStation5:
|
||||
case RedumpSystem.SonyPlayStationPortable:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if a system is considered audio-only
|
||||
/// </summary>
|
||||
/// <param name="system">RedumpSystem value to check</param>
|
||||
/// <returns>True if the system is audio-only, false otherwise</returns>
|
||||
/// <remarks>
|
||||
/// Philips CD-i should NOT be in this list. It's being included until there's a
|
||||
/// reasonable distinction between CD-i and CD-i ready on the database side.
|
||||
/// </remarks>
|
||||
public static bool IsAudio(this RedumpSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem:
|
||||
case RedumpSystem.AudioCD:
|
||||
case RedumpSystem.DVDAudio:
|
||||
case RedumpSystem.HasbroiONEducationalGamingSystem:
|
||||
case RedumpSystem.HasbroVideoNow:
|
||||
case RedumpSystem.HasbroVideoNowColor:
|
||||
case RedumpSystem.HasbroVideoNowJr:
|
||||
case RedumpSystem.HasbroVideoNowXP:
|
||||
case RedumpSystem.PhilipsCDi:
|
||||
case RedumpSystem.PlayStationGameSharkUpdates:
|
||||
case RedumpSystem.SuperAudioCD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if a system is considered XGD
|
||||
/// </summary>
|
||||
/// <param name="system">RedumpSystem value to check</param>
|
||||
/// <returns>True if the system is XGD, false otherwise</returns>
|
||||
public static bool IsXGD(this RedumpSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case RedumpSystem.MicrosoftXbox:
|
||||
case RedumpSystem.MicrosoftXbox360:
|
||||
case RedumpSystem.MicrosoftXboxOne:
|
||||
case RedumpSystem.MicrosoftXboxSeriesXS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List all programs with their short usable names
|
||||
/// </summary>
|
||||
public static List<string> ListPrograms()
|
||||
{
|
||||
var programs = new List<string>();
|
||||
|
||||
foreach (var val in Enum.GetValues(typeof(InternalProgram)))
|
||||
{
|
||||
if (((InternalProgram)val) == InternalProgram.NONE)
|
||||
continue;
|
||||
|
||||
programs.Add($"{((InternalProgram?)val).LongName()}");
|
||||
}
|
||||
|
||||
return programs;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MPF.Core.Utilities
|
||||
{
|
||||
public static class Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Process a chunk of text and send it to a handler
|
||||
/// </summary>
|
||||
/// <param name="reader">TextReader representing the input</param>
|
||||
/// <param name="baseClass">Invoking class, passed on to the event handler</param>
|
||||
/// <param name="handler">Event handler to be invoked to write to log</param>
|
||||
#if NET48
|
||||
public static async Task OutputToLog(TextReader reader, object baseClass, EventHandler<string> handler)
|
||||
#else
|
||||
public static async Task OutputToLog(TextReader reader, object baseClass, EventHandler<string>? handler)
|
||||
#endif
|
||||
{
|
||||
// Initialize the required variables
|
||||
char[] buffer = new char[256];
|
||||
int read = 0;
|
||||
var sb = new StringBuilder();
|
||||
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Try to read the next chunk of characters
|
||||
read = await reader.ReadAsync(buffer, 0, buffer.Length);
|
||||
if (read == 0)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert the characters into a string
|
||||
string line = new string(buffer, 0, read);
|
||||
|
||||
// If we have no newline characters, store in the string builder
|
||||
if (!line.Contains("\r") && !line.Contains("\n"))
|
||||
sb.Append(line);
|
||||
|
||||
// If we have a newline, append and log
|
||||
else if (line.Contains("\n") || line.Contains("\r\n"))
|
||||
ProcessNewLines(sb, line, baseClass, handler);
|
||||
|
||||
// If we have a carriage return only, append and log first and last instances
|
||||
else if (line.Contains("\r"))
|
||||
ProcessCarriageReturns(sb, line, baseClass, handler);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
handler?.Invoke(baseClass, sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process a chunk that contains newlines
|
||||
/// </summary>
|
||||
/// <param name="sb">StringBuilder to write from and append to</param>
|
||||
/// <param name="line">Current line to process</param>
|
||||
/// <param name="baseClass">Invoking class, passed on to the event handler</param>
|
||||
/// <param name="handler">Event handler to be invoked to write to log</param>
|
||||
#if NET48
|
||||
private static void ProcessNewLines(StringBuilder sb, string line, object baseClass, EventHandler<string> handler)
|
||||
#else
|
||||
private static void ProcessNewLines(StringBuilder sb, string line, object baseClass, EventHandler<string>? handler)
|
||||
#endif
|
||||
{
|
||||
line = line.Replace("\r\n", "\n");
|
||||
var split = line.Split('\n');
|
||||
for (int i = 0; i < split.Length; i++)
|
||||
{
|
||||
// If the chunk contains a carriage return, handle it like a separate line
|
||||
if (split[i].Contains("\r"))
|
||||
{
|
||||
ProcessCarriageReturns(sb, split[i], baseClass, handler);
|
||||
continue;
|
||||
}
|
||||
|
||||
// For the first item, append to anything existing and then write out
|
||||
if (i == 0)
|
||||
{
|
||||
sb.Append(split[i]);
|
||||
handler?.Invoke(baseClass, sb.ToString());
|
||||
sb.Clear();
|
||||
}
|
||||
|
||||
// For the last item, just append so it's dealt with the next time
|
||||
else if (i == split.Length - 1)
|
||||
{
|
||||
sb.Append(split[i]);
|
||||
}
|
||||
|
||||
// For everything else, directly write out
|
||||
else
|
||||
{
|
||||
handler?.Invoke(baseClass, split[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process a chunk that contains carriage returns
|
||||
/// </summary>
|
||||
/// <param name="sb">StringBuilder to write from and append to</param>
|
||||
/// <param name="line">Current line to process</param>
|
||||
/// <param name="baseClass">Invoking class, passed on to the event handler</param>
|
||||
/// <param name="handler">Event handler to be invoked to write to log</param>
|
||||
#if NET48
|
||||
private static void ProcessCarriageReturns(StringBuilder sb, string line, object baseClass, EventHandler<string> handler)
|
||||
#else
|
||||
private static void ProcessCarriageReturns(StringBuilder sb, string line, object baseClass, EventHandler<string>? handler)
|
||||
#endif
|
||||
{
|
||||
var split = line.Split('\r');
|
||||
|
||||
// Append and log the first
|
||||
sb.Append(split[0]);
|
||||
handler?.Invoke(baseClass, sb.ToString());
|
||||
|
||||
// Append the last
|
||||
sb.Clear();
|
||||
sb.Append($"\r{split[split.Length - 1]}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,301 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Data;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Utilities
|
||||
{
|
||||
public static class OptionsLoader
|
||||
{
|
||||
private const string ConfigurationPath = "config.json";
|
||||
|
||||
#region Arguments
|
||||
|
||||
/// <summary>
|
||||
/// Process any standalone arguments for the program
|
||||
/// </summary>
|
||||
/// <returns>True if one of the arguments was processed, false otherwise</returns>
|
||||
public static bool? ProcessStandaloneArguments(string[] args)
|
||||
{
|
||||
// Help options
|
||||
if (args.Length == 0 || args[0] == "-h" || args[0] == "-?")
|
||||
return false;
|
||||
|
||||
// List options
|
||||
if (args[0] == "-lm" || args[0] == "--listmedia")
|
||||
{
|
||||
Console.WriteLine("Supported Media Types:");
|
||||
foreach (string mediaType in Extensions.ListMediaTypes())
|
||||
{
|
||||
Console.WriteLine(mediaType);
|
||||
}
|
||||
Console.ReadLine();
|
||||
return true;
|
||||
}
|
||||
else if (args[0] == "-lp" || args[0] == "--listprograms")
|
||||
{
|
||||
Console.WriteLine("Supported Programs:");
|
||||
foreach (string program in EnumExtensions.ListPrograms())
|
||||
{
|
||||
Console.WriteLine(program);
|
||||
}
|
||||
Console.ReadLine();
|
||||
return true;
|
||||
}
|
||||
else if (args[0] == "-ls" || args[0] == "--listsystems")
|
||||
{
|
||||
Console.WriteLine("Supported Systems:");
|
||||
foreach (string system in Extensions.ListSystems())
|
||||
{
|
||||
Console.WriteLine(system);
|
||||
}
|
||||
Console.ReadLine();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process common arguments for all functionality
|
||||
/// </summary>
|
||||
/// <returns>True if all arguments pass, false otherwise</returns>
|
||||
#if NET48
|
||||
public static (bool, MediaType, RedumpSystem?, string) ProcessCommonArguments(string[] args)
|
||||
#else
|
||||
public static (bool, MediaType, RedumpSystem?, string?) ProcessCommonArguments(string[] args)
|
||||
#endif
|
||||
{
|
||||
// All other use requires at least 3 arguments
|
||||
if (args.Length < 3)
|
||||
return (false, MediaType.NONE, null, "Invalid number of arguments");
|
||||
|
||||
// Check the MediaType
|
||||
var mediaType = EnumConverter.ToMediaType(args[0].Trim('"'));
|
||||
if (mediaType == MediaType.NONE)
|
||||
return (false, MediaType.NONE, null, $"{args[0]} is not a recognized media type");
|
||||
|
||||
// Check the RedumpSystem
|
||||
var knownSystem = Extensions.ToRedumpSystem(args[1].Trim('"'));
|
||||
if (knownSystem == null)
|
||||
return (false, MediaType.NONE, null, $"{args[1]} is not a recognized system");
|
||||
|
||||
return (true, mediaType, knownSystem, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load the current set of options from application arguments
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public static (Options, SubmissionInfo, string, int) LoadFromArguments(string[] args, int startIndex = 0)
|
||||
#else
|
||||
public static (Options, SubmissionInfo?, string?, int) LoadFromArguments(string[] args, int startIndex = 0)
|
||||
#endif
|
||||
{
|
||||
// Create the output values with defaults
|
||||
var options = new Options()
|
||||
{
|
||||
RedumpUsername = null,
|
||||
RedumpPassword = null,
|
||||
InternalProgram = InternalProgram.NONE,
|
||||
AddFilenameSuffix = false,
|
||||
OutputSubmissionJSON = false,
|
||||
CompressLogFiles = false,
|
||||
DeleteUnnecessaryFiles = false,
|
||||
};
|
||||
|
||||
// Create the submission info to return, if necessary
|
||||
#if NET48
|
||||
SubmissionInfo info = null;
|
||||
string parsedPath = null;
|
||||
#else
|
||||
SubmissionInfo? info = null;
|
||||
string? parsedPath = null;
|
||||
#endif
|
||||
|
||||
// These values require multiple parts to be active
|
||||
bool scan = false, protectFile = false;
|
||||
|
||||
// If we have no arguments, just return
|
||||
if (args == null || args.Length == 0)
|
||||
return (options, null, null, 0);
|
||||
|
||||
// If we have an invalid start index, just return
|
||||
if (startIndex < 0 || startIndex >= args.Length)
|
||||
return (options, null, null, startIndex);
|
||||
|
||||
// Loop through the arguments and parse out values
|
||||
for (; startIndex < args.Length; startIndex++)
|
||||
{
|
||||
// Use specific program
|
||||
if (args[startIndex].StartsWith("-u=") || args[startIndex].StartsWith("--use="))
|
||||
{
|
||||
string internalProgram = args[startIndex].Split('=')[1];
|
||||
options.InternalProgram = EnumConverter.ToInternalProgram(internalProgram);
|
||||
}
|
||||
else if (args[startIndex] == "-u" || args[startIndex] == "--use")
|
||||
{
|
||||
string internalProgram = args[startIndex + 1];
|
||||
options.InternalProgram = EnumConverter.ToInternalProgram(internalProgram);
|
||||
startIndex++;
|
||||
}
|
||||
|
||||
// Redump login
|
||||
else if (args[startIndex].StartsWith("-c=") || args[startIndex].StartsWith("--credentials="))
|
||||
{
|
||||
string[] credentials = args[startIndex].Split('=')[1].Split(';');
|
||||
options.RedumpUsername = credentials[0];
|
||||
options.RedumpPassword = credentials[1];
|
||||
}
|
||||
else if (args[startIndex] == "-c" || args[startIndex] == "--credentials")
|
||||
{
|
||||
options.RedumpUsername = args[startIndex + 1];
|
||||
options.RedumpPassword = args[startIndex + 2];
|
||||
startIndex += 2;
|
||||
}
|
||||
|
||||
// Pull all information (requires Redump login)
|
||||
else if (args[startIndex].Equals("-a") || args[startIndex].Equals("--pull-all"))
|
||||
{
|
||||
options.PullAllInformation = true;
|
||||
}
|
||||
|
||||
// Use a device path for physical checks
|
||||
else if (args[startIndex].StartsWith("-p=") || args[startIndex].StartsWith("--path="))
|
||||
{
|
||||
parsedPath = args[startIndex].Split('=')[1];
|
||||
}
|
||||
else if (args[startIndex] == "-p" || args[startIndex] == "--path")
|
||||
{
|
||||
parsedPath = args[startIndex + 1];
|
||||
startIndex++;
|
||||
}
|
||||
|
||||
// Scan for protection (requires device path)
|
||||
else if (args[startIndex].Equals("-s") || args[startIndex].Equals("--scan"))
|
||||
{
|
||||
scan = true;
|
||||
}
|
||||
|
||||
// Output protection to separate file (requires scan for protection)
|
||||
else if (args[startIndex].Equals("-f") || args[startIndex].Equals("--protect-file"))
|
||||
{
|
||||
protectFile = true;
|
||||
}
|
||||
|
||||
// Include seed info file
|
||||
else if (args[startIndex].StartsWith("-l=") || args[startIndex].StartsWith("--load-seed="))
|
||||
{
|
||||
string seedInfo = args[startIndex].Split('=')[1];
|
||||
info = SubmissionInfoTool.CreateFromFile(seedInfo);
|
||||
}
|
||||
else if (args[startIndex] == "-l" || args[startIndex] == "--load-seed")
|
||||
{
|
||||
string seedInfo = args[startIndex + 1];
|
||||
info = SubmissionInfoTool.CreateFromFile(seedInfo);
|
||||
startIndex++;
|
||||
}
|
||||
|
||||
// Add filename suffix
|
||||
else if (args[startIndex].Equals("-x") || args[startIndex].Equals("--suffix"))
|
||||
{
|
||||
options.AddFilenameSuffix = true;
|
||||
}
|
||||
|
||||
// Output submission JSON
|
||||
else if (args[startIndex].Equals("-j") || args[startIndex].Equals("--json"))
|
||||
{
|
||||
options.OutputSubmissionJSON = true;
|
||||
}
|
||||
|
||||
// Compress log and extraneous files
|
||||
else if (args[startIndex].Equals("-z") || args[startIndex].Equals("--zip"))
|
||||
{
|
||||
options.CompressLogFiles = true;
|
||||
}
|
||||
|
||||
// Delete unnecessary files files
|
||||
else if (args[startIndex].Equals("-d") || args[startIndex].Equals("--delete"))
|
||||
{
|
||||
options.DeleteUnnecessaryFiles = true;
|
||||
}
|
||||
|
||||
// Default, we fall out
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Now deal with the complex options
|
||||
options.ScanForProtection = scan && !string.IsNullOrWhiteSpace(parsedPath);
|
||||
options.OutputSeparateProtectionFile = scan && protectFile && !string.IsNullOrWhiteSpace(parsedPath);
|
||||
|
||||
return (options, info, parsedPath, startIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a list of supported arguments and descriptions
|
||||
/// </summary>
|
||||
public static List<string> PrintSupportedArguments()
|
||||
{
|
||||
var supportedArguments = new List<string>
|
||||
{
|
||||
"-u, --use <program> Dumping program output type [REQUIRED]",
|
||||
"-c, --credentials <user> <pw> Redump username and password",
|
||||
"-a, --pull-all Pull all information from Redump (requires --credentials)",
|
||||
"-p, --path <drivepath> Physical drive path for additional checks",
|
||||
"-s, --scan Enable copy protection scan (requires --path)",
|
||||
"-f, --protect-file Output protection to separate file (requires --scan)",
|
||||
"-l, --load-seed <path> Load a seed submission JSON for user information",
|
||||
"-x, --suffix Enable adding filename suffix",
|
||||
"-j, --json Enable submission JSON output",
|
||||
"-z, --zip Enable log file compression",
|
||||
"-d, --delete Enable unnecessary file deletion",
|
||||
};
|
||||
|
||||
return supportedArguments;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Configuration
|
||||
|
||||
/// <summary>
|
||||
/// Load the current set of options from the application configuration
|
||||
/// </summary>
|
||||
public static Options LoadFromConfig()
|
||||
{
|
||||
if (!File.Exists(ConfigurationPath))
|
||||
{
|
||||
_ = File.Create(ConfigurationPath);
|
||||
return new Options();
|
||||
}
|
||||
|
||||
var serializer = JsonSerializer.Create();
|
||||
var reader = new StreamReader(ConfigurationPath);
|
||||
#if NET48
|
||||
var settings = serializer.Deserialize(reader, typeof(Dictionary<string, string>)) as Dictionary<string, string>;
|
||||
#else
|
||||
var settings = serializer.Deserialize(reader, typeof(Dictionary<string, string?>)) as Dictionary<string, string?>;
|
||||
#endif
|
||||
return new Options(settings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save the current set of options to the application configuration
|
||||
/// </summary>
|
||||
public static void SaveToConfig(Options options)
|
||||
{
|
||||
var serializer = JsonSerializer.Create();
|
||||
var sw = new StreamWriter(ConfigurationPath) { AutoFlush = true };
|
||||
var writer = new JsonTextWriter(sw) { Formatting = Formatting.Indented };
|
||||
serializer.Serialize(writer, options.Settings, typeof(Dictionary<string, string>));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,365 +0,0 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using MPF.Core.Data;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Utilities
|
||||
{
|
||||
public static class Tools
|
||||
{
|
||||
#region Byte Arrays
|
||||
|
||||
/// <summary>
|
||||
/// Search for a byte array in another array
|
||||
/// </summary>
|
||||
public static bool Contains(this byte[] stack, byte[] needle, out int position, int start = 0, int end = -1)
|
||||
{
|
||||
// Initialize the found position to -1
|
||||
position = -1;
|
||||
|
||||
// If either array is null or empty, we can't do anything
|
||||
if (stack == null || stack.Length == 0 || needle == null || needle.Length == 0)
|
||||
return false;
|
||||
|
||||
// If the needle array is larger than the stack array, it can't be contained within
|
||||
if (needle.Length > stack.Length)
|
||||
return false;
|
||||
|
||||
// If start or end are not set properly, set them to defaults
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
if (end < 0)
|
||||
end = stack.Length - needle.Length;
|
||||
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
if (stack.EqualAt(needle, i))
|
||||
{
|
||||
position = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See if a byte array starts with another
|
||||
/// </summary>
|
||||
public static bool StartsWith(this byte[] stack, byte[] needle)
|
||||
{
|
||||
return stack.Contains(needle, out int _, start: 0, end: 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get if a stack at a certain index is equal to a needle
|
||||
/// </summary>
|
||||
private static bool EqualAt(this byte[] stack, byte[] needle, int index)
|
||||
{
|
||||
// If we're too close to the end of the stack, return false
|
||||
if (needle.Length >= stack.Length - index)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < needle.Length; i++)
|
||||
{
|
||||
if (stack[i + index] != needle[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Support
|
||||
|
||||
/// <summary>
|
||||
/// Verify that, given a system and a media type, they are correct
|
||||
/// </summary>
|
||||
public static Result GetSupportStatus(RedumpSystem? system, MediaType? type)
|
||||
{
|
||||
// No system chosen, update status
|
||||
if (system == null)
|
||||
return Result.Failure("Please select a valid system");
|
||||
|
||||
// If we're on an unsupported type, update the status accordingly
|
||||
#if NET48
|
||||
switch (type)
|
||||
{
|
||||
// Fully supported types
|
||||
case MediaType.BluRay:
|
||||
case MediaType.CDROM:
|
||||
case MediaType.DVD:
|
||||
case MediaType.FloppyDisk:
|
||||
case MediaType.HardDisk:
|
||||
case MediaType.CompactFlash:
|
||||
case MediaType.SDCard:
|
||||
case MediaType.FlashDrive:
|
||||
case MediaType.HDDVD:
|
||||
return Result.Success($"{type.LongName()} ready to dump");
|
||||
|
||||
// Partially supported types
|
||||
case MediaType.GDROM:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return Result.Success($"{type.LongName()} partially supported for dumping");
|
||||
|
||||
// Special case for other supported tools
|
||||
case MediaType.UMD:
|
||||
return Result.Failure($"{type.LongName()} supported for submission info parsing");
|
||||
|
||||
// Specifically unknown type
|
||||
case MediaType.NONE:
|
||||
return Result.Failure($"Please select a valid media type");
|
||||
|
||||
// Undumpable but recognized types
|
||||
default:
|
||||
return Result.Failure($"{type.LongName()} media are not supported for dumping");
|
||||
}
|
||||
#else
|
||||
return type switch
|
||||
{
|
||||
// Fully supported types
|
||||
MediaType.BluRay
|
||||
or MediaType.CDROM
|
||||
or MediaType.DVD
|
||||
or MediaType.FloppyDisk
|
||||
or MediaType.HardDisk
|
||||
or MediaType.CompactFlash
|
||||
or MediaType.SDCard
|
||||
or MediaType.FlashDrive
|
||||
or MediaType.HDDVD => Result.Success($"{type.LongName()} ready to dump"),
|
||||
|
||||
// Partially supported types
|
||||
MediaType.GDROM
|
||||
or MediaType.NintendoGameCubeGameDisc
|
||||
or MediaType.NintendoWiiOpticalDisc => Result.Success($"{type.LongName()} partially supported for dumping"),
|
||||
|
||||
// Special case for other supported tools
|
||||
MediaType.UMD => Result.Failure($"{type.LongName()} supported for submission info parsing"),
|
||||
|
||||
// Specifically unknown type
|
||||
MediaType.NONE => Result.Failure($"Please select a valid media type"),
|
||||
|
||||
// Undumpable but recognized types
|
||||
_ => Result.Failure($"{type.LongName()} media are not supported for dumping"),
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns false if a given InternalProgram does not support a given MediaType
|
||||
/// </summary>
|
||||
public static bool ProgramSupportsMedia(InternalProgram program, MediaType? type)
|
||||
{
|
||||
// If the media type is not set, return false
|
||||
if (type == null || type == MediaType.NONE)
|
||||
return false;
|
||||
|
||||
#if NET48
|
||||
switch (program)
|
||||
{
|
||||
case InternalProgram.Redumper:
|
||||
switch (type)
|
||||
{
|
||||
// Formats considered at least partially dumpable by Redumper
|
||||
case MediaType.BluRay:
|
||||
case MediaType.CDROM:
|
||||
case MediaType.DVD:
|
||||
case MediaType.GDROM:
|
||||
case MediaType.HDDVD:
|
||||
return true;
|
||||
|
||||
// All other formats considered unsupported
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case InternalProgram.Aaru:
|
||||
case InternalProgram.DiscImageCreator:
|
||||
switch (type)
|
||||
{
|
||||
// Formats considered at least partially supported
|
||||
case MediaType.BluRay:
|
||||
case MediaType.CDROM:
|
||||
case MediaType.DVD:
|
||||
case MediaType.FloppyDisk:
|
||||
case MediaType.HardDisk:
|
||||
case MediaType.CompactFlash:
|
||||
case MediaType.SDCard:
|
||||
case MediaType.FlashDrive:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return true;
|
||||
|
||||
// All other formats considered unsupported
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
// All other InternalPrograms are not used for dumping
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return (program) switch
|
||||
{
|
||||
// Aaru
|
||||
InternalProgram.Aaru when type == MediaType.BluRay => true,
|
||||
InternalProgram.Aaru when type == MediaType.CDROM => true,
|
||||
InternalProgram.Aaru when type == MediaType.CompactFlash => true,
|
||||
InternalProgram.Aaru when type == MediaType.DVD => true,
|
||||
InternalProgram.Aaru when type == MediaType.GDROM => true,
|
||||
InternalProgram.Aaru when type == MediaType.FlashDrive => true,
|
||||
InternalProgram.Aaru when type == MediaType.FloppyDisk => true,
|
||||
InternalProgram.Aaru when type == MediaType.HardDisk => true,
|
||||
InternalProgram.Aaru when type == MediaType.HDDVD => true,
|
||||
InternalProgram.Aaru when type == MediaType.NintendoGameCubeGameDisc => true,
|
||||
InternalProgram.Aaru when type == MediaType.NintendoWiiOpticalDisc => true,
|
||||
InternalProgram.Aaru when type == MediaType.SDCard => true,
|
||||
|
||||
// DiscImageCreator
|
||||
InternalProgram.DiscImageCreator when type == MediaType.BluRay => true,
|
||||
InternalProgram.DiscImageCreator when type == MediaType.CDROM => true,
|
||||
InternalProgram.DiscImageCreator when type == MediaType.CompactFlash => true,
|
||||
InternalProgram.DiscImageCreator when type == MediaType.DVD => true,
|
||||
InternalProgram.DiscImageCreator when type == MediaType.GDROM => true,
|
||||
InternalProgram.DiscImageCreator when type == MediaType.FlashDrive => true,
|
||||
InternalProgram.DiscImageCreator when type == MediaType.FloppyDisk => true,
|
||||
InternalProgram.DiscImageCreator when type == MediaType.HardDisk => true,
|
||||
InternalProgram.DiscImageCreator when type == MediaType.HDDVD => true,
|
||||
InternalProgram.DiscImageCreator when type == MediaType.NintendoGameCubeGameDisc => true,
|
||||
InternalProgram.DiscImageCreator when type == MediaType.NintendoWiiOpticalDisc => true,
|
||||
InternalProgram.DiscImageCreator when type == MediaType.SDCard => true,
|
||||
|
||||
// Redumper
|
||||
InternalProgram.Redumper when type == MediaType.BluRay => true,
|
||||
InternalProgram.Redumper when type == MediaType.CDROM => true,
|
||||
InternalProgram.Redumper when type == MediaType.DVD => true,
|
||||
InternalProgram.Redumper when type == MediaType.GDROM => true,
|
||||
InternalProgram.Redumper when type == MediaType.HDDVD => true,
|
||||
|
||||
// Default
|
||||
_ => false,
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Versioning
|
||||
|
||||
/// <summary>
|
||||
/// Check for a new MPF version
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Bool representing if the values are different.
|
||||
/// String representing the message to display the the user.
|
||||
/// String representing the new release URL.
|
||||
/// </returns>
|
||||
#if NET48
|
||||
public static (bool different, string message, string url) CheckForNewVersion()
|
||||
#else
|
||||
public static (bool different, string message, string? url) CheckForNewVersion()
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get current assembly version
|
||||
var assemblyVersion = Assembly.GetEntryAssembly()?.GetName()?.Version;
|
||||
if (assemblyVersion == null)
|
||||
return (false, "Assembly version could not be determined", null);
|
||||
|
||||
string version = $"{assemblyVersion.Major}.{assemblyVersion.Minor}.{assemblyVersion.Build}";
|
||||
|
||||
// Get the latest tag from GitHub
|
||||
var (tag, url) = GetRemoteVersionAndUrl();
|
||||
bool different = version != tag;
|
||||
|
||||
string message = $"Local version: {version}"
|
||||
+ $"{Environment.NewLine}Remote version: {tag}"
|
||||
+ (different
|
||||
? $"{Environment.NewLine}The update URL has been added copied to your clipboard"
|
||||
: $"{Environment.NewLine}You have the newest version!");
|
||||
|
||||
return (different, message, url);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (false, ex.ToString(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current informational version formatted as a string
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public static string GetCurrentVersion()
|
||||
#else
|
||||
public static string? GetCurrentVersion()
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
var assembly = Assembly.GetEntryAssembly();
|
||||
if (assembly == null)
|
||||
return null;
|
||||
|
||||
var assemblyVersion = Attribute.GetCustomAttribute(assembly, typeof(AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute;
|
||||
return assemblyVersion?.InformationalVersion;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ex.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the latest version of MPF from GitHub and the release URL
|
||||
/// </summary>
|
||||
#if NET48
|
||||
private static (string tag, string url) GetRemoteVersionAndUrl()
|
||||
#else
|
||||
private static (string? tag, string? url) GetRemoteVersionAndUrl()
|
||||
#endif
|
||||
{
|
||||
#if NET48
|
||||
using (var wc = new System.Net.WebClient())
|
||||
{
|
||||
wc.Headers["User-Agent"] = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0";
|
||||
|
||||
// TODO: Figure out a better way than having this hardcoded...
|
||||
string url = "https://api.github.com/repos/SabreTools/MPF/releases/latest";
|
||||
string latestReleaseJsonString = wc.DownloadString(url);
|
||||
var latestReleaseJson = JObject.Parse(latestReleaseJsonString);
|
||||
string latestTag = latestReleaseJson["tag_name"].ToString();
|
||||
string releaseUrl = latestReleaseJson["html_url"].ToString();
|
||||
|
||||
return (latestTag, releaseUrl);
|
||||
}
|
||||
#else
|
||||
using (var hc = new System.Net.Http.HttpClient())
|
||||
{
|
||||
// TODO: Figure out a better way than having this hardcoded...
|
||||
string url = "https://api.github.com/repos/SabreTools/MPF/releases/latest";
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, url);
|
||||
message.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0");
|
||||
var latestReleaseJsonString = hc.Send(message)?.Content?.ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
if (latestReleaseJsonString == null)
|
||||
return (null, null);
|
||||
|
||||
var latestReleaseJson = JObject.Parse(latestReleaseJsonString);
|
||||
if (latestReleaseJson == null)
|
||||
return (null, null);
|
||||
|
||||
var latestTag = latestReleaseJson["tag_name"]?.ToString();
|
||||
var releaseUrl = latestReleaseJson["html_url"]?.ToString();
|
||||
|
||||
return (latestTag, releaseUrl);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
517
MPF.ExecutionContexts.Test/AaruTests.cs
Normal file
517
MPF.ExecutionContexts.Test/AaruTests.cs
Normal file
@@ -0,0 +1,517 @@
|
||||
using System.Collections.Generic;
|
||||
using MPF.ExecutionContexts.Aaru;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.ExecutionContexts.Test
|
||||
{
|
||||
public class AaruTests
|
||||
{
|
||||
#region Converters.Extension
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, ".aaruf")]
|
||||
[InlineData(MediaType.CDROM, ".aaruf")]
|
||||
[InlineData(MediaType.GDROM, ".aaruf")]
|
||||
[InlineData(MediaType.DVD, ".aaruf")]
|
||||
[InlineData(MediaType.HDDVD, ".aaruf")]
|
||||
[InlineData(MediaType.BluRay, ".aaruf")]
|
||||
[InlineData(MediaType.FloppyDisk, ".aaruf")]
|
||||
[InlineData(MediaType.HardDisk, ".aaruf")]
|
||||
[InlineData(MediaType.ApertureCard, ".aaruf")]
|
||||
public void ExtensionTest(MediaType? type, string expected)
|
||||
{
|
||||
string actual = Converters.Extension(type);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Default Values
|
||||
|
||||
private static readonly Dictionary<string, string?> AllOptions = new()
|
||||
{
|
||||
[SettingConstants.EnableDebug] = "true",
|
||||
[SettingConstants.EnableVerbose] = "true",
|
||||
[SettingConstants.ForceDumping] = "true",
|
||||
[SettingConstants.RereadCount] = "1000",
|
||||
[SettingConstants.StripPersonalData] = "true",
|
||||
};
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null, null, "filename.bin", null, null)]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
|
||||
[InlineData(RedumpSystem.SegaDreamcast, MediaType.GDROM, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
|
||||
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
|
||||
[InlineData(RedumpSystem.BDVideo, MediaType.BluRay, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
|
||||
[InlineData(RedumpSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
|
||||
[InlineData(RedumpSystem.NintendoWii, MediaType.NintendoWiiOpticalDisc, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
|
||||
[InlineData(RedumpSystem.NintendoWiiU, MediaType.NintendoWiiUOpticalDisc, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.FloppyDisk, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
|
||||
public void DefaultValueTest(RedumpSystem? system,
|
||||
MediaType? type,
|
||||
string? drivePath,
|
||||
string filename,
|
||||
int? driveSpeed,
|
||||
string? expected)
|
||||
{
|
||||
var context = new ExecutionContext(system, type, drivePath, filename, driveSpeed, AllOptions);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Archive Family
|
||||
|
||||
[Theory]
|
||||
[InlineData("arc info filename.bin")]
|
||||
[InlineData("arc info \"filename.bin\"")]
|
||||
[InlineData("archive info filename.bin")]
|
||||
[InlineData("archive info \"filename.bin\"")]
|
||||
public void ArchiveInfoTest(string parameters)
|
||||
{
|
||||
string? expected = "archive info \"filename.bin\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Database Family
|
||||
|
||||
[Theory]
|
||||
[InlineData("db stats")]
|
||||
[InlineData("database stats")]
|
||||
public void DatabaseStatsTest(string parameters)
|
||||
{
|
||||
string? expected = "database stats";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("db update --clear --clear-all")]
|
||||
[InlineData("db update --clear true --clear-all true")]
|
||||
[InlineData("database update --clear --clear-all")]
|
||||
[InlineData("database update --clear true --clear-all true")]
|
||||
public void DatabaseUpdateTest(string parameters)
|
||||
{
|
||||
string? expected = "database update --clear True --clear-all True";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Device Family
|
||||
|
||||
[Theory]
|
||||
[InlineData("dev info -w prefix filename.bin")]
|
||||
[InlineData("dev info --output-prefix prefix filename.bin")]
|
||||
[InlineData("device info -w prefix filename.bin")]
|
||||
[InlineData("device info --output-prefix prefix filename.bin")]
|
||||
public void DeviceInfoTest(string parameters)
|
||||
{
|
||||
string? expected = "device info --output-prefix \"prefix\" filename.bin";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("dev list localhost")]
|
||||
[InlineData("device list localhost")]
|
||||
public void DeviceListTest(string parameters)
|
||||
{
|
||||
string? expected = "device list \"localhost\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("dev report -t filename.bin")]
|
||||
[InlineData("dev report -t true filename.bin")]
|
||||
[InlineData("dev report --trap-disc filename.bin")]
|
||||
[InlineData("dev report --trap-disc true filename.bin")]
|
||||
[InlineData("device report -t filename.bin")]
|
||||
[InlineData("device report -t true filename.bin")]
|
||||
[InlineData("device report --trap-disc filename.bin")]
|
||||
[InlineData("device report --trap-disc true filename.bin")]
|
||||
public void DeviceReportTest(string parameters)
|
||||
{
|
||||
string? expected = "device report --trap-disc True filename.bin";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Filesystem Family
|
||||
|
||||
[Theory]
|
||||
[InlineData("fi extract -e enc -x -n ns -O opts input output")]
|
||||
[InlineData("fi extract -e enc -x true -n ns -O opts input output")]
|
||||
[InlineData("fi extract --encoding enc --xattrs --namespace ns --options opts input output")]
|
||||
[InlineData("fi extract --encoding enc --xattrs true --namespace ns --options opts input output")]
|
||||
[InlineData("fs extract -e enc -x -n ns -O opts input output")]
|
||||
[InlineData("fs extract -e enc -x true -n ns -O opts input output")]
|
||||
[InlineData("fs extract --encoding enc --xattrs --namespace ns --options opts input output")]
|
||||
[InlineData("fs extract --encoding enc --xattrs true --namespace ns --options opts input output")]
|
||||
[InlineData("filesystem extract -e enc -x -n ns -O opts input output")]
|
||||
[InlineData("filesystem extract -e enc -x true -n ns -O opts input output")]
|
||||
[InlineData("filesystem extract --encoding enc --xattrs --namespace ns --options opts input output")]
|
||||
[InlineData("filesystem extract --encoding enc --xattrs true --namespace ns --options opts input output")]
|
||||
public void FilesystemExtractTest(string parameters)
|
||||
{
|
||||
string? expected = "filesystem extract --xattrs True --encoding \"enc\" --namespace \"ns\" --options \"opts\" \"input\" \"output\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("fi info -e enc -x -n ns -O opts input")]
|
||||
[InlineData("fi info -e enc -x true -n ns -O opts input")]
|
||||
[InlineData("fi info --encoding enc --xattrs --namespace ns --options opts input")]
|
||||
[InlineData("fi info --encoding enc --xattrs true --namespace ns --options opts input")]
|
||||
[InlineData("fs info -e enc -x -n ns -O opts input")]
|
||||
[InlineData("fs info -e enc -x true -n ns -O opts input")]
|
||||
[InlineData("fs info --encoding enc --xattrs --namespace ns --options opts input")]
|
||||
[InlineData("fs info --encoding enc --xattrs true --namespace ns --options opts input")]
|
||||
[InlineData("filesystem info -e enc -x -n ns -O opts input")]
|
||||
[InlineData("filesystem info -e enc -x true -n ns -O opts input")]
|
||||
[InlineData("filesystem info --encoding enc --xattrs --namespace ns --options opts input")]
|
||||
[InlineData("filesystem info --encoding enc --xattrs true --namespace ns --options opts input")]
|
||||
public void FilesystemInfoTest(string parameters)
|
||||
{
|
||||
string? expected = "filesystem info --xattrs True --encoding \"enc\" --namespace \"ns\" --options \"opts\" \"input\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("fi ls -e enc -f -l -p input")]
|
||||
[InlineData("fi list -e enc -f -l -p input")]
|
||||
[InlineData("fi ls -e enc -f true -l true -p true input")]
|
||||
[InlineData("fi list -e enc -f true -l true -p true input")]
|
||||
[InlineData("fi ls --encoding enc --filesystems --long-format --partitions input")]
|
||||
[InlineData("fi list --encoding enc --filesystems --long-format --partitions input")]
|
||||
[InlineData("fi ls --encoding enc --filesystems true --long-format true --partitions true input")]
|
||||
[InlineData("fi list --encoding enc --filesystems true --long-format true --partitions true input")]
|
||||
[InlineData("fs ls -e enc -f -l -p input")]
|
||||
[InlineData("fs list -e enc -f -l -p input")]
|
||||
[InlineData("fs ls -e enc -f true -l true -p true input")]
|
||||
[InlineData("fs list -e enc -f true -l true -p true input")]
|
||||
[InlineData("fs ls --encoding enc --filesystems --long-format --partitions input")]
|
||||
[InlineData("fs list --encoding enc --filesystems --long-format --partitions input")]
|
||||
[InlineData("fs ls --encoding enc --filesystems true --long-format true --partitions true input")]
|
||||
[InlineData("fs list --encoding enc --filesystems true --long-format true --partitions true input")]
|
||||
[InlineData("filesystem ls -e enc -f -l -p input")]
|
||||
[InlineData("filesystem list -e enc -f -l -p input")]
|
||||
[InlineData("filesystem ls -e enc -f true -l true -p true input")]
|
||||
[InlineData("filesystem list -e enc -f true -l true -p true input")]
|
||||
[InlineData("filesystem ls --encoding enc --filesystems --long-format --partitions input")]
|
||||
[InlineData("filesystem list --encoding enc --filesystems --long-format --partitions input")]
|
||||
[InlineData("filesystem ls --encoding enc --filesystems true --long-format true --partitions true input")]
|
||||
[InlineData("filesystem list --encoding enc --filesystems true --long-format true --partitions true input")]
|
||||
public void FilesystemListTest(string parameters)
|
||||
{
|
||||
string? expected = "filesystem list --filesystems True --long-format True --partitions True --encoding \"enc\" \"input\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("fi options")]
|
||||
[InlineData("fs options")]
|
||||
[InlineData("filesystem options")]
|
||||
public void FilesystemOptionsTest(string parameters)
|
||||
{
|
||||
string? expected = "filesystem options";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Image Family
|
||||
|
||||
[Theory]
|
||||
[InlineData("i chk -a --crc16 -c --crc64 --fletcher16 --fletcher32 -m -t -s --sha256 --sha384 --sha512 -f -w filename.bin")]
|
||||
[InlineData("i chk -a true --crc16 true -c true --crc64 true --fletcher16 true --fletcher32 true -m true -t true -s true --sha256 true --sha384 true --sha512 true -f true -w true filename.bin")]
|
||||
[InlineData("i chk --adler32 --crc16 --crc32 --crc64 --fletcher16 --fletcher32 --md5 --separated-tracks --sha1 --sha256 --sha384 --sha512 --spamsum --whole-disc filename.bin")]
|
||||
[InlineData("i chk --adler32 true --crc16 true --crc32 true --crc64 true --fletcher16 true --fletcher32 true --md5 true --separated-tracks true --sha1 true --sha256 true --sha384 true --sha512 true --spamsum true --whole-disc true filename.bin")]
|
||||
[InlineData("i checksum -a --crc16 -c --crc64 --fletcher16 --fletcher32 -m -t -s --sha256 --sha384 --sha512 -f -w filename.bin")]
|
||||
[InlineData("i checksum -a true --crc16 true -c true --crc64 true --fletcher16 true --fletcher32 true -m true -t true -s true --sha256 true --sha384 true --sha512 true -f true -w true filename.bin")]
|
||||
[InlineData("i checksum --adler32 --crc16 --crc32 --crc64 --fletcher16 --fletcher32 --md5 --separated-tracks --sha1 --sha256 --sha384 --sha512 --spamsum --whole-disc filename.bin")]
|
||||
[InlineData("i checksum --adler32 true --crc16 true --crc32 true --crc64 true --fletcher16 true --fletcher32 true --md5 true --separated-tracks true --sha1 true --sha256 true --sha384 true --sha512 true --spamsum true --whole-disc true filename.bin")]
|
||||
[InlineData("image chk -a --crc16 -c --crc64 --fletcher16 --fletcher32 -m -t -s --sha256 --sha384 --sha512 -f -w filename.bin")]
|
||||
[InlineData("image chk -a true --crc16 true -c true --crc64 true --fletcher16 true --fletcher32 true -m true -t true -s true --sha256 true --sha384 true --sha512 true -f true -w true filename.bin")]
|
||||
[InlineData("image chk --adler32 --crc16 --crc32 --crc64 --fletcher16 --fletcher32 --md5 --separated-tracks --sha1 --sha256 --sha384 --sha512 --spamsum --whole-disc filename.bin")]
|
||||
[InlineData("image chk --adler32 true --crc16 true --crc32 true --crc64 true --fletcher16 true --fletcher32 true --md5 true --separated-tracks true --sha1 true --sha256 true --sha384 true --sha512 true --spamsum true --whole-disc true filename.bin")]
|
||||
[InlineData("image checksum -a --crc16 -c --crc64 --fletcher16 --fletcher32 -m -t -s --sha256 --sha384 --sha512 -f -w filename.bin")]
|
||||
[InlineData("image checksum -a true --crc16 true -c true --crc64 true --fletcher16 true --fletcher32 true -m true -t true -s true --sha256 true --sha384 true --sha512 true -f true -w true filename.bin")]
|
||||
[InlineData("image checksum --adler32 --crc16 --crc32 --crc64 --fletcher16 --fletcher32 --md5 --separated-tracks --sha1 --sha256 --sha384 --sha512 --spamsum --whole-disc filename.bin")]
|
||||
[InlineData("image checksum --adler32 true --crc16 true --crc32 true --crc64 true --fletcher16 true --fletcher32 true --md5 true --separated-tracks true --sha1 true --sha256 true --sha384 true --sha512 true --spamsum true --whole-disc true filename.bin")]
|
||||
public void ImageChecksumTest(string parameters)
|
||||
{
|
||||
string? expected = "image checksum --adler32 True --crc16 True --crc32 True --crc64 True --fletcher16 True --fletcher32 True --md5 True --separated-tracks True --sha1 True --sha256 True --sha384 True --sha512 True --spamsum True --whole-disc True \"filename.bin\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("i cmp input1.bin input2.bin")]
|
||||
[InlineData("i compare input1.bin input2.bin")]
|
||||
[InlineData("image cmp input1.bin input2.bin")]
|
||||
[InlineData("image compare input1.bin input2.bin")]
|
||||
public void ImageCompareTest(string parameters)
|
||||
{
|
||||
string? expected = "image compare \"input1.bin\" \"input2.bin\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("i convert --comments co -c 0 --creator cr --drive-manufacturer dm --drive-model dm --drive-revision dr --drive-serial ds --fix-subchannel --fix-subchannel-crc --fix-subchannel-position -f -p fmt --generate-subchannels -g geo --media-barcode mb --media-lastsequence 0 --media-manufacturer mm --media-model mm --media-partnumber mpn --media-sequence 0 --media-serial ms --media-title mt -O opt -r resume -x cicm input1.bin input2.bin")]
|
||||
[InlineData("i convert --comments co -c 0 --creator cr --drive-manufacturer dm --drive-model dm --drive-revision dr --drive-serial ds --fix-subchannel true --fix-subchannel-crc true --fix-subchannel-position true -f true -p fmt --generate-subchannels true -g geo --media-barcode mb --media-lastsequence 0 --media-manufacturer mm --media-model mm --media-partnumber mpn --media-sequence 0 --media-serial ms --media-title mt -O opt -r resume -x cicm input1.bin input2.bin")]
|
||||
[InlineData("i convert --comments co --count 0 --creator cr --drive-manufacturer dm --drive-model dm --drive-revision dr --drive-serial ds --fix-subchannel --fix-subchannel-crc --fix-subchannel-position --force --format fmt --generate-subchannels --geometry geo --media-barcode mb --media-lastsequence 0 --media-manufacturer mm --media-model mm --media-partnumber mpn --media-sequence 0 --media-serial ms --media-title mt --options opt --resume-file resume --cicm-xml cicm input1.bin input2.bin")]
|
||||
[InlineData("i convert --comments co --count 0 --creator cr --drive-manufacturer dm --drive-model dm --drive-revision dr --drive-serial ds --fix-subchannel true --fix-subchannel-crc true --fix-subchannel-position true --force true --format fmt --generate-subchannels true --geometry geo --media-barcode mb --media-lastsequence 0 --media-manufacturer mm --media-model mm --media-partnumber mpn --media-sequence 0 --media-serial ms --media-title mt --options opt --resume-file resume --cicm-xml cicm input1.bin input2.bin")]
|
||||
[InlineData("image convert --comments co -c 0 --creator cr --drive-manufacturer dm --drive-model dm --drive-revision dr --drive-serial ds --fix-subchannel --fix-subchannel-crc --fix-subchannel-position -f -p fmt --generate-subchannels -g geo --media-barcode mb --media-lastsequence 0 --media-manufacturer mm --media-model mm --media-partnumber mpn --media-sequence 0 --media-serial ms --media-title mt -O opt -r resume -x cicm input1.bin input2.bin")]
|
||||
[InlineData("image convert --comments co -c 0 --creator cr --drive-manufacturer dm --drive-model dm --drive-revision dr --drive-serial ds --fix-subchannel true --fix-subchannel-crc true --fix-subchannel-position true -f true -p fmt --generate-subchannels true -g geo --media-barcode mb --media-lastsequence 0 --media-manufacturer mm --media-model mm --media-partnumber mpn --media-sequence 0 --media-serial ms --media-title mt -O opt -r resume -x cicm input1.bin input2.bin")]
|
||||
[InlineData("image convert --comments co --count 0 --creator cr --drive-manufacturer dm --drive-model dm --drive-revision dr --drive-serial ds --fix-subchannel --fix-subchannel-crc --fix-subchannel-position --force --format fmt --generate-subchannels --geometry geo --media-barcode mb --media-lastsequence 0 --media-manufacturer mm --media-model mm --media-partnumber mpn --media-sequence 0 --media-serial ms --media-title mt --options opt --resume-file resume --cicm-xml cicm input1.bin input2.bin")]
|
||||
[InlineData("image convert --comments co --count 0 --creator cr --drive-manufacturer dm --drive-model dm --drive-revision dr --drive-serial ds --fix-subchannel true --fix-subchannel-crc true --fix-subchannel-position true --force true --format fmt --generate-subchannels true --geometry geo --media-barcode mb --media-lastsequence 0 --media-manufacturer mm --media-model mm --media-partnumber mpn --media-sequence 0 --media-serial ms --media-title mt --options opt --resume-file resume --cicm-xml cicm input1.bin input2.bin")]
|
||||
public void ImageConvertTest(string parameters)
|
||||
{
|
||||
string? expected = "image convert --fix-subchannel True --fix-subchannel-crc True --fix-subchannel-position True --force True --generate-subchannels True --count 0 --media-lastsequence 0 --media-sequence 0 --comments \"co\" --creator \"cr\" --drive-manufacturer \"dm\" --drive-model \"dm\" --drive-revision \"dr\" --drive-serial \"ds\" --format \"fmt\" --geometry \"geo\" --media-barcode \"mb\" --media-manufacturer \"mm\" --media-model \"mm\" --media-partnumber \"mpn\" --media-serial \"ms\" --media-title \"mt\" --options \"opt\" --resume-file \"resume\" --cicm-xml \"cicm\" \"input1.bin\" \"input2.bin\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("i create-sidecar -b 0 -e enc -t filename.bin")]
|
||||
[InlineData("i create-sidecar -b 0 -e enc -t true filename.bin")]
|
||||
[InlineData("i create-sidecar --block-size 0 --encoding enc --tape filename.bin")]
|
||||
[InlineData("i create-sidecar --block-size 0 --encoding enc --tape true filename.bin")]
|
||||
[InlineData("image create-sidecar -b 0 -e enc -t filename.bin")]
|
||||
[InlineData("image create-sidecar -b 0 -e enc -t true filename.bin")]
|
||||
[InlineData("image create-sidecar --block-size 0 --encoding enc --tape filename.bin")]
|
||||
[InlineData("image create-sidecar --block-size 0 --encoding enc --tape true filename.bin")]
|
||||
public void ImageCreateSidecarTest(string parameters)
|
||||
{
|
||||
string? expected = "image create-sidecar --tape True --block-size 0 --encoding \"enc\" \"filename.bin\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("i decode -f -l all -p -s 0 filename.bin")]
|
||||
[InlineData("i decode -f true -l all -p true -s 0 filename.bin")]
|
||||
[InlineData("i decode --disk-tags --length all --sector-tags --start 0 filename.bin")]
|
||||
[InlineData("i decode --disk-tags true --length all --sector-tags true --start 0 filename.bin")]
|
||||
[InlineData("image decode -f -l all -p -s 0 filename.bin")]
|
||||
[InlineData("image decode -f true -l all -p true -s 0 filename.bin")]
|
||||
[InlineData("image decode --disk-tags --length all --sector-tags --start 0 filename.bin")]
|
||||
[InlineData("image decode --disk-tags true --length all --sector-tags true --start 0 filename.bin")]
|
||||
public void ImageDecodeTest(string parameters)
|
||||
{
|
||||
string? expected = "image decode --disk-tags True --sector-tags True --length all --start 0 \"filename.bin\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("i entropy -p -t -w filename.bin")]
|
||||
[InlineData("i entropy -p true -t true -w true filename.bin")]
|
||||
[InlineData("i entropy --duplicated-sectors --separated-tracks --whole-disc filename.bin")]
|
||||
[InlineData("i entropy --duplicated-sectors true --separated-tracks true --whole-disc true filename.bin")]
|
||||
[InlineData("image entropy -p -t -w filename.bin")]
|
||||
[InlineData("image entropy -p true -t true -w true filename.bin")]
|
||||
[InlineData("image entropy --duplicated-sectors --separated-tracks --whole-disc filename.bin")]
|
||||
[InlineData("image entropy --duplicated-sectors true --separated-tracks true --whole-disc true filename.bin")]
|
||||
public void ImageEntropyTest(string parameters)
|
||||
{
|
||||
string? expected = "image entropy --duplicated-sectors True --separated-tracks True --whole-disc True \"filename.bin\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("i info filename.bin")]
|
||||
[InlineData("image info filename.bin")]
|
||||
public void ImageInfoTest(string parameters)
|
||||
{
|
||||
string? expected = "image info \"filename.bin\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("i options")]
|
||||
[InlineData("image options")]
|
||||
public void ImageOptionsTest(string parameters)
|
||||
{
|
||||
string? expected = "image options";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("i print -l 0 -r -s 0 -w 0 filename.bin")]
|
||||
[InlineData("i print -l 0 -r true -s 0 -w 0 filename.bin")]
|
||||
[InlineData("i print --length 0 --long-sectors --start 0 --width 0 filename.bin")]
|
||||
[InlineData("i print --length 0 --long-sectors true --start 0 --width 0 filename.bin")]
|
||||
[InlineData("image print -l 0 -r -s 0 -w 0 filename.bin")]
|
||||
[InlineData("image print -l 0 -r true -s 0 -w 0 filename.bin")]
|
||||
[InlineData("image print --length 0 --long-sectors --start 0 --width 0 filename.bin")]
|
||||
[InlineData("image print --length 0 --long-sectors true --start 0 --width 0 filename.bin")]
|
||||
public void ImagePrintTest(string parameters)
|
||||
{
|
||||
string? expected = "image print --long-sectors True --width 0 --length 0 --start 0 \"filename.bin\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("i verify -w -s filename.bin")]
|
||||
[InlineData("i verify -w true -s true filename.bin")]
|
||||
[InlineData("i verify --verify-disc --verify-sectors filename.bin")]
|
||||
[InlineData("i verify --verify-disc true --verify-sectors true filename.bin")]
|
||||
[InlineData("image verify -w -s filename.bin")]
|
||||
[InlineData("image verify -w true -s true filename.bin")]
|
||||
[InlineData("image verify --verify-disc --verify-sectors filename.bin")]
|
||||
[InlineData("image verify --verify-disc true --verify-sectors true filename.bin")]
|
||||
public void ImageVerifyTest(string parameters)
|
||||
{
|
||||
string? expected = "image verify --verify-disc True --verify-sectors True \"filename.bin\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Media Family
|
||||
|
||||
[Theory]
|
||||
[InlineData("m dump --eject -e enc --first-pregap --fix-offset --fix-subchannel --fix-subchannel-crc --fix-subchannel-position -f --generate-subchannels --max-blocks 0 --metadata -O opt --persistent --private -r -p 0 --retry-subchannel -k 0 --skip-cdiready-hole --speed 0 -s --store-encrypted --subchannel any --title-keys --trim --use-buffered-reads -x cicm input output.bin")]
|
||||
[InlineData("m dump --eject true -e enc --first-pregap true --fix-offset true --fix-subchannel true --fix-subchannel-crc true --fix-subchannel-position true -f true --generate-subchannels true --max-blocks 0 --metadata true -O opt --persistent true --private true -r true -p 0 --retry-subchannel true -k 0 --skip-cdiready-hole true --speed 0 -s true --store-encrypted true --subchannel any --title-keys true --trim true --use-buffered-reads true -x cicm input output.bin")]
|
||||
[InlineData("m dump --eject --encoding enc --first-pregap --fix-offset --fix-subchannel --fix-subchannel-crc --fix-subchannel-position --force --generate-subchannels --max-blocks 0 --metadata --options opt --persistent --private --resume --retry-passes 0 --retry-subchannel --skip 0 --skip-cdiready-hole --speed 0 --stop-on-error --store-encrypted --subchannel any --title-keys --trim --use-buffered-reads --cicm-xml cicm input output.bin")]
|
||||
[InlineData("m dump --eject true --encoding enc --first-pregap true --fix-offset true --fix-subchannel true --fix-subchannel-crc true --fix-subchannel-position true --force true --generate-subchannels true --max-blocks 0 --metadata true --options opt --persistent true --private true --resume true --retry-passes 0 --retry-subchannel true --skip 0 --skip-cdiready-hole true --speed 0 --stop-on-error true --store-encrypted true --subchannel any --title-keys true --trim true --use-buffered-reads true --cicm-xml cicm input output.bin")]
|
||||
[InlineData("media dump --eject -e enc --first-pregap --fix-offset --fix-subchannel --fix-subchannel-crc --fix-subchannel-position -f --generate-subchannels --max-blocks 0 --metadata -O opt --persistent --private -r -p 0 --retry-subchannel -k 0 --skip-cdiready-hole --speed 0 -s --store-encrypted --subchannel any --title-keys --trim --use-buffered-reads -x cicm input output.bin")]
|
||||
[InlineData("media dump --eject true -e enc --first-pregap true --fix-offset true --fix-subchannel true --fix-subchannel-crc true --fix-subchannel-position true -f true --generate-subchannels true --max-blocks 0 --metadata true -O opt --persistent true --private true -r true -p 0 --retry-subchannel true -k 0 --skip-cdiready-hole true --speed 0 -s true --store-encrypted true --subchannel any --title-keys true --trim true --use-buffered-reads true -x cicm input output.bin")]
|
||||
[InlineData("media dump --eject --encoding enc --first-pregap --fix-offset --fix-subchannel --fix-subchannel-crc --fix-subchannel-position --force --generate-subchannels --max-blocks 0 --metadata --options opt --persistent --private --resume --retry-passes 0 --retry-subchannel --skip 0 --skip-cdiready-hole --speed 0 --stop-on-error --store-encrypted --subchannel any --title-keys --trim --use-buffered-reads --cicm-xml cicm input output.bin")]
|
||||
[InlineData("media dump --eject true --encoding enc --first-pregap true --fix-offset true --fix-subchannel true --fix-subchannel-crc true --fix-subchannel-position true --force true --generate-subchannels true --max-blocks 0 --metadata true --options opt --persistent true --private true --resume true --retry-passes 0 --retry-subchannel true --skip 0 --skip-cdiready-hole true --speed 0 --stop-on-error true --store-encrypted true --subchannel any --title-keys true --trim true --use-buffered-reads true --cicm-xml cicm input output.bin")]
|
||||
public void MediaDumpTest(string parameters)
|
||||
{
|
||||
string? expected = "media dump --eject True --first-pregap True --fix-offset True --fix-subchannel True --fix-subchannel-crc True --fix-subchannel-position True --force True --generate-subchannels True --metadata True --persistent True --private True --resume True --retry-subchannel True --skip-cdiready-hole True --stop-on-error True --store-encrypted True --title-keys True --trim True --use-buffered-reads True --speed 0 --retry-passes 0 --max-blocks 0 --skip 0 --encoding \"enc\" --options \"opt\" --subchannel \"any\" --cicm-xml \"cicm\" input \"output.bin\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.True(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("m info -w prefix input")]
|
||||
[InlineData("m info --output-prefix prefix input")]
|
||||
[InlineData("media info -w prefix input")]
|
||||
[InlineData("media info --output-prefix prefix input")]
|
||||
public void MediaInfoTest(string parameters)
|
||||
{
|
||||
string? expected = "media info --output-prefix \"prefix\" input";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("m scan -b ibg -m mhdd --use-buffered-reads input")]
|
||||
[InlineData("m scan -b ibg -m mhdd --use-buffered-reads true input")]
|
||||
[InlineData("m scan --ibg-log ibg --mhdd-log mhdd --use-buffered-reads input")]
|
||||
[InlineData("m scan --ibg-log ibg --mhdd-log mhdd --use-buffered-reads true input")]
|
||||
[InlineData("media scan -b ibg -m mhdd --use-buffered-reads input")]
|
||||
[InlineData("media scan -b ibg -m mhdd --use-buffered-reads true input")]
|
||||
[InlineData("media scan --ibg-log ibg --mhdd-log mhdd --use-buffered-reads input")]
|
||||
[InlineData("media scan --ibg-log ibg --mhdd-log mhdd --use-buffered-reads true input")]
|
||||
public void MediaScanTest(string parameters)
|
||||
{
|
||||
string? expected = "media scan --use-buffered-reads True --ibg-log \"ibg\" --mhdd-log \"mhdd\" input";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Standalone Commands
|
||||
|
||||
[Theory]
|
||||
[InlineData("--debug --help --verbose --version formats")]
|
||||
[InlineData("--debug true --help true --verbose true --version true formats")]
|
||||
public void PreCommandFlagsTest(string parameters)
|
||||
{
|
||||
string? expected = "--debug True --help True --verbose True --version True formats";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("configure", "configure")]
|
||||
[InlineData("formats", "formats")]
|
||||
[InlineData("list-encodings", "list-encodings")]
|
||||
[InlineData("list-namespaces", "list-namespaces")]
|
||||
[InlineData("remote localhost", "remote \"localhost\"")]
|
||||
public void StandaloneCommandsTest(string parameters, string? expected)
|
||||
{
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
464
MPF.ExecutionContexts.Test/BaseExecutionContextTests.cs
Normal file
464
MPF.ExecutionContexts.Test/BaseExecutionContextTests.cs
Normal file
@@ -0,0 +1,464 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.ExecutionContexts.Test
|
||||
{
|
||||
public class BaseExecutionContextTests
|
||||
{
|
||||
#region GetBooleanSetting
|
||||
|
||||
[Fact]
|
||||
public void GetBooleanSetting_InvalidDict_Default()
|
||||
{
|
||||
Dictionary<string, string?> settings = [];
|
||||
string key = "key";
|
||||
bool defaultValue = false;
|
||||
|
||||
bool actual = BaseExecutionContext.GetBooleanSetting(settings, key, defaultValue);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetBooleanSetting_InvalidKey_Default()
|
||||
{
|
||||
Dictionary<string, string?> settings = new()
|
||||
{
|
||||
["key2"] = "true",
|
||||
};
|
||||
string key = "key";
|
||||
bool defaultValue = false;
|
||||
|
||||
bool actual = BaseExecutionContext.GetBooleanSetting(settings, key, defaultValue);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetBooleanSetting_NullValue_Default()
|
||||
{
|
||||
Dictionary<string, string?> settings = new()
|
||||
{
|
||||
["key"] = null,
|
||||
};
|
||||
string key = "key";
|
||||
bool defaultValue = false;
|
||||
|
||||
bool actual = BaseExecutionContext.GetBooleanSetting(settings, key, defaultValue);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetBooleanSetting_InvalidValue_Default()
|
||||
{
|
||||
Dictionary<string, string?> settings = new()
|
||||
{
|
||||
["key"] = "invalid",
|
||||
};
|
||||
string key = "key";
|
||||
bool defaultValue = false;
|
||||
|
||||
bool actual = BaseExecutionContext.GetBooleanSetting(settings, key, defaultValue);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetBooleanSetting_ValidValue_Parsed()
|
||||
{
|
||||
Dictionary<string, string?> settings = new()
|
||||
{
|
||||
["key"] = "true",
|
||||
};
|
||||
string key = "key";
|
||||
bool defaultValue = false;
|
||||
|
||||
bool actual = BaseExecutionContext.GetBooleanSetting(settings, key, defaultValue);
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetInt32Setting
|
||||
|
||||
[Fact]
|
||||
public void GetInt32Setting_InvalidDict_Default()
|
||||
{
|
||||
Dictionary<string, string?> settings = [];
|
||||
string key = "key";
|
||||
int defaultValue = -1;
|
||||
|
||||
int actual = BaseExecutionContext.GetInt32Setting(settings, key, defaultValue);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetInt32Setting_InvalidKey_Default()
|
||||
{
|
||||
Dictionary<string, string?> settings = new()
|
||||
{
|
||||
["key2"] = "12345",
|
||||
};
|
||||
string key = "key";
|
||||
int defaultValue = -1;
|
||||
|
||||
int actual = BaseExecutionContext.GetInt32Setting(settings, key, defaultValue);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetInt32Setting_NullValue_Default()
|
||||
{
|
||||
Dictionary<string, string?> settings = new()
|
||||
{
|
||||
["key"] = null,
|
||||
};
|
||||
string key = "key";
|
||||
int defaultValue = -1;
|
||||
|
||||
int actual = BaseExecutionContext.GetInt32Setting(settings, key, defaultValue);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetInt32Setting_InvalidValue_Default()
|
||||
{
|
||||
Dictionary<string, string?> settings = new()
|
||||
{
|
||||
["key"] = "invalid",
|
||||
};
|
||||
string key = "key";
|
||||
int defaultValue = -1;
|
||||
|
||||
int actual = BaseExecutionContext.GetInt32Setting(settings, key, defaultValue);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetInt32Setting_ValidValue_Parsed()
|
||||
{
|
||||
int expected = 12345;
|
||||
Dictionary<string, string?> settings = new()
|
||||
{
|
||||
["key"] = "12345",
|
||||
};
|
||||
string key = "key";
|
||||
int defaultValue = -1;
|
||||
|
||||
int actual = BaseExecutionContext.GetInt32Setting(settings, key, defaultValue);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetStringSetting
|
||||
|
||||
[Fact]
|
||||
public void GetStringSetting_InvalidDict_Default()
|
||||
{
|
||||
Dictionary<string, string?> settings = [];
|
||||
string key = "key";
|
||||
string? defaultValue = null;
|
||||
|
||||
string? actual = BaseExecutionContext.GetStringSetting(settings, key, defaultValue);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStringSetting_InvalidKey_Default()
|
||||
{
|
||||
Dictionary<string, string?> settings = new()
|
||||
{
|
||||
["key2"] = "12345",
|
||||
};
|
||||
string key = "key";
|
||||
string? defaultValue = null;
|
||||
|
||||
string? actual = BaseExecutionContext.GetStringSetting(settings, key, defaultValue);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStringSetting_ValidValue_Rturned()
|
||||
{
|
||||
string expected = "expected";
|
||||
Dictionary<string, string?> settings = new()
|
||||
{
|
||||
["key"] = "expected",
|
||||
};
|
||||
string key = "key";
|
||||
string? defaultValue = null;
|
||||
|
||||
string? actual = BaseExecutionContext.GetStringSetting(settings, key, defaultValue);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SplitParameterString
|
||||
|
||||
[Fact]
|
||||
public void SplitParameterString_Empty_Empty()
|
||||
{
|
||||
string parameters = string.Empty;
|
||||
string[] actual = BaseExecutionContext.SplitParameterString(parameters);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SplitParameterString_NoSplit_Single()
|
||||
{
|
||||
string expected = "single";
|
||||
string parameters = "single";
|
||||
string[] actual = BaseExecutionContext.SplitParameterString(parameters);
|
||||
|
||||
var p0 = Assert.Single(actual);
|
||||
Assert.Equal(expected, p0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SplitParameterString_SplitNoEquals_Multiple()
|
||||
{
|
||||
string[] expected = ["-flag1", "value1", "-flag2"];
|
||||
string parameters = "-flag1 value1 -flag2";
|
||||
string[] actual = BaseExecutionContext.SplitParameterString(parameters);
|
||||
Assert.True(expected.SequenceEqual(actual));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SplitParameterString_SplitEquals_Multiple()
|
||||
{
|
||||
string[] expected = ["-flag1=value1", "-flag2"];
|
||||
string parameters = "-flag1=value1 -flag2";
|
||||
string[] actual = BaseExecutionContext.SplitParameterString(parameters);
|
||||
Assert.True(expected.SequenceEqual(actual));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SplitParameterString_SplitNoEqualsQuotes_Multiple()
|
||||
{
|
||||
string[] expected = ["-flag1", "\"value1 value2\"", "-flag2"];
|
||||
string parameters = "-flag1 \"value1 value2\" -flag2";
|
||||
string[] actual = BaseExecutionContext.SplitParameterString(parameters);
|
||||
Assert.True(expected.SequenceEqual(actual));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SplitParameterString_SplitEqualsQuotes_Multiple()
|
||||
{
|
||||
string[] expected = ["-flag1=\"value1 value2\"", "-flag2"];
|
||||
string parameters = "-flag1=\"value1 value2\" -flag2";
|
||||
string[] actual = BaseExecutionContext.SplitParameterString(parameters);
|
||||
Assert.True(expected.SequenceEqual(actual));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DoesExist
|
||||
|
||||
[Fact]
|
||||
public void DoesExist_Empty_False()
|
||||
{
|
||||
string[] parts = [];
|
||||
int index = 0;
|
||||
bool actual = BaseExecutionContext.DoesExist(parts, index);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DoesExist_Negative_False()
|
||||
{
|
||||
string[] parts = ["item"];
|
||||
int index = -1;
|
||||
bool actual = BaseExecutionContext.DoesExist(parts, index);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DoesExist_Greater_False()
|
||||
{
|
||||
string[] parts = ["item"];
|
||||
int index = 1;
|
||||
bool actual = BaseExecutionContext.DoesExist(parts, index);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DoesExist_Valid_True()
|
||||
{
|
||||
string[] parts = ["item"];
|
||||
int index = 0;
|
||||
bool actual = BaseExecutionContext.DoesExist(parts, index);
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IsValidBool
|
||||
|
||||
[Theory]
|
||||
[InlineData("", false)]
|
||||
[InlineData("true", true)]
|
||||
[InlineData("True", true)]
|
||||
[InlineData("TRUE", true)]
|
||||
[InlineData("Yes", false)]
|
||||
[InlineData("false", true)]
|
||||
[InlineData("False", true)]
|
||||
[InlineData("FALSE", true)]
|
||||
[InlineData("No", false)]
|
||||
[InlineData("Invalid", false)]
|
||||
public void IsValidBoolTest(string parameter, bool expected)
|
||||
{
|
||||
bool actual = BaseExecutionContext.IsValidBool(parameter);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IsValidInt8
|
||||
|
||||
[Theory]
|
||||
[InlineData("", null, null, false)]
|
||||
[InlineData("", (sbyte)0, (sbyte)1, false)]
|
||||
[InlineData("", (sbyte)0, sbyte.MaxValue, false)]
|
||||
[InlineData("-2", null, null, true)]
|
||||
[InlineData("-2", (sbyte)0, (sbyte)1, false)]
|
||||
[InlineData("-2", (sbyte)0, sbyte.MaxValue, false)]
|
||||
[InlineData("0", null, null, true)]
|
||||
[InlineData("0", (sbyte)0, (sbyte)1, true)]
|
||||
[InlineData("0", (sbyte)0, sbyte.MaxValue, true)]
|
||||
[InlineData("2", null, null, true)]
|
||||
[InlineData("2", (sbyte)0, (sbyte)1, false)]
|
||||
[InlineData("2", (sbyte)0, sbyte.MaxValue, true)]
|
||||
[InlineData("Invalid", null, null, false)]
|
||||
[InlineData("Invalid", (sbyte)0, (sbyte)1, false)]
|
||||
[InlineData("Invalid", (sbyte)0, sbyte.MaxValue, false)]
|
||||
public void IsValidInt8Test(string parameter, sbyte? lowerBound, sbyte? upperBound, bool expected)
|
||||
{
|
||||
bool actual = BaseExecutionContext.IsValidInt8(parameter, lowerBound, upperBound);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IsValidInt16
|
||||
|
||||
[Theory]
|
||||
[InlineData("", null, null, false)]
|
||||
[InlineData("", (short)0, (short)1, false)]
|
||||
[InlineData("", (short)0, short.MaxValue, false)]
|
||||
[InlineData("-2", null, null, true)]
|
||||
[InlineData("-2", (short)0, (short)1, false)]
|
||||
[InlineData("-2", (short)0, short.MaxValue, false)]
|
||||
[InlineData("0", null, null, true)]
|
||||
[InlineData("0", (short)0, (short)1, true)]
|
||||
[InlineData("0", (short)0, short.MaxValue, true)]
|
||||
[InlineData("2", null, null, true)]
|
||||
[InlineData("2", (short)0, (short)1, false)]
|
||||
[InlineData("2", (short)0, short.MaxValue, true)]
|
||||
[InlineData("Invalid", null, null, false)]
|
||||
[InlineData("Invalid", (short)0, (short)1, false)]
|
||||
[InlineData("Invalid", (short)0, short.MaxValue, false)]
|
||||
public void IsValidInt16Test(string parameter, short? lowerBound, short? upperBound, bool expected)
|
||||
{
|
||||
bool actual = BaseExecutionContext.IsValidInt16(parameter, lowerBound, upperBound);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IsValidInt32
|
||||
|
||||
[Theory]
|
||||
[InlineData("", null, null, false)]
|
||||
[InlineData("", (int)0, (int)1, false)]
|
||||
[InlineData("", (int)0, int.MaxValue, false)]
|
||||
[InlineData("-2", null, null, true)]
|
||||
[InlineData("-2", (int)0, (int)1, false)]
|
||||
[InlineData("-2", (int)0, int.MaxValue, false)]
|
||||
[InlineData("0", null, null, true)]
|
||||
[InlineData("0", (int)0, (int)1, true)]
|
||||
[InlineData("0", (int)0, int.MaxValue, true)]
|
||||
[InlineData("2", null, null, true)]
|
||||
[InlineData("2", (int)0, (int)1, false)]
|
||||
[InlineData("2", (int)0, int.MaxValue, true)]
|
||||
[InlineData("Invalid", null, null, false)]
|
||||
[InlineData("Invalid", (int)0, (int)1, false)]
|
||||
[InlineData("Invalid", (int)0, int.MaxValue, false)]
|
||||
public void IsValidInt32Test(string parameter, int? lowerBound, int? upperBound, bool expected)
|
||||
{
|
||||
bool actual = BaseExecutionContext.IsValidInt32(parameter, lowerBound, upperBound);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IsValidInt64
|
||||
|
||||
[Theory]
|
||||
[InlineData("", null, null, false)]
|
||||
[InlineData("", (long)0, (long)1, false)]
|
||||
[InlineData("", (long)0, long.MaxValue, false)]
|
||||
[InlineData("-2", null, null, true)]
|
||||
[InlineData("-2", (long)0, (long)1, false)]
|
||||
[InlineData("-2", (long)0, long.MaxValue, false)]
|
||||
[InlineData("0", null, null, true)]
|
||||
[InlineData("0", (long)0, (long)1, true)]
|
||||
[InlineData("0", (long)0, long.MaxValue, true)]
|
||||
[InlineData("2", null, null, true)]
|
||||
[InlineData("2", (long)0, (long)1, false)]
|
||||
[InlineData("2", (long)0, long.MaxValue, true)]
|
||||
[InlineData("Invalid", null, null, false)]
|
||||
[InlineData("Invalid", (long)0, (long)1, false)]
|
||||
[InlineData("Invalid", (long)0, long.MaxValue, false)]
|
||||
public void IsValidInt64Test(string parameter, long? lowerBound, long? upperBound, bool expected)
|
||||
{
|
||||
bool actual = BaseExecutionContext.IsValidInt64(parameter, lowerBound, upperBound);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ExtractFactorFromValue
|
||||
|
||||
[Theory]
|
||||
[InlineData("1", "1", 1)]
|
||||
[InlineData("1c", "1", 1)]
|
||||
[InlineData("1w", "1", 2)]
|
||||
[InlineData("1d", "1", 4)]
|
||||
[InlineData("1q", "1", 8)]
|
||||
[InlineData("1k", "1", 1024)]
|
||||
[InlineData("1M", "1", 1024 * 1024)]
|
||||
[InlineData("1G", "1", 1024 * 1024 * 1024)]
|
||||
public void ExtractFactorFromValueTest(string value, string expected, long expectedFactor)
|
||||
{
|
||||
string actual = BaseExecutionContext.ExtractFactorFromValue(value, out long factor);
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.Equal(expectedFactor, factor);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region RemoveHexIdentifier
|
||||
|
||||
[Theory]
|
||||
[InlineData("", "")]
|
||||
[InlineData("0", "0")]
|
||||
[InlineData("00", "00")]
|
||||
[InlineData("0x", "0x")]
|
||||
[InlineData("0X", "0X")]
|
||||
[InlineData("A", "A")]
|
||||
[InlineData("A0", "A0")]
|
||||
[InlineData("Ax", "Ax")]
|
||||
[InlineData("AX", "AX")]
|
||||
[InlineData("012345", "012345")]
|
||||
[InlineData("0x12345", "12345")]
|
||||
[InlineData("0X12345", "12345")]
|
||||
public void RemoveHexIdentifierTest(string value, string expected)
|
||||
{
|
||||
string actual = BaseExecutionContext.RemoveHexIdentifier(value);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
465
MPF.ExecutionContexts.Test/DiscImageCreatorTests.cs
Normal file
465
MPF.ExecutionContexts.Test/DiscImageCreatorTests.cs
Normal file
@@ -0,0 +1,465 @@
|
||||
using System.Collections.Generic;
|
||||
using MPF.ExecutionContexts.DiscImageCreator;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.ExecutionContexts.Test
|
||||
{
|
||||
public class DiscImageCreatorTests
|
||||
{
|
||||
// TODO: Add Converters.ToRedumpSystem test
|
||||
// TODO: Add Converters.ToMediaType test
|
||||
|
||||
#region Converters.Extension
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null)]
|
||||
[InlineData(MediaType.CDROM, ".bin")]
|
||||
[InlineData(MediaType.GDROM, ".bin")]
|
||||
[InlineData(MediaType.Cartridge, ".bin")]
|
||||
[InlineData(MediaType.HardDisk, ".bin")]
|
||||
[InlineData(MediaType.CompactFlash, ".bin")]
|
||||
[InlineData(MediaType.MMC, ".bin")]
|
||||
[InlineData(MediaType.SDCard, ".bin")]
|
||||
[InlineData(MediaType.FlashDrive, ".bin")]
|
||||
[InlineData(MediaType.DVD, ".iso")]
|
||||
[InlineData(MediaType.HDDVD, ".iso")]
|
||||
[InlineData(MediaType.BluRay, ".iso")]
|
||||
[InlineData(MediaType.NintendoWiiOpticalDisc, ".iso")]
|
||||
[InlineData(MediaType.LaserDisc, ".raw")]
|
||||
[InlineData(MediaType.NintendoGameCubeGameDisc, ".raw")]
|
||||
[InlineData(MediaType.NintendoWiiUOpticalDisc, ".wud")]
|
||||
[InlineData(MediaType.FloppyDisk, ".img")]
|
||||
[InlineData(MediaType.Cassette, ".wav")]
|
||||
[InlineData(MediaType.ApertureCard, null)]
|
||||
public void ExtensionTest(MediaType? type, string? expected)
|
||||
{
|
||||
string? actual = Converters.Extension(type);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Default Values
|
||||
|
||||
private static readonly Dictionary<string, string?> AllOptions = new()
|
||||
{
|
||||
[SettingConstants.DVDRereadCount] = "1000",
|
||||
[SettingConstants.MultiSectorRead] = "true",
|
||||
[SettingConstants.MultiSectorReadValue] = "1000",
|
||||
[SettingConstants.ParanoidMode] = "true",
|
||||
[SettingConstants.QuietMode] = "true",
|
||||
[SettingConstants.RereadCount] = "1000",
|
||||
[SettingConstants.UseCMIFlag] = "true",
|
||||
};
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null, null, "filename.bin", null, null)]
|
||||
[InlineData(RedumpSystem.AppleMacintosh, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "cd /dev/sr0 \"filename.bin\" 2 /c2 1000 /q /mr 1000 /ns /sf /ss /s 2")]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "cd /dev/sr0 \"filename.bin\" 2 /c2 1000 /q /mr 1000 /ns /sf /ss /s 2")]
|
||||
[InlineData(RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "cd /dev/sr0 \"filename.bin\" 2 /aj /c2 1000 /q /mr 1000")]
|
||||
[InlineData(RedumpSystem.HasbroVideoNow, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "cd /dev/sr0 \"filename.bin\" 2 /a 0 /c2 1000 /q /mr 1000")]
|
||||
[InlineData(RedumpSystem.HasbroVideoNowColor, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "cd /dev/sr0 \"filename.bin\" 2 /a 0 /c2 1000 /q /mr 1000")]
|
||||
[InlineData(RedumpSystem.HasbroVideoNowJr, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "cd /dev/sr0 \"filename.bin\" 2 /a 0 /c2 1000 /q /mr 1000")]
|
||||
[InlineData(RedumpSystem.HasbroVideoNowXP, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "cd /dev/sr0 \"filename.bin\" 2 /a 0 /c2 1000 /q /mr 1000")]
|
||||
[InlineData(RedumpSystem.SonyPlayStation, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "cd /dev/sr0 \"filename.bin\" 2 /c2 1000 /q /mr 1000 /nl /am")]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, "/dev/sr0", "filename.bin", 2, "dvd /dev/sr0 \"filename.bin\" 2 /c /q /rr 1000 /sf")]
|
||||
[InlineData(RedumpSystem.MicrosoftXbox, MediaType.DVD, "/dev/sr0", "filename.bin", 2, "xbox /dev/sr0 \"filename.bin\" 2 /q /rr 1000")]
|
||||
[InlineData(RedumpSystem.MicrosoftXbox360, MediaType.DVD, "/dev/sr0", "filename.bin", 2, "xbox /dev/sr0 \"filename.bin\" 2 /q /rr 1000")]
|
||||
[InlineData(RedumpSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc, "/dev/sr0", "filename.bin", 2, "dvd /dev/sr0 \"filename.bin\" 2 /q /raw")]
|
||||
[InlineData(RedumpSystem.NintendoWii, MediaType.NintendoWiiOpticalDisc, "/dev/sr0", "filename.bin", 2, "dvd /dev/sr0 \"filename.bin\" 2 /q /raw")]
|
||||
[InlineData(RedumpSystem.SegaDreamcast, MediaType.GDROM, "/dev/sr0", "filename.bin", 2, "gd /dev/sr0 \"filename.bin\" 2 /c2 1000 /q")]
|
||||
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, "/dev/sr0", "filename.bin", 2, "dvd /dev/sr0 \"filename.bin\" 2 /c /q /rr 1000")]
|
||||
[InlineData(RedumpSystem.BDVideo, MediaType.BluRay, "/dev/sr0", "filename.bin", 2, "bd /dev/sr0 \"filename.bin\" 2 /q /rr 1000")]
|
||||
[InlineData(RedumpSystem.NintendoWiiU, MediaType.NintendoWiiUOpticalDisc, "/dev/sr0", "filename.bin", 2, "bd /dev/sr0 \"filename.bin\" 2 /q")]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.FloppyDisk, "/dev/sr0", "filename.bin", 2, "fd /dev/sr0 \"filename.bin\"")]
|
||||
public void DefaultValueTest(RedumpSystem? system,
|
||||
MediaType? type,
|
||||
string? drivePath,
|
||||
string filename,
|
||||
int? driveSpeed,
|
||||
string? expected)
|
||||
{
|
||||
var context = new ExecutionContext(system, type, drivePath, filename, driveSpeed, AllOptions);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Audio
|
||||
|
||||
[Theory]
|
||||
[InlineData("audio F filename.bin 0 1 2 /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /f 0 /np /nq /nr /r /am /sf 1 /ss /sk 1 0 /s 0 /t")]
|
||||
public void AudioTest(string parameters)
|
||||
{
|
||||
string? expected = "audio F \"filename.bin\" 0 1 2 /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /f 0 /np /nq /nr /r /am /sf 1 /ss /sk 1 0 /s 0 /t";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.True(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region BluRay
|
||||
|
||||
[Theory]
|
||||
[InlineData("bd F filename.bin 0 /d /q /rr 0 /f 0 /ra /avdp")]
|
||||
public void BluRayTest(string parameters)
|
||||
{
|
||||
string? expected = "bd F \"filename.bin\" 0 /d /q /rr 0 /f 0 /ra /avdp";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.True(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Close
|
||||
|
||||
[Theory]
|
||||
[InlineData("close f")]
|
||||
public void CloseTest(string parameters)
|
||||
{
|
||||
string? expected = "close f";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CompactDisc
|
||||
|
||||
[Theory]
|
||||
[InlineData("cd f filename.bin 0 /a 0 /p /aj /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /mscf /fdesc sync edc /f 0 /fulltoc /mr 0 /np /nq /nl /ns /nr /am /sf 1 /ss /74 /s 0 /toc /trp /vn 0 /vnc /vnx")]
|
||||
public void CompactDiscTest(string parameters)
|
||||
{
|
||||
string? expected = "cd f \"filename.bin\" 0 /a 0 /p /aj /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /mscf /fdesc sync edc /f 0 /fulltoc /mr 0 /np /nq /nl /ns /nr /am /sf 1 /ss /74 /s 0 /toc /trp /vn 0 /vnc /vnx";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.True(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Data
|
||||
|
||||
[Theory]
|
||||
[InlineData("data F filename.bin 0 1 2 /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /f 0 /np /nq /nr /r /am /sf 1 /ss /sk 1 0 /s 0 /t")]
|
||||
public void DataTest(string parameters)
|
||||
{
|
||||
string? expected = "data F \"filename.bin\" 0 1 2 /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /f 0 /np /nq /nr /r /am /sf 1 /ss /sk 1 0 /s 0 /t";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.True(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DigitalVideoDisc
|
||||
|
||||
[Theory]
|
||||
[InlineData("dvd F filename.bin 0 /c /d /q /rr 0 /fix 0 /ps 0 /ra 0 1 /raw /re /r 0 1 /sf 1 /sk 1 0 /avdp")]
|
||||
public void DigitalVideoDiscTest(string parameters)
|
||||
{
|
||||
string? expected = "dvd F \"filename.bin\" 0 /c /d /q /rr 0 /fix 0 /ps 0 /ra 0 1 /raw /re /r 0 1 /sf 1 /sk 1 0 /avdp";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.True(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Disk
|
||||
|
||||
[Theory]
|
||||
[InlineData("disk F filename.bin /d")]
|
||||
public void DiskTest(string parameters)
|
||||
{
|
||||
string? expected = "disk F \"filename.bin\" /d";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.True(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DriveSpeed
|
||||
|
||||
[Theory]
|
||||
[InlineData("ls f")]
|
||||
public void DriveSpeedTest(string parameters)
|
||||
{
|
||||
string? expected = "ls f";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Eject
|
||||
|
||||
[Theory]
|
||||
[InlineData("eject f")]
|
||||
public void EjectTest(string parameters)
|
||||
{
|
||||
string? expected = "eject f";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Floppy
|
||||
|
||||
[Theory]
|
||||
[InlineData("fd F filename.bin /d")]
|
||||
public void FloppyTest(string parameters)
|
||||
{
|
||||
string? expected = "fd F \"filename.bin\" /d";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.True(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GDROM
|
||||
|
||||
[Theory]
|
||||
[InlineData("gd f filename.bin 0 /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /f 0 /np /nq /nr /s 0")]
|
||||
public void GDROMTest(string parameters)
|
||||
{
|
||||
string? expected = "gd f \"filename.bin\" 0 /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /f 0 /np /nq /nr /s 0";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.True(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MDS
|
||||
|
||||
[Theory]
|
||||
[InlineData("mds filename.bin")]
|
||||
public void MDSTest(string parameters)
|
||||
{
|
||||
string? expected = "mds \"filename.bin\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Merge
|
||||
|
||||
[Theory]
|
||||
[InlineData("merge input1.bin input2.bin")]
|
||||
public void MergeTest(string parameters)
|
||||
{
|
||||
string? expected = "merge \"input1.bin\" \"input2.bin\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Reset
|
||||
|
||||
[Theory]
|
||||
[InlineData("reset f")]
|
||||
public void ResetTest(string parameters)
|
||||
{
|
||||
string? expected = "reset f";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SACD
|
||||
|
||||
[Theory]
|
||||
[InlineData("sacd f filename.bin 0 /d /q")]
|
||||
public void SACDTest(string parameters)
|
||||
{
|
||||
string? expected = "sacd f \"filename.bin\" 0 /d /q";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.True(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Start
|
||||
|
||||
[Theory]
|
||||
[InlineData("start f")]
|
||||
public void StartTest(string parameters)
|
||||
{
|
||||
string? expected = "start f";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stop
|
||||
|
||||
[Theory]
|
||||
[InlineData("stop f")]
|
||||
public void StopTest(string parameters)
|
||||
{
|
||||
string? expected = "stop f";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Sub
|
||||
|
||||
[Theory]
|
||||
[InlineData("sub filename.bin")]
|
||||
public void SubTest(string parameters)
|
||||
{
|
||||
string? expected = "sub \"filename.bin\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Swap
|
||||
|
||||
[Theory]
|
||||
[InlineData("swap f filename.bin 0 /a 0 /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /f 0 /np /nq /nl /ns /nr /am /sf 1 /ss /74 /s 0 /trp /vn 0 /vnc /vnx")]
|
||||
public void SwapTest(string parameters)
|
||||
{
|
||||
string? expected = "swap f \"filename.bin\" 0 /a 0 /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /f 0 /np /nq /nl /ns /nr /am /sf 1 /ss /74 /s 0 /trp /vn 0 /vnc /vnx";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.True(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tape
|
||||
|
||||
[Theory]
|
||||
[InlineData("tape filename.bin")]
|
||||
public void TapeTest(string parameters)
|
||||
{
|
||||
string? expected = "tape \"filename.bin\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.True(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Version
|
||||
|
||||
[Theory]
|
||||
[InlineData("/v")]
|
||||
public void VersionTest(string parameters)
|
||||
{
|
||||
string? expected = "/v";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region XBOX
|
||||
|
||||
[Theory]
|
||||
[InlineData("xbox f filename.bin 0 /d /q /rr 0 /f 0 /nss 0")]
|
||||
public void XBOXTest(string parameters)
|
||||
{
|
||||
string? expected = "xbox f \"filename.bin\" 0 /d /q /rr 0 /f 0 /nss 0";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.True(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region XBOXSwap
|
||||
|
||||
[Theory]
|
||||
[InlineData("xboxswap f filename.bin 0 /d /q /f 0 /nss 0")]
|
||||
public void XBOXSwapTest(string parameters)
|
||||
{
|
||||
string? expected = "xboxswap f \"filename.bin\" 0 /d /q /f 0 /nss 0";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.True(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region XGD2Swap
|
||||
|
||||
[Theory]
|
||||
[InlineData("xgd2swap f filename.bin 0 /d /q /f 0 /nss 0")]
|
||||
public void XGD2SwapTest(string parameters)
|
||||
{
|
||||
string? expected = "xgd2swap f \"filename.bin\" 0 /d /q /f 0 /nss 0";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.True(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region XGD3Swap
|
||||
|
||||
[Theory]
|
||||
[InlineData("xgd3swap f filename.bin 0 /d /q /f 0 /nss 0")]
|
||||
public void XGD3SwapTest(string parameters)
|
||||
{
|
||||
string? expected = "xgd3swap f \"filename.bin\" 0 /d /q /f 0 /nss 0";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.True(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
410
MPF.ExecutionContexts.Test/InputTests.cs
Normal file
410
MPF.ExecutionContexts.Test/InputTests.cs
Normal file
@@ -0,0 +1,410 @@
|
||||
using MPF.ExecutionContexts.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.ExecutionContexts.Test
|
||||
{
|
||||
public class InputTests
|
||||
{
|
||||
#region FlagInput
|
||||
|
||||
[Theory]
|
||||
// Invalid parts
|
||||
[InlineData("flag", new string[0], 0, false, false)]
|
||||
// Invalid index
|
||||
[InlineData("flag", new string[] { "flag" }, -1, false, false)]
|
||||
[InlineData("flag", new string[] { "flag" }, 1, false, false)]
|
||||
// Invalid name
|
||||
[InlineData("flag", new string[] { "" }, 0, false, false)]
|
||||
[InlineData("flag", new string[] { "flag2" }, 0, false, false)]
|
||||
// Valid
|
||||
[InlineData("flag", new string[] { "flag" }, 0, true, true)]
|
||||
public void FlagInputTest(string name, string[] parts, int index, bool success, bool expected)
|
||||
{
|
||||
var input = new FlagInput(name);
|
||||
bool actual = input.Process(parts, ref index);
|
||||
|
||||
Assert.Equal(success, actual);
|
||||
Assert.Equal(expected, input.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region BooleanInput
|
||||
|
||||
[Theory]
|
||||
// Invalid parts
|
||||
[InlineData("flag", true, new string[0], 0, false, null)]
|
||||
// Invalid index
|
||||
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
|
||||
// Invalid name
|
||||
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
|
||||
// Valid name, no following
|
||||
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag" }, 0, true, true)]
|
||||
// Valid name, invalid following
|
||||
[InlineData("flag", true, new string[] { "flag", "invalid" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag", "invalid" }, 0, true, true)]
|
||||
[InlineData("flag", true, new string[] { "flag=invalid" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag=invalid" }, 0, true, true)]
|
||||
// Valid name, valid following
|
||||
[InlineData("flag", true, new string[] { "flag", "true" }, 0, true, true)]
|
||||
[InlineData("flag", true, new string[] { "flag", "false" }, 0, true, false)]
|
||||
[InlineData("flag", true, new string[] { "flag=true" }, 0, true, true)]
|
||||
[InlineData("flag", true, new string[] { "flag=false" }, 0, true, false)]
|
||||
public void BooleanInputTest(string name, bool required, string[] parts, int index, bool success, bool? expected)
|
||||
{
|
||||
var input = new BooleanInput(name, required);
|
||||
bool actual = input.Process(parts, ref index);
|
||||
|
||||
Assert.Equal(success, actual);
|
||||
Assert.Equal(expected, input.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Int8Input
|
||||
|
||||
[Theory]
|
||||
// Invalid parts
|
||||
[InlineData("flag", true, new string[0], 0, false, null)]
|
||||
// Invalid index
|
||||
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
|
||||
// Invalid name
|
||||
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
|
||||
// Valid name, no following
|
||||
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag" }, 0, true, sbyte.MinValue)]
|
||||
// Valid name, invalid following
|
||||
[InlineData("flag", true, new string[] { "flag", "invalid" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag", "invalid" }, 0, true, sbyte.MinValue)]
|
||||
[InlineData("flag", true, new string[] { "flag=invalid" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag=invalid" }, 0, true, sbyte.MinValue)]
|
||||
// Valid name, valid following
|
||||
[InlineData("flag", true, new string[] { "flag", "1" }, 0, true, (sbyte)1)]
|
||||
[InlineData("flag", true, new string[] { "flag", "-1" }, 0, true, (sbyte)-1)]
|
||||
[InlineData("flag", true, new string[] { "flag=1" }, 0, true, (sbyte)1)]
|
||||
[InlineData("flag", true, new string[] { "flag=-1" }, 0, true, (sbyte)-1)]
|
||||
public void Int8InputTest(string name, bool required, string[] parts, int index, bool success, sbyte? expected)
|
||||
{
|
||||
var input = new Int8Input(name, required);
|
||||
bool actual = input.Process(parts, ref index);
|
||||
|
||||
Assert.Equal(success, actual);
|
||||
Assert.Equal(expected, input.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UInt8Input
|
||||
|
||||
[Theory]
|
||||
// Invalid parts
|
||||
[InlineData("flag", true, new string[0], 0, false, null)]
|
||||
// Invalid index
|
||||
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
|
||||
// Invalid name
|
||||
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
|
||||
// Valid name, no following
|
||||
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag" }, 0, true, byte.MinValue)]
|
||||
// Valid name, invalid following
|
||||
[InlineData("flag", true, new string[] { "flag", "invalid" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag", "invalid" }, 0, true, byte.MinValue)]
|
||||
[InlineData("flag", true, new string[] { "flag=invalid" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag=invalid" }, 0, true, byte.MinValue)]
|
||||
// Valid name, valid following
|
||||
[InlineData("flag", true, new string[] { "flag", "1" }, 0, true, (byte)1)]
|
||||
[InlineData("flag", true, new string[] { "flag=1" }, 0, true, (byte)1)]
|
||||
public void UInt8InputTest(string name, bool required, string[] parts, int index, bool success, byte? expected)
|
||||
{
|
||||
var input = new UInt8Input(name, required);
|
||||
bool actual = input.Process(parts, ref index);
|
||||
|
||||
Assert.Equal(success, actual);
|
||||
Assert.Equal(expected, input.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Int16Input
|
||||
|
||||
[Theory]
|
||||
// Invalid parts
|
||||
[InlineData("flag", true, new string[0], 0, false, null)]
|
||||
// Invalid index
|
||||
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
|
||||
// Invalid name
|
||||
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
|
||||
// Valid name, no following
|
||||
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag" }, 0, true, short.MinValue)]
|
||||
// Valid name, invalid following
|
||||
[InlineData("flag", true, new string[] { "flag", "invalid" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag", "invalid" }, 0, true, short.MinValue)]
|
||||
[InlineData("flag", true, new string[] { "flag=invalid" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag=invalid" }, 0, true, short.MinValue)]
|
||||
// Valid name, valid following
|
||||
[InlineData("flag", true, new string[] { "flag", "1" }, 0, true, (short)1)]
|
||||
[InlineData("flag", true, new string[] { "flag", "-1" }, 0, true, (short)-1)]
|
||||
[InlineData("flag", true, new string[] { "flag=1" }, 0, true, (short)1)]
|
||||
[InlineData("flag", true, new string[] { "flag=-1" }, 0, true, (short)-1)]
|
||||
public void Int16InputTest(string name, bool required, string[] parts, int index, bool success, short? expected)
|
||||
{
|
||||
var input = new Int16Input(name, required);
|
||||
bool actual = input.Process(parts, ref index);
|
||||
|
||||
Assert.Equal(success, actual);
|
||||
Assert.Equal(expected, input.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UInt16Input
|
||||
|
||||
[Theory]
|
||||
// Invalid parts
|
||||
[InlineData("flag", true, new string[0], 0, false, null)]
|
||||
// Invalid index
|
||||
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
|
||||
// Invalid name
|
||||
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
|
||||
// Valid name, no following
|
||||
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag" }, 0, true, ushort.MinValue)]
|
||||
// Valid name, invalid following
|
||||
[InlineData("flag", true, new string[] { "flag", "invalid" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag", "invalid" }, 0, true, ushort.MinValue)]
|
||||
[InlineData("flag", true, new string[] { "flag=invalid" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag=invalid" }, 0, true, ushort.MinValue)]
|
||||
// Valid name, valid following
|
||||
[InlineData("flag", true, new string[] { "flag", "1" }, 0, true, (ushort)1)]
|
||||
[InlineData("flag", true, new string[] { "flag=1" }, 0, true, (ushort)1)]
|
||||
public void UInt16InputTest(string name, bool required, string[] parts, int index, bool success, ushort? expected)
|
||||
{
|
||||
var input = new UInt16Input(name, required);
|
||||
bool actual = input.Process(parts, ref index);
|
||||
|
||||
Assert.Equal(success, actual);
|
||||
Assert.Equal(expected, input.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Int32Input
|
||||
|
||||
[Theory]
|
||||
// Invalid parts
|
||||
[InlineData("flag", true, new string[0], 0, false, null)]
|
||||
// Invalid index
|
||||
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
|
||||
// Invalid name
|
||||
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
|
||||
// Valid name, no following
|
||||
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag" }, 0, true, int.MinValue)]
|
||||
// Valid name, invalid following
|
||||
[InlineData("flag", true, new string[] { "flag", "invalid" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag", "invalid" }, 0, true, int.MinValue)]
|
||||
[InlineData("flag", true, new string[] { "flag=invalid" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag=invalid" }, 0, true, int.MinValue)]
|
||||
// Valid name, valid following
|
||||
[InlineData("flag", true, new string[] { "flag", "1" }, 0, true, (int)1)]
|
||||
[InlineData("flag", true, new string[] { "flag", "-1" }, 0, true, (int)-1)]
|
||||
[InlineData("flag", true, new string[] { "flag=1" }, 0, true, (int)1)]
|
||||
[InlineData("flag", true, new string[] { "flag=-1" }, 0, true, (int)-1)]
|
||||
public void Int32InputTest(string name, bool required, string[] parts, int index, bool success, int? expected)
|
||||
{
|
||||
var input = new Int32Input(name, required);
|
||||
bool actual = input.Process(parts, ref index);
|
||||
|
||||
Assert.Equal(success, actual);
|
||||
Assert.Equal(expected, input.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UInt32Input
|
||||
|
||||
[Theory]
|
||||
// Invalid parts
|
||||
[InlineData("flag", true, new string[0], 0, false, null)]
|
||||
// Invalid index
|
||||
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
|
||||
// Invalid name
|
||||
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
|
||||
// Valid name, no following
|
||||
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag" }, 0, true, uint.MinValue)]
|
||||
// Valid name, invalid following
|
||||
[InlineData("flag", true, new string[] { "flag", "invalid" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag", "invalid" }, 0, true, uint.MinValue)]
|
||||
[InlineData("flag", true, new string[] { "flag=invalid" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag=invalid" }, 0, true, uint.MinValue)]
|
||||
// Valid name, valid following
|
||||
[InlineData("flag", true, new string[] { "flag", "1" }, 0, true, (uint)1)]
|
||||
[InlineData("flag", true, new string[] { "flag=1" }, 0, true, (uint)1)]
|
||||
public void UInt32InputTest(string name, bool required, string[] parts, int index, bool success, uint? expected)
|
||||
{
|
||||
var input = new UInt32Input(name, required);
|
||||
bool actual = input.Process(parts, ref index);
|
||||
|
||||
Assert.Equal(success, actual);
|
||||
Assert.Equal(expected, input.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Int64Input
|
||||
|
||||
[Theory]
|
||||
// Invalid parts
|
||||
[InlineData("flag", true, new string[0], 0, false, null)]
|
||||
// Invalid index
|
||||
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
|
||||
// Invalid name
|
||||
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
|
||||
// Valid name, no following
|
||||
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag" }, 0, true, long.MinValue)]
|
||||
// Valid name, invalid following
|
||||
[InlineData("flag", true, new string[] { "flag", "invalid" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag", "invalid" }, 0, true, long.MinValue)]
|
||||
[InlineData("flag", true, new string[] { "flag=invalid" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag=invalid" }, 0, true, long.MinValue)]
|
||||
// Valid name, valid following
|
||||
[InlineData("flag", true, new string[] { "flag", "1" }, 0, true, (long)1)]
|
||||
[InlineData("flag", true, new string[] { "flag", "-1" }, 0, true, (long)-1)]
|
||||
[InlineData("flag", true, new string[] { "flag=1" }, 0, true, (long)1)]
|
||||
[InlineData("flag", true, new string[] { "flag=-1" }, 0, true, (long)-1)]
|
||||
public void Int64InputTest(string name, bool required, string[] parts, int index, bool success, long? expected)
|
||||
{
|
||||
var input = new Int64Input(name, required);
|
||||
bool actual = input.Process(parts, ref index);
|
||||
|
||||
Assert.Equal(success, actual);
|
||||
Assert.Equal(expected, input.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UInt64Input
|
||||
|
||||
[Theory]
|
||||
// Invalid parts
|
||||
[InlineData("flag", true, new string[0], 0, false, null)]
|
||||
// Invalid index
|
||||
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
|
||||
// Invalid name
|
||||
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
|
||||
// Valid name, no following
|
||||
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag" }, 0, true, ulong.MinValue)]
|
||||
// Valid name, invalid following
|
||||
[InlineData("flag", true, new string[] { "flag", "invalid" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag", "invalid" }, 0, true, ulong.MinValue)]
|
||||
[InlineData("flag", true, new string[] { "flag=invalid" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag=invalid" }, 0, true, ulong.MinValue)]
|
||||
// Valid name, valid following
|
||||
[InlineData("flag", true, new string[] { "flag", "1" }, 0, true, (ulong)1)]
|
||||
[InlineData("flag", true, new string[] { "flag=1" }, 0, true, (ulong)1)]
|
||||
public void UInt64InputTest(string name, bool required, string[] parts, int index, bool success, ulong? expected)
|
||||
{
|
||||
var input = new UInt64Input(name, required);
|
||||
bool actual = input.Process(parts, ref index);
|
||||
|
||||
Assert.Equal(success, actual);
|
||||
Assert.Equal(expected, input.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region StringInput
|
||||
|
||||
[Theory]
|
||||
// Invalid parts
|
||||
[InlineData("flag", true, new string[0], 0, false, null)]
|
||||
// Invalid index
|
||||
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
|
||||
// Invalid name
|
||||
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
|
||||
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
|
||||
// Valid name, no following
|
||||
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
|
||||
[InlineData("flag", false, new string[] { "flag" }, 0, true, "")]
|
||||
// Valid name, following
|
||||
[InlineData("flag", true, new string[] { "flag", "value" }, 0, true, "value")]
|
||||
[InlineData("flag", true, new string[] { "flag=value" }, 0, true, "value")]
|
||||
public void StringInputTest(string name, bool required, string[] parts, int index, bool success, string? expected)
|
||||
{
|
||||
var input = new StringInput(name, required);
|
||||
bool actual = input.Process(parts, ref index);
|
||||
|
||||
Assert.Equal(success, actual);
|
||||
Assert.Equal(expected, input.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ExtractFactorFromValue
|
||||
|
||||
[Theory]
|
||||
[InlineData("1", "1", 1)]
|
||||
[InlineData("1c", "1", 1)]
|
||||
[InlineData("1w", "1", 2)]
|
||||
[InlineData("1d", "1", 4)]
|
||||
[InlineData("1q", "1", 8)]
|
||||
[InlineData("1k", "1", 1024)]
|
||||
[InlineData("1M", "1", 1024 * 1024)]
|
||||
[InlineData("1G", "1", 1024 * 1024 * 1024)]
|
||||
public void ExtractFactorFromValueTest(string value, string expected, long expectedFactor)
|
||||
{
|
||||
string actual = Input.ExtractFactorFromValue(value, out long factor);
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.Equal(expectedFactor, factor);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region RemoveHexIdentifier
|
||||
|
||||
[Theory]
|
||||
[InlineData("", "")]
|
||||
[InlineData("0", "0")]
|
||||
[InlineData("00", "00")]
|
||||
[InlineData("0x", "0x")]
|
||||
[InlineData("0X", "0X")]
|
||||
[InlineData("A", "A")]
|
||||
[InlineData("A0", "A0")]
|
||||
[InlineData("Ax", "Ax")]
|
||||
[InlineData("AX", "AX")]
|
||||
[InlineData("012345", "012345")]
|
||||
[InlineData("0x12345", "12345")]
|
||||
[InlineData("0X12345", "12345")]
|
||||
public void RemoveHexIdentifierTest(string value, string expected)
|
||||
{
|
||||
string actual = Input.RemoveHexIdentifier(value);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
38
MPF.ExecutionContexts.Test/MPF.ExecutionContexts.Test.csproj
Normal file
38
MPF.ExecutionContexts.Test/MPF.ExecutionContexts.Test.csproj
Normal file
@@ -0,0 +1,38 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MPF.ExecutionContexts\MPF.ExecutionContexts.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeCoverage" Version="18.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="[1.9.0]" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
|
||||
<PackageReference Include="xunit.analyzers" Version="1.25.0" />
|
||||
<PackageReference Include="xunit.assert" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.core" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.extensibility.core" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.extensibility.execution" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.console" Version="2.9.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
378
MPF.ExecutionContexts.Test/RedumperTests.cs
Normal file
378
MPF.ExecutionContexts.Test/RedumperTests.cs
Normal file
@@ -0,0 +1,378 @@
|
||||
using System.Collections.Generic;
|
||||
using MPF.ExecutionContexts.Redumper;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.ExecutionContexts.Test
|
||||
{
|
||||
public class RedumperTests
|
||||
{
|
||||
#region Converters.Extension
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null)]
|
||||
[InlineData(MediaType.CDROM, ".bin")]
|
||||
[InlineData(MediaType.GDROM, ".bin")]
|
||||
[InlineData(MediaType.DVD, ".iso")]
|
||||
[InlineData(MediaType.HDDVD, ".iso")]
|
||||
[InlineData(MediaType.BluRay, ".iso")]
|
||||
[InlineData(MediaType.NintendoWiiOpticalDisc, ".iso")]
|
||||
[InlineData(MediaType.NintendoGameCubeGameDisc, ".raw")]
|
||||
[InlineData(MediaType.NintendoWiiUOpticalDisc, ".wud")]
|
||||
[InlineData(MediaType.ApertureCard, null)]
|
||||
public void ExtensionTest(MediaType? type, string? expected)
|
||||
{
|
||||
string? actual = Converters.Extension(type);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Default Values
|
||||
|
||||
private static readonly Dictionary<string, string?> AllOptions = new()
|
||||
{
|
||||
[SettingConstants.EnableVerbose] = "true",
|
||||
[SettingConstants.LeadinRetryCount] = "1000",
|
||||
[SettingConstants.ReadMethod] = "BE",
|
||||
[SettingConstants.RereadCount] = "1000",
|
||||
[SettingConstants.SectorOrder] = "DATA_C2_SUB",
|
||||
[SettingConstants.DriveType] = "GENERIC",
|
||||
};
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null, null, "filename.bin", null, "disc --verbose --skeleton --retries=1000 --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --skeleton --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --skeleton --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
|
||||
[InlineData(RedumpSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
|
||||
[InlineData(RedumpSystem.NintendoWii, MediaType.NintendoWiiOpticalDisc, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
|
||||
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
|
||||
[InlineData(RedumpSystem.BDVideo, MediaType.BluRay, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
|
||||
[InlineData(RedumpSystem.NintendoWiiU, MediaType.NintendoWiiUOpticalDisc, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
|
||||
public void DefaultValueTest(RedumpSystem? system,
|
||||
MediaType? type,
|
||||
string? drivePath,
|
||||
string filename,
|
||||
int? driveSpeed,
|
||||
string? expected)
|
||||
{
|
||||
var context = new ExecutionContext(system, type, drivePath, filename, driveSpeed, AllOptions);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Disc
|
||||
|
||||
[Theory]
|
||||
[InlineData("disc -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
[InlineData("disc --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
public void DiscTest(string parameters)
|
||||
{
|
||||
string? expected = "disc --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.True(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("disc --drive=dr --image-path=\"directory name\" --image-name=\"image name.bin\"")]
|
||||
public void SpacesTest(string parameters)
|
||||
{
|
||||
string? expected = "disc --drive=dr --image-path=\"directory name\" --image-name=\"image name.bin\"";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.True(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rings
|
||||
|
||||
[Theory]
|
||||
[InlineData("rings -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
[InlineData("rings --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
public void RingsTest(string parameters)
|
||||
{
|
||||
string? expected = "rings --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dump
|
||||
|
||||
[Theory]
|
||||
[InlineData("dump -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
[InlineData("dump --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
public void DumpTest(string parameters)
|
||||
{
|
||||
string? expected = "dump --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DumpExtra
|
||||
|
||||
[Theory]
|
||||
[InlineData("dump::extra -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
[InlineData("dump::extra --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
public void DumpExtraTest(string parameters)
|
||||
{
|
||||
string? expected = "dump::extra --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Refine
|
||||
|
||||
[Theory]
|
||||
[InlineData("refine -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
[InlineData("refine --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
public void RefineTest(string parameters)
|
||||
{
|
||||
string? expected = "refine --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Verify
|
||||
|
||||
[Theory]
|
||||
[InlineData("verify -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
[InlineData("verify --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
public void VerifyTest(string parameters)
|
||||
{
|
||||
string? expected = "verify --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DVDKey
|
||||
|
||||
[Theory]
|
||||
[InlineData("dvdkey -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
[InlineData("dvdkey --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
public void DVDKeyTest(string parameters)
|
||||
{
|
||||
string? expected = "dvdkey --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Eject
|
||||
|
||||
[Theory]
|
||||
[InlineData("eject -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
[InlineData("eject --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
public void EjectTest(string parameters)
|
||||
{
|
||||
string? expected = "eject --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DVDIsoKey
|
||||
|
||||
[Theory]
|
||||
[InlineData("dvdisokey -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
[InlineData("dvdisokey --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
public void DVDIsoKeyTest(string parameters)
|
||||
{
|
||||
string? expected = "dvdisokey --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protection
|
||||
|
||||
[Theory]
|
||||
[InlineData("protection -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
[InlineData("protection --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
|
||||
public void ProtectionTest(string parameters)
|
||||
{
|
||||
string? expected = "protection --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Split
|
||||
|
||||
[Theory]
|
||||
[InlineData("split -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
[InlineData("split --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
public void SplitTest(string parameters)
|
||||
{
|
||||
string? expected = "split --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Hash
|
||||
|
||||
[Theory]
|
||||
[InlineData("hash -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
[InlineData("hash --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
public void HashTest(string parameters)
|
||||
{
|
||||
string? expected = "hash --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Info
|
||||
|
||||
[Theory]
|
||||
[InlineData("info -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
[InlineData("info --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
public void InfoTest(string parameters)
|
||||
{
|
||||
string? expected = "info --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Skeleton
|
||||
|
||||
[Theory]
|
||||
[InlineData("skeleton -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
[InlineData("skeleton --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
public void SkeletonTest(string parameters)
|
||||
{
|
||||
string? expected = "skeleton --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Subchannel
|
||||
|
||||
[Theory]
|
||||
[InlineData("subchannel -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
[InlineData("subchannel --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
public void SubchannelTest(string parameters)
|
||||
{
|
||||
string? expected = "subchannel --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Debug
|
||||
|
||||
[Theory]
|
||||
[InlineData("debug -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
[InlineData("debug --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
public void DebugTest(string parameters)
|
||||
{
|
||||
string? expected = "debug --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.False(context.IsDumpingCommand());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region FixMSF
|
||||
|
||||
[Theory]
|
||||
[InlineData("fixmsf -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
[InlineData("fixmsf --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
public void FixMSFTest(string parameters)
|
||||
{
|
||||
string? expected = "fixmsf --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DebugFlip
|
||||
|
||||
[Theory]
|
||||
[InlineData("debug::flip -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
[InlineData("debug::flip --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
public void DebugFlipTest(string parameters)
|
||||
{
|
||||
string? expected = "debug::flip --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DriveTest
|
||||
|
||||
[Theory]
|
||||
[InlineData("drive::test -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
[InlineData("drive::test --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
|
||||
public void DriveTestTest(string parameters)
|
||||
{
|
||||
string? expected = "drive::test --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
|
||||
var context = new ExecutionContext(parameters);
|
||||
string? actual = context.GenerateParameters();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
89
MPF.ExecutionContexts/Aaru/CommandStrings.cs
Normal file
89
MPF.ExecutionContexts/Aaru/CommandStrings.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
namespace MPF.ExecutionContexts.Aaru
|
||||
{
|
||||
/// <summary>
|
||||
/// Top-level commands for Aaru
|
||||
/// </summary>
|
||||
public static class CommandStrings
|
||||
{
|
||||
public const string NONE = "";
|
||||
|
||||
#region Archive Family
|
||||
|
||||
public const string ArchivePrefixShort = "arc";
|
||||
public const string ArchivePrefixLong = "archive";
|
||||
public const string ArchiveInfo = "info";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Database Family
|
||||
|
||||
public const string DatabasePrefixShort = "db";
|
||||
public const string DatabasePrefixLong = "database";
|
||||
public const string DatabaseStats = "stats";
|
||||
public const string DatabaseUpdate = "update";
|
||||
|
||||
#endregion
|
||||
|
||||
#region 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";
|
||||
|
||||
#endregion
|
||||
|
||||
#region 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";
|
||||
|
||||
#endregion
|
||||
|
||||
#region 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";
|
||||
|
||||
#endregion
|
||||
|
||||
#region 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";
|
||||
|
||||
#endregion
|
||||
|
||||
#region 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";
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Modules.Aaru
|
||||
namespace MPF.ExecutionContexts.Aaru
|
||||
{
|
||||
public static class Converters
|
||||
{
|
||||
43
MPF.ExecutionContexts/Aaru/EncodingStrings.cs
Normal file
43
MPF.ExecutionContexts/Aaru/EncodingStrings.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
namespace MPF.ExecutionContexts.Aaru
|
||||
{
|
||||
/// <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";
|
||||
}
|
||||
}
|
||||
1029
MPF.ExecutionContexts/Aaru/ExecutionContext.cs
Normal file
1029
MPF.ExecutionContexts/Aaru/ExecutionContext.cs
Normal file
File diff suppressed because it is too large
Load Diff
173
MPF.ExecutionContexts/Aaru/FlagStrings.cs
Normal file
173
MPF.ExecutionContexts/Aaru/FlagStrings.cs
Normal file
@@ -0,0 +1,173 @@
|
||||
namespace MPF.ExecutionContexts.Aaru
|
||||
{
|
||||
/// <summary>
|
||||
/// Dumping flags for Aaru
|
||||
/// </summary>
|
||||
public static class FlagStrings
|
||||
{
|
||||
#region Precommand Flags
|
||||
|
||||
public const string DebugShort = "-d";
|
||||
public const string DebugLong = "--debug";
|
||||
public const string HelpShort = "-h";
|
||||
public const string HelpShortAlt = "-?";
|
||||
public const string HelpLong = "--help";
|
||||
public const string VerboseShort = "-v";
|
||||
public const string VerboseLong = "--verbose";
|
||||
public const string VersionLong = "--version";
|
||||
|
||||
#endregion
|
||||
|
||||
#region 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 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 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 VerifyDiscShort = "-w";
|
||||
public const string VerifyDiscLong = "--verify-disc";
|
||||
public const string VerifySectorsShort = "-s";
|
||||
public const string VerifySectorsLong = "--verify-sectors";
|
||||
public const string WholeDiscShort = "-w";
|
||||
public const string WholeDiscLong = "--whole-disc";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Int8 flags
|
||||
|
||||
public const string SpeedLong = "--speed";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Int16 flags
|
||||
|
||||
public const string RetryPassesShort = "-p";
|
||||
public const string RetryPassesLong = "--retry-passes";
|
||||
public const string WidthShort = "-w";
|
||||
public const string WidthLong = "--width";
|
||||
|
||||
#endregion
|
||||
|
||||
#region 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";
|
||||
|
||||
#endregion
|
||||
|
||||
#region 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";
|
||||
|
||||
#endregion
|
||||
|
||||
#region 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 FormatDumpShort = "-t";
|
||||
public const string FormatLong = "--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";
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
169
MPF.ExecutionContexts/Aaru/FormatStrings.cs
Normal file
169
MPF.ExecutionContexts/Aaru/FormatStrings.cs
Normal file
@@ -0,0 +1,169 @@
|
||||
namespace MPF.ExecutionContexts.Aaru
|
||||
{
|
||||
/// <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";
|
||||
}
|
||||
}
|
||||
27
MPF.ExecutionContexts/Aaru/NamespaceStrings.cs
Normal file
27
MPF.ExecutionContexts/Aaru/NamespaceStrings.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
namespace MPF.ExecutionContexts.Aaru
|
||||
{
|
||||
/// <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";
|
||||
}
|
||||
}
|
||||
43
MPF.ExecutionContexts/Aaru/OptionStrings.cs
Normal file
43
MPF.ExecutionContexts/Aaru/OptionStrings.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
namespace MPF.ExecutionContexts.Aaru
|
||||
{
|
||||
/// <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
|
||||
}
|
||||
}
|
||||
20
MPF.ExecutionContexts/Aaru/SettingConstants.cs
Normal file
20
MPF.ExecutionContexts/Aaru/SettingConstants.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace MPF.ExecutionContexts.Aaru
|
||||
{
|
||||
public static class SettingConstants
|
||||
{
|
||||
public const string EnableDebug = "AaruEnableDebug";
|
||||
public const bool EnableDebugDefault = false;
|
||||
|
||||
public const string EnableVerbose = "AaruEnableVerbose";
|
||||
public const bool EnableVerboseDefault = true;
|
||||
|
||||
public const string ForceDumping = "AaruForceDumping";
|
||||
public const bool ForceDumpingDefault = true;
|
||||
|
||||
public const string RereadCount = "AaruRereadCount";
|
||||
public const int RereadCountDefault = 5;
|
||||
|
||||
public const string StripPersonalData = "AaruStripPersonalData";
|
||||
public const bool StripPersonalDataDefault = false;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
123
MPF.ExecutionContexts/Data/BooleanInput.cs
Normal file
123
MPF.ExecutionContexts/Data/BooleanInput.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace MPF.ExecutionContexts.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a boolean flag with an optional trailing value
|
||||
/// </summary>
|
||||
public class BooleanInput : Input<bool?>
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
public BooleanInput(string name)
|
||||
: base(name) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public BooleanInput(string name, bool required)
|
||||
: base(name, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public BooleanInput(string shortName, string longName)
|
||||
: base(shortName, longName) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public BooleanInput(string shortName, string longName, bool required)
|
||||
: base(shortName, longName, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public BooleanInput(string[] names)
|
||||
: base(names) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public BooleanInput(string[] names, bool required)
|
||||
: base(names, required) { }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string Format(bool useEquals)
|
||||
{
|
||||
// Do not output if there is no value
|
||||
if (Value == null)
|
||||
return string.Empty;
|
||||
|
||||
// Build the output format
|
||||
var builder = new StringBuilder();
|
||||
|
||||
// Flag name
|
||||
builder.Append(Name);
|
||||
|
||||
// Separator
|
||||
if (useEquals)
|
||||
builder.Append('=');
|
||||
else
|
||||
builder.Append(' ');
|
||||
|
||||
// Value
|
||||
builder.Append(Value.ToString());
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Process(string[] parts, ref int index)
|
||||
{
|
||||
// Check the parts array
|
||||
if (index < 0 || index >= parts.Length)
|
||||
return false;
|
||||
|
||||
// Check for space-separated
|
||||
string part = parts[index];
|
||||
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
|
||||
{
|
||||
// Ensure the value exists
|
||||
if (index + 1 >= parts.Length)
|
||||
{
|
||||
Value = _required ? null : true;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// If the next value is valid
|
||||
if (!bool.TryParse(parts[index + 1], out bool value))
|
||||
{
|
||||
Value = _required ? null : true;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
index++;
|
||||
Value = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for equal separated
|
||||
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
|
||||
{
|
||||
// Split the string, using the first equal sign as the separator
|
||||
string[] tempSplit = part.Split('=');
|
||||
string key = tempSplit[0];
|
||||
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
|
||||
|
||||
// Ensure the value exists
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
Value = _required ? null : true;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// If the next value is valid
|
||||
if (!bool.TryParse(val, out bool value))
|
||||
{
|
||||
Value = _required ? null : true;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
Value = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
73
MPF.ExecutionContexts/Data/FlagInput.cs
Normal file
73
MPF.ExecutionContexts/Data/FlagInput.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace MPF.ExecutionContexts.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a boolean flag without a trailing value
|
||||
/// </summary>
|
||||
public class FlagInput : Input<bool>
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
public FlagInput(string name)
|
||||
: base(name) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public FlagInput(string name, bool required)
|
||||
: base(name, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public FlagInput(string shortName, string longName)
|
||||
: base(shortName, longName) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public FlagInput(string shortName, string longName, bool required)
|
||||
: base(shortName, longName, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public FlagInput(string[] names)
|
||||
: base(names) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public FlagInput(string[] names, bool required)
|
||||
: base(names, required) { }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string Format(bool useEquals)
|
||||
{
|
||||
// Do not output if there is no value
|
||||
if (Value == false)
|
||||
return string.Empty;
|
||||
|
||||
// Build the output format
|
||||
var builder = new StringBuilder();
|
||||
|
||||
// Flag name
|
||||
builder.Append(Name);
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Process(string[] parts, ref int index)
|
||||
{
|
||||
// Check the parts array
|
||||
if (index < 0 || index >= parts.Length)
|
||||
return false;
|
||||
|
||||
// Check the name
|
||||
string part = parts[index];
|
||||
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
|
||||
{
|
||||
Value = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
291
MPF.ExecutionContexts/Data/Input.cs
Normal file
291
MPF.ExecutionContexts/Data/Input.cs
Normal file
@@ -0,0 +1,291 @@
|
||||
namespace MPF.ExecutionContexts.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single input for an execution context
|
||||
/// </summary>
|
||||
public abstract class Input
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Primary name for the input
|
||||
/// </summary>
|
||||
public readonly string Name;
|
||||
|
||||
/// <summary>
|
||||
/// Alternative name for the input
|
||||
/// </summary>
|
||||
protected readonly string[] _altNames;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the value following is required or not
|
||||
/// </summary>
|
||||
protected readonly bool _required;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if a value has been set
|
||||
/// </summary>
|
||||
public abstract bool ValueSet { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <param name="name">Flag name / value</param>
|
||||
public Input(string name)
|
||||
{
|
||||
Name = name;
|
||||
_altNames = [];
|
||||
_required = true;
|
||||
}
|
||||
|
||||
/// <param name="name">Flag name / value</param>
|
||||
/// <param name="required">Indicates if a following value is required</param>
|
||||
public Input(string name, bool required)
|
||||
{
|
||||
Name = name;
|
||||
_altNames = [];
|
||||
_required = required;
|
||||
}
|
||||
|
||||
/// <param name="shortName">Flag name / value</param>
|
||||
/// <param name="longName">Verbose flag name / value</param>
|
||||
public Input(string shortName, string longName)
|
||||
{
|
||||
Name = longName;
|
||||
_altNames = [shortName];
|
||||
_required = true;
|
||||
}
|
||||
|
||||
/// <param name="shortName">Flag name / value</param>
|
||||
/// <param name="longName">Verbose flag name / value</param>
|
||||
/// <param name="required">Indicates if a following value is required</param>
|
||||
public Input(string shortName, string longName, bool required)
|
||||
{
|
||||
Name = longName;
|
||||
_altNames = [shortName];
|
||||
_required = required;
|
||||
}
|
||||
|
||||
/// <param name="names">Set of names to use</param>
|
||||
public Input(string[] names)
|
||||
{
|
||||
Name = names.Length > 0 ? names[0] : string.Empty;
|
||||
_altNames = names;
|
||||
_required = true;
|
||||
}
|
||||
|
||||
/// <param name="names">Set of names to use</param>
|
||||
/// <param name="required">Indicates if a following value is required</param>
|
||||
public Input(string[] names, bool required)
|
||||
{
|
||||
Name = names.Length > 0 ? names[0] : string.Empty;
|
||||
_altNames = names;
|
||||
_required = required;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Functionality
|
||||
|
||||
/// <summary>
|
||||
/// Clear any accumulated value
|
||||
/// </summary>
|
||||
public abstract void ClearValue();
|
||||
|
||||
/// <summary>
|
||||
/// Create a formatted representation of the input and possible value
|
||||
/// </summary>
|
||||
/// <param name="useEquals">Use an equal sign as a separator on output</param>
|
||||
public abstract string Format(bool useEquals);
|
||||
|
||||
/// <summary>
|
||||
/// Process the current index, if possible
|
||||
/// </summary>
|
||||
/// <param name="parts">Parts array to be referenced</param>
|
||||
/// <param name="index">Reference to the position in the parts</param>
|
||||
/// <returns>True if a value could be determined, false otherwise</returns>
|
||||
public abstract bool Process(string[] parts, ref int index);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Get the trimmed value and multiplication factor from a value
|
||||
/// </summary>
|
||||
/// <param name="value">String value to treat as suffixed number</param>
|
||||
/// <returns>Trimmed value and multiplication factor</returns>
|
||||
internal static string ExtractFactorFromValue(string value, out long factor)
|
||||
{
|
||||
value = value.Trim('"');
|
||||
factor = 1;
|
||||
|
||||
// Characters
|
||||
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
|
||||
if (value.EndsWith('c'))
|
||||
#else
|
||||
if (value.EndsWith("c", System.StringComparison.Ordinal))
|
||||
#endif
|
||||
{
|
||||
factor = 1;
|
||||
value = value.TrimEnd('c');
|
||||
}
|
||||
|
||||
// Words
|
||||
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
|
||||
else if (value.EndsWith('w'))
|
||||
#else
|
||||
else if (value.EndsWith("w", System.StringComparison.Ordinal))
|
||||
#endif
|
||||
{
|
||||
factor = 2;
|
||||
value = value.TrimEnd('w');
|
||||
}
|
||||
|
||||
// Double Words
|
||||
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
|
||||
else if (value.EndsWith('d'))
|
||||
#else
|
||||
else if (value.EndsWith("d", System.StringComparison.Ordinal))
|
||||
#endif
|
||||
{
|
||||
factor = 4;
|
||||
value = value.TrimEnd('d');
|
||||
}
|
||||
|
||||
// Quad Words
|
||||
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
|
||||
else if (value.EndsWith('q'))
|
||||
#else
|
||||
else if (value.EndsWith("q", System.StringComparison.Ordinal))
|
||||
#endif
|
||||
{
|
||||
factor = 8;
|
||||
value = value.TrimEnd('q');
|
||||
}
|
||||
|
||||
// Kilobytes
|
||||
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
|
||||
else if (value.EndsWith('k'))
|
||||
#else
|
||||
else if (value.EndsWith("k", System.StringComparison.Ordinal))
|
||||
#endif
|
||||
{
|
||||
factor = 1024;
|
||||
value = value.TrimEnd('k');
|
||||
}
|
||||
|
||||
// Megabytes
|
||||
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
|
||||
else if (value.EndsWith('M'))
|
||||
#else
|
||||
else if (value.EndsWith("M", System.StringComparison.Ordinal))
|
||||
#endif
|
||||
{
|
||||
factor = 1024 * 1024;
|
||||
value = value.TrimEnd('M');
|
||||
}
|
||||
|
||||
// Gigabytes
|
||||
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
|
||||
else if (value.EndsWith('G'))
|
||||
#else
|
||||
else if (value.EndsWith("G", System.StringComparison.Ordinal))
|
||||
#endif
|
||||
{
|
||||
factor = 1024 * 1024 * 1024;
|
||||
value = value.TrimEnd('G');
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a leading 0x if it exists, case insensitive
|
||||
/// </summary>
|
||||
/// <param name="value">String with removed leading 0x</param>
|
||||
/// <returns></returns>
|
||||
internal static string RemoveHexIdentifier(string value)
|
||||
{
|
||||
if (value.Length <= 2)
|
||||
return value;
|
||||
if (value[0] != '0')
|
||||
return value;
|
||||
if (value[1] != 'x' && value[1] != 'X')
|
||||
return value;
|
||||
|
||||
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
|
||||
return value[2..];
|
||||
#else
|
||||
return value.Substring(2);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a single input for an execution context
|
||||
/// </summary>
|
||||
public abstract class Input<T> : Input
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Represents the last value stored
|
||||
/// </summary>
|
||||
public T? Value { get; protected set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool ValueSet => Value != null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Input(string name)
|
||||
: base(name) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Input(string name, bool required)
|
||||
: base(name, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Input(string shortName, string longName)
|
||||
: base(shortName, longName) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Input(string shortName, string longName, bool required)
|
||||
: base(shortName, longName, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Input(string[] names)
|
||||
: base(names) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Input(string[] names, bool required)
|
||||
: base(names, required) { }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Functionality
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ClearValue()
|
||||
{
|
||||
Value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set a new value
|
||||
/// </summary>
|
||||
public void SetValue(T value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
189
MPF.ExecutionContexts/Data/Int16Input.cs
Normal file
189
MPF.ExecutionContexts/Data/Int16Input.cs
Normal file
@@ -0,0 +1,189 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace MPF.ExecutionContexts.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an Int16 flag with an optional trailing value
|
||||
/// </summary>
|
||||
public class Int16Input : Input<short?>
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a minimum value (inclusive) for the flag
|
||||
/// </summary>
|
||||
public short? MinValue { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a maximum value (inclusive) for the flag
|
||||
/// </summary>
|
||||
public short? MaxValue { get; set; } = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int16Input(string name)
|
||||
: base(name) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int16Input(string name, bool required)
|
||||
: base(name, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int16Input(string shortName, string longName)
|
||||
: base(shortName, longName) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int16Input(string shortName, string longName, bool required)
|
||||
: base(shortName, longName, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int16Input(string[] names)
|
||||
: base(names) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int16Input(string[] names, bool required)
|
||||
: base(names, required) { }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string Format(bool useEquals)
|
||||
{
|
||||
// Do not output if there is no value
|
||||
if (Value == null)
|
||||
return string.Empty;
|
||||
|
||||
// Build the output format
|
||||
var builder = new StringBuilder();
|
||||
|
||||
// Flag name
|
||||
builder.Append(Name);
|
||||
|
||||
// Only output separator and value if needed
|
||||
if (_required || (!_required && Value != short.MinValue))
|
||||
{
|
||||
// Separator
|
||||
if (useEquals)
|
||||
builder.Append('=');
|
||||
else
|
||||
builder.Append(' ');
|
||||
|
||||
// Value
|
||||
builder.Append(Value.ToString());
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Process(string[] parts, ref int index)
|
||||
{
|
||||
// Check the parts array
|
||||
if (index < 0 || index >= parts.Length)
|
||||
return false;
|
||||
|
||||
// Check for space-separated
|
||||
string part = parts[index];
|
||||
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
|
||||
{
|
||||
// Ensure the value exists
|
||||
if (index + 1 >= parts.Length)
|
||||
{
|
||||
Value = _required ? null : short.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// If the next value is valid
|
||||
if (ParseValue(parts[index + 1], out short? value) && value != null)
|
||||
{
|
||||
index++;
|
||||
Value = value;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return value based on required flag
|
||||
Value = _required ? null : short.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// Check for equal separated
|
||||
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
|
||||
{
|
||||
// Split the string, using the first equal sign as the separator
|
||||
string[] tempSplit = part.Split('=');
|
||||
string key = tempSplit[0];
|
||||
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
|
||||
|
||||
// Ensure the value exists
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
Value = _required ? null : short.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// If the next value is valid
|
||||
if (ParseValue(val, out short? value) && value != null)
|
||||
{
|
||||
Value = value;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return value based on required flag
|
||||
Value = _required ? null : short.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a value from a string
|
||||
/// </summary>
|
||||
private static bool ParseValue(string str, out short? output)
|
||||
{
|
||||
// If the next value is valid
|
||||
if (short.TryParse(str, out short value))
|
||||
{
|
||||
output = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to process as a formatted string
|
||||
string baseVal = ExtractFactorFromValue(str, out long factor);
|
||||
if (short.TryParse(baseVal, out value))
|
||||
{
|
||||
output = (short)(value * factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to process as a hex string
|
||||
string hexValue = RemoveHexIdentifier(baseVal);
|
||||
if (short.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
|
||||
{
|
||||
output = (short)(value * factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// The value could not be parsed
|
||||
output = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
161
MPF.ExecutionContexts/Data/Int32ArrInput.cs
Normal file
161
MPF.ExecutionContexts/Data/Int32ArrInput.cs
Normal file
@@ -0,0 +1,161 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace MPF.ExecutionContexts.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an Int32 flag with an optional trailing value
|
||||
/// </summary>
|
||||
public class Int32ArrInput : Input<int?[]>
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Internal array size
|
||||
/// </summary>
|
||||
public int Size { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a minimum value (inclusive) for the flag
|
||||
/// </summary>
|
||||
public int? MinValue { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a maximum value (inclusive) for the flag
|
||||
/// </summary>
|
||||
public int? MaxValue { get; set; } = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int32ArrInput(string name)
|
||||
: base(name) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int32ArrInput(string name, bool required)
|
||||
: base(name, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int32ArrInput(string shortName, string longName)
|
||||
: base(shortName, longName) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int32ArrInput(string shortName, string longName, bool required)
|
||||
: base(shortName, longName, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int32ArrInput(string[] names)
|
||||
: base(names) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int32ArrInput(string[] names, bool required)
|
||||
: base(names, required) { }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string Format(bool useEquals)
|
||||
{
|
||||
// Do not output if there is no value
|
||||
if (Value == null)
|
||||
return string.Empty;
|
||||
|
||||
// Build the output format
|
||||
var builder = new StringBuilder();
|
||||
|
||||
// Flag name
|
||||
builder.Append(Name);
|
||||
|
||||
// Only output separator and value if needed
|
||||
if (_required || (!_required && Value != null))
|
||||
{
|
||||
// Separator
|
||||
if (useEquals)
|
||||
builder.Append('=');
|
||||
else
|
||||
builder.Append(' ');
|
||||
|
||||
// Value
|
||||
int?[] nonNull = Array.FindAll(Value, i => i != null);
|
||||
string[] stringValues = Array.ConvertAll(nonNull, i => i.ToString() ?? string.Empty);
|
||||
builder.Append(string.Join(" ", stringValues));
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Process(string[] parts, ref int index)
|
||||
{
|
||||
// Check the parts array
|
||||
if (index < 0 || index >= parts.Length)
|
||||
return false;
|
||||
|
||||
// Check for space-separated
|
||||
string part = parts[index];
|
||||
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
|
||||
{
|
||||
Value = new int?[Size];
|
||||
for (int i = 0; i < Size; i++)
|
||||
{
|
||||
// Ensure the value exists
|
||||
if (index + 1 >= parts.Length)
|
||||
return !_required;
|
||||
|
||||
// If the next value is valid
|
||||
if (ParseValue(parts[index + 1], out int? value) && value != null)
|
||||
{
|
||||
index++;
|
||||
Value[i] = value;
|
||||
Value[i] = (MinValue != null && Value[i] < MinValue) ? MinValue : Value[i];
|
||||
Value[i] = (MaxValue != null && Value[i] > MaxValue) ? MaxValue : Value[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
// Return value based on required flag
|
||||
return !_required;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a value from a string
|
||||
/// </summary>
|
||||
private static bool ParseValue(string str, out int? output)
|
||||
{
|
||||
// If the next value is valid
|
||||
if (int.TryParse(str, out int value))
|
||||
{
|
||||
output = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to process as a formatted string
|
||||
string baseVal = ExtractFactorFromValue(str, out long factor);
|
||||
if (int.TryParse(baseVal, out value))
|
||||
{
|
||||
output = (int)(value * factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to process as a hex string
|
||||
string hexValue = RemoveHexIdentifier(baseVal);
|
||||
if (int.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
|
||||
{
|
||||
output = (int)(value * factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// The value could not be parsed
|
||||
output = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
189
MPF.ExecutionContexts/Data/Int32Input.cs
Normal file
189
MPF.ExecutionContexts/Data/Int32Input.cs
Normal file
@@ -0,0 +1,189 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace MPF.ExecutionContexts.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an Int32 flag with an optional trailing value
|
||||
/// </summary>
|
||||
public class Int32Input : Input<int?>
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a minimum value (inclusive) for the flag
|
||||
/// </summary>
|
||||
public int? MinValue { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a maximum value (inclusive) for the flag
|
||||
/// </summary>
|
||||
public int? MaxValue { get; set; } = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int32Input(string name)
|
||||
: base(name) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int32Input(string name, bool required)
|
||||
: base(name, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int32Input(string shortName, string longName)
|
||||
: base(shortName, longName) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int32Input(string shortName, string longName, bool required)
|
||||
: base(shortName, longName, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int32Input(string[] names)
|
||||
: base(names) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int32Input(string[] names, bool required)
|
||||
: base(names, required) { }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string Format(bool useEquals)
|
||||
{
|
||||
// Do not output if there is no value
|
||||
if (Value == null)
|
||||
return string.Empty;
|
||||
|
||||
// Build the output format
|
||||
var builder = new StringBuilder();
|
||||
|
||||
// Flag name
|
||||
builder.Append(Name);
|
||||
|
||||
// Only output separator and value if needed
|
||||
if (_required || (!_required && Value != int.MinValue))
|
||||
{
|
||||
// Separator
|
||||
if (useEquals)
|
||||
builder.Append('=');
|
||||
else
|
||||
builder.Append(' ');
|
||||
|
||||
// Value
|
||||
builder.Append(Value.ToString());
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Process(string[] parts, ref int index)
|
||||
{
|
||||
// Check the parts array
|
||||
if (index < 0 || index >= parts.Length)
|
||||
return false;
|
||||
|
||||
// Check for space-separated
|
||||
string part = parts[index];
|
||||
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
|
||||
{
|
||||
// Ensure the value exists
|
||||
if (index + 1 >= parts.Length)
|
||||
{
|
||||
Value = _required ? null : int.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// If the next value is valid
|
||||
if (ParseValue(parts[index + 1], out int? value) && value != null)
|
||||
{
|
||||
index++;
|
||||
Value = value;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return value based on required flag
|
||||
Value = _required ? null : int.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// Check for equal separated
|
||||
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
|
||||
{
|
||||
// Split the string, using the first equal sign as the separator
|
||||
string[] tempSplit = part.Split('=');
|
||||
string key = tempSplit[0];
|
||||
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
|
||||
|
||||
// Ensure the value exists
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
Value = _required ? null : int.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// If the next value is valid
|
||||
if (ParseValue(val, out int? value) && value != null)
|
||||
{
|
||||
Value = value;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return value based on required flag
|
||||
Value = _required ? null : int.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a value from a string
|
||||
/// </summary>
|
||||
private static bool ParseValue(string str, out int? output)
|
||||
{
|
||||
// If the next value is valid
|
||||
if (int.TryParse(str, out int value))
|
||||
{
|
||||
output = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to process as a formatted string
|
||||
string baseVal = ExtractFactorFromValue(str, out long factor);
|
||||
if (int.TryParse(baseVal, out value))
|
||||
{
|
||||
output = (int)(value * factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to process as a hex string
|
||||
string hexValue = RemoveHexIdentifier(baseVal);
|
||||
if (int.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
|
||||
{
|
||||
output = (int)(value * factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// The value could not be parsed
|
||||
output = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
189
MPF.ExecutionContexts/Data/Int64Input.cs
Normal file
189
MPF.ExecutionContexts/Data/Int64Input.cs
Normal file
@@ -0,0 +1,189 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace MPF.ExecutionContexts.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an Int64 flag with an optional trailing value
|
||||
/// </summary>
|
||||
public class Int64Input : Input<long?>
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a minimum value (inclusive) for the flag
|
||||
/// </summary>
|
||||
public long? MinValue { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a maximum value (inclusive) for the flag
|
||||
/// </summary>
|
||||
public long? MaxValue { get; set; } = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int64Input(string name)
|
||||
: base(name) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int64Input(string name, bool required)
|
||||
: base(name, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int64Input(string shortName, string longName)
|
||||
: base(shortName, longName) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int64Input(string shortName, string longName, bool required)
|
||||
: base(shortName, longName, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int64Input(string[] names)
|
||||
: base(names) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int64Input(string[] names, bool required)
|
||||
: base(names, required) { }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string Format(bool useEquals)
|
||||
{
|
||||
// Do not output if there is no value
|
||||
if (Value == null)
|
||||
return string.Empty;
|
||||
|
||||
// Build the output format
|
||||
var builder = new StringBuilder();
|
||||
|
||||
// Flag name
|
||||
builder.Append(Name);
|
||||
|
||||
// Only output separator and value if needed
|
||||
if (_required || (!_required && Value != long.MinValue))
|
||||
{
|
||||
// Separator
|
||||
if (useEquals)
|
||||
builder.Append('=');
|
||||
else
|
||||
builder.Append(' ');
|
||||
|
||||
// Value
|
||||
builder.Append(Value.ToString());
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Process(string[] parts, ref int index)
|
||||
{
|
||||
// Check the parts array
|
||||
if (index < 0 || index >= parts.Length)
|
||||
return false;
|
||||
|
||||
// Check for space-separated
|
||||
string part = parts[index];
|
||||
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
|
||||
{
|
||||
// Ensure the value exists
|
||||
if (index + 1 >= parts.Length)
|
||||
{
|
||||
Value = _required ? null : long.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// If the next value is valid
|
||||
if (ParseValue(parts[index + 1], out long? value) && value != null)
|
||||
{
|
||||
index++;
|
||||
Value = value;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return value based on required flag
|
||||
Value = _required ? null : long.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// Check for equal separated
|
||||
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
|
||||
{
|
||||
// Split the string, using the first equal sign as the separator
|
||||
string[] tempSplit = part.Split('=');
|
||||
string key = tempSplit[0];
|
||||
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
|
||||
|
||||
// Ensure the value exists
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
Value = _required ? null : long.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// If the next value is valid
|
||||
if (ParseValue(val, out long? value) && value != null)
|
||||
{
|
||||
Value = value;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return value based on required flag
|
||||
Value = _required ? null : long.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a value from a string
|
||||
/// </summary>
|
||||
private static bool ParseValue(string str, out long? output)
|
||||
{
|
||||
// If the next value is valid
|
||||
if (long.TryParse(str, out long value))
|
||||
{
|
||||
output = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to process as a formatted string
|
||||
string baseVal = ExtractFactorFromValue(str, out long factor);
|
||||
if (long.TryParse(baseVal, out value))
|
||||
{
|
||||
output = (long)(value * factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to process as a hex string
|
||||
string hexValue = RemoveHexIdentifier(baseVal);
|
||||
if (long.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
|
||||
{
|
||||
output = (long)(value * factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// The value could not be parsed
|
||||
output = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
189
MPF.ExecutionContexts/Data/Int8Input.cs
Normal file
189
MPF.ExecutionContexts/Data/Int8Input.cs
Normal file
@@ -0,0 +1,189 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace MPF.ExecutionContexts.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an Int8 flag with an optional trailing value
|
||||
/// </summary>
|
||||
public class Int8Input : Input<sbyte?>
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a minimum value (inclusive) for the flag
|
||||
/// </summary>
|
||||
public sbyte? MinValue { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a maximum value (inclusive) for the flag
|
||||
/// </summary>
|
||||
public sbyte? MaxValue { get; set; } = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int8Input(string name)
|
||||
: base(name) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int8Input(string name, bool required)
|
||||
: base(name, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int8Input(string shortName, string longName)
|
||||
: base(shortName, longName) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int8Input(string shortName, string longName, bool required)
|
||||
: base(shortName, longName, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int8Input(string[] names)
|
||||
: base(names) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Int8Input(string[] names, bool required)
|
||||
: base(names, required) { }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string Format(bool useEquals)
|
||||
{
|
||||
// Do not output if there is no value
|
||||
if (Value == null)
|
||||
return string.Empty;
|
||||
|
||||
// Build the output format
|
||||
var builder = new StringBuilder();
|
||||
|
||||
// Flag name
|
||||
builder.Append(Name);
|
||||
|
||||
// Only output separator and value if needed
|
||||
if (_required || (!_required && Value != sbyte.MinValue))
|
||||
{
|
||||
// Separator
|
||||
if (useEquals)
|
||||
builder.Append('=');
|
||||
else
|
||||
builder.Append(' ');
|
||||
|
||||
// Value
|
||||
builder.Append(Value.ToString());
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Process(string[] parts, ref int index)
|
||||
{
|
||||
// Check the parts array
|
||||
if (index < 0 || index >= parts.Length)
|
||||
return false;
|
||||
|
||||
// Check for space-separated
|
||||
string part = parts[index];
|
||||
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
|
||||
{
|
||||
// Ensure the value exists
|
||||
if (index + 1 >= parts.Length)
|
||||
{
|
||||
Value = _required ? null : sbyte.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// If the next value is valid
|
||||
if (ParseValue(parts[index + 1], out sbyte? value) && value != null)
|
||||
{
|
||||
index++;
|
||||
Value = value;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return value based on required flag
|
||||
Value = _required ? null : sbyte.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// Check for equal separated
|
||||
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
|
||||
{
|
||||
// Split the string, using the first equal sign as the separator
|
||||
string[] tempSplit = part.Split('=');
|
||||
string key = tempSplit[0];
|
||||
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
|
||||
|
||||
// Ensure the value exists
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
Value = _required ? null : sbyte.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// If the next value is valid
|
||||
if (ParseValue(val, out sbyte? value) && value != null)
|
||||
{
|
||||
Value = value;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return value based on required flag
|
||||
Value = _required ? null : sbyte.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a value from a string
|
||||
/// </summary>
|
||||
private static bool ParseValue(string str, out sbyte? output)
|
||||
{
|
||||
// If the next value is valid
|
||||
if (sbyte.TryParse(str, out sbyte value))
|
||||
{
|
||||
output = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to process as a formatted string
|
||||
string baseVal = ExtractFactorFromValue(str, out long factor);
|
||||
if (sbyte.TryParse(baseVal, out value))
|
||||
{
|
||||
output = (sbyte)(value * factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to process as a hex string
|
||||
string hexValue = RemoveHexIdentifier(baseVal);
|
||||
if (sbyte.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
|
||||
{
|
||||
output = (sbyte)(value * factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// The value could not be parsed
|
||||
output = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
126
MPF.ExecutionContexts/Data/StringInput.cs
Normal file
126
MPF.ExecutionContexts/Data/StringInput.cs
Normal file
@@ -0,0 +1,126 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace MPF.ExecutionContexts.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a string flag with an optional trailing value
|
||||
/// </summary>
|
||||
public class StringInput : Input<string>
|
||||
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether quotes are used in output or not
|
||||
/// </summary>
|
||||
public bool Quotes { get; set; } = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
public StringInput(string name)
|
||||
: base(name) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public StringInput(string name, bool required)
|
||||
: base(name, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public StringInput(string shortName, string longName)
|
||||
: base(shortName, longName) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public StringInput(string shortName, string longName, bool required)
|
||||
: base(shortName, longName, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public StringInput(string[] names)
|
||||
: base(names) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public StringInput(string[] names, bool required)
|
||||
: base(names, required) { }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string Format(bool useEquals)
|
||||
{
|
||||
// Do not output if there is no value
|
||||
if (Value == null)
|
||||
return string.Empty;
|
||||
|
||||
// Build the output format
|
||||
var builder = new StringBuilder();
|
||||
|
||||
// Flag name
|
||||
builder.Append(Name);
|
||||
|
||||
// Only output separator and value if needed
|
||||
if (_required || (!_required && Value != string.Empty))
|
||||
{
|
||||
// Separator
|
||||
if (useEquals)
|
||||
builder.Append('=');
|
||||
else
|
||||
builder.Append(' ');
|
||||
|
||||
// Value
|
||||
if (Quotes)
|
||||
builder.Append($"\"{Value}\"");
|
||||
else
|
||||
builder.Append(Value);
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Process(string[] parts, ref int index)
|
||||
{
|
||||
// Check the parts array
|
||||
if (index < 0 || index >= parts.Length)
|
||||
return false;
|
||||
|
||||
// Check for space-separated
|
||||
string part = parts[index];
|
||||
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
|
||||
{
|
||||
// Ensure the value exists
|
||||
if (index + 1 >= parts.Length)
|
||||
{
|
||||
Value = _required ? null : string.Empty;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
index++;
|
||||
Value = parts[index].Trim('"');
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for equal separated
|
||||
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
|
||||
{
|
||||
// Split the string, using the first equal sign as the separator
|
||||
string[] tempSplit = part.Split('=');
|
||||
string key = tempSplit[0];
|
||||
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
|
||||
|
||||
// Ensure the value exists
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
Value = _required ? null : string.Empty;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
Value = val.Trim('"');
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
189
MPF.ExecutionContexts/Data/UInt16Input.cs
Normal file
189
MPF.ExecutionContexts/Data/UInt16Input.cs
Normal file
@@ -0,0 +1,189 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace MPF.ExecutionContexts.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an UInt16 flag with an optional trailing value
|
||||
/// </summary>
|
||||
public class UInt16Input : Input<ushort?>
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a minimum value (inclusive) for the flag
|
||||
/// </summary>
|
||||
public ushort? MinValue { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a maximum value (inclusive) for the flag
|
||||
/// </summary>
|
||||
public ushort? MaxValue { get; set; } = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt16Input(string name)
|
||||
: base(name) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt16Input(string name, bool required)
|
||||
: base(name, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt16Input(string shortName, string longName)
|
||||
: base(shortName, longName) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt16Input(string shortName, string longName, bool required)
|
||||
: base(shortName, longName, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt16Input(string[] names)
|
||||
: base(names) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt16Input(string[] names, bool required)
|
||||
: base(names, required) { }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string Format(bool useEquals)
|
||||
{
|
||||
// Do not output if there is no value
|
||||
if (Value == null)
|
||||
return string.Empty;
|
||||
|
||||
// Build the output format
|
||||
var builder = new StringBuilder();
|
||||
|
||||
// Flag name
|
||||
builder.Append(Name);
|
||||
|
||||
// Only output separator and value if needed
|
||||
if (_required || (!_required && Value != ushort.MinValue))
|
||||
{
|
||||
// Separator
|
||||
if (useEquals)
|
||||
builder.Append('=');
|
||||
else
|
||||
builder.Append(' ');
|
||||
|
||||
// Value
|
||||
builder.Append(Value.ToString());
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Process(string[] parts, ref int index)
|
||||
{
|
||||
// Check the parts array
|
||||
if (index < 0 || index >= parts.Length)
|
||||
return false;
|
||||
|
||||
// Check for space-separated
|
||||
string part = parts[index];
|
||||
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
|
||||
{
|
||||
// Ensure the value exists
|
||||
if (index + 1 >= parts.Length)
|
||||
{
|
||||
Value = _required ? null : ushort.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// If the next value is valid
|
||||
if (ParseValue(parts[index + 1], out ushort? value) && value != null)
|
||||
{
|
||||
index++;
|
||||
Value = value;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return value based on required flag
|
||||
Value = _required ? null : ushort.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// Check for equal separated
|
||||
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
|
||||
{
|
||||
// Split the string, using the first equal sign as the separator
|
||||
string[] tempSplit = part.Split('=');
|
||||
string key = tempSplit[0];
|
||||
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
|
||||
|
||||
// Ensure the value exists
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
Value = _required ? null : ushort.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// If the next value is valid
|
||||
if (ParseValue(val, out ushort? value) && value != null)
|
||||
{
|
||||
Value = value;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return value based on required flag
|
||||
Value = _required ? null : ushort.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a value from a string
|
||||
/// </summary>
|
||||
private static bool ParseValue(string str, out ushort? output)
|
||||
{
|
||||
// If the next value is valid
|
||||
if (ushort.TryParse(str, out ushort value))
|
||||
{
|
||||
output = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to process as a formatted string
|
||||
string baseVal = ExtractFactorFromValue(str, out long factor);
|
||||
if (ushort.TryParse(baseVal, out value))
|
||||
{
|
||||
output = (ushort)(value * factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to process as a hex string
|
||||
string hexValue = RemoveHexIdentifier(baseVal);
|
||||
if (ushort.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
|
||||
{
|
||||
output = (ushort)(value * factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// The value could not be parsed
|
||||
output = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
189
MPF.ExecutionContexts/Data/UInt32Input.cs
Normal file
189
MPF.ExecutionContexts/Data/UInt32Input.cs
Normal file
@@ -0,0 +1,189 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace MPF.ExecutionContexts.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an UInt32 flag with an optional trailing value
|
||||
/// </summary>
|
||||
public class UInt32Input : Input<uint?>
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a minimum value (inclusive) for the flag
|
||||
/// </summary>
|
||||
public uint? MinValue { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a maximum value (inclusive) for the flag
|
||||
/// </summary>
|
||||
public uint? MaxValue { get; set; } = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt32Input(string name)
|
||||
: base(name) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt32Input(string name, bool required)
|
||||
: base(name, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt32Input(string shortName, string longName)
|
||||
: base(shortName, longName) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt32Input(string shortName, string longName, bool required)
|
||||
: base(shortName, longName, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt32Input(string[] names)
|
||||
: base(names) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt32Input(string[] names, bool required)
|
||||
: base(names, required) { }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string Format(bool useEquals)
|
||||
{
|
||||
// Do not output if there is no value
|
||||
if (Value == null)
|
||||
return string.Empty;
|
||||
|
||||
// Build the output format
|
||||
var builder = new StringBuilder();
|
||||
|
||||
// Flag name
|
||||
builder.Append(Name);
|
||||
|
||||
// Only output separator and value if needed
|
||||
if (_required || (!_required && Value != uint.MinValue))
|
||||
{
|
||||
// Separator
|
||||
if (useEquals)
|
||||
builder.Append('=');
|
||||
else
|
||||
builder.Append(' ');
|
||||
|
||||
// Value
|
||||
builder.Append(Value.ToString());
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Process(string[] parts, ref int index)
|
||||
{
|
||||
// Check the parts array
|
||||
if (index < 0 || index >= parts.Length)
|
||||
return false;
|
||||
|
||||
// Check for space-separated
|
||||
string part = parts[index];
|
||||
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
|
||||
{
|
||||
// Ensure the value exists
|
||||
if (index + 1 >= parts.Length)
|
||||
{
|
||||
Value = _required ? null : uint.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// If the next value is valid
|
||||
if (ParseValue(parts[index + 1], out uint? value) && value != null)
|
||||
{
|
||||
index++;
|
||||
Value = value;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return value based on required flag
|
||||
Value = _required ? null : uint.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// Check for equal separated
|
||||
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
|
||||
{
|
||||
// Split the string, using the first equal sign as the separator
|
||||
string[] tempSplit = part.Split('=');
|
||||
string key = tempSplit[0];
|
||||
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
|
||||
|
||||
// Ensure the value exists
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
Value = _required ? null : uint.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// If the next value is valid
|
||||
if (ParseValue(val, out uint? value) && value != null)
|
||||
{
|
||||
Value = value;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return value based on required flag
|
||||
Value = _required ? null : uint.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a value from a string
|
||||
/// </summary>
|
||||
private static bool ParseValue(string str, out uint? output)
|
||||
{
|
||||
// If the next value is valid
|
||||
if (uint.TryParse(str, out uint value))
|
||||
{
|
||||
output = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to process as a formatted string
|
||||
string baseVal = ExtractFactorFromValue(str, out long factor);
|
||||
if (uint.TryParse(baseVal, out value))
|
||||
{
|
||||
output = (uint)(value * factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to process as a hex string
|
||||
string hexValue = RemoveHexIdentifier(baseVal);
|
||||
if (uint.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
|
||||
{
|
||||
output = (uint)(value * factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// The value could not be parsed
|
||||
output = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
189
MPF.ExecutionContexts/Data/UInt64Input.cs
Normal file
189
MPF.ExecutionContexts/Data/UInt64Input.cs
Normal file
@@ -0,0 +1,189 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace MPF.ExecutionContexts.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an UInt64 flag with an optional trailing value
|
||||
/// </summary>
|
||||
public class UInt64Input : Input<ulong?>
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a minimum value (inclusive) for the flag
|
||||
/// </summary>
|
||||
public ulong? MinValue { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a maximum value (inclusive) for the flag
|
||||
/// </summary>
|
||||
public ulong? MaxValue { get; set; } = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt64Input(string name)
|
||||
: base(name) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt64Input(string name, bool required)
|
||||
: base(name, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt64Input(string shortName, string longName)
|
||||
: base(shortName, longName) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt64Input(string shortName, string longName, bool required)
|
||||
: base(shortName, longName, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt64Input(string[] names)
|
||||
: base(names) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt64Input(string[] names, bool required)
|
||||
: base(names, required) { }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string Format(bool useEquals)
|
||||
{
|
||||
// Do not output if there is no value
|
||||
if (Value == null)
|
||||
return string.Empty;
|
||||
|
||||
// Build the output format
|
||||
var builder = new StringBuilder();
|
||||
|
||||
// Flag name
|
||||
builder.Append(Name);
|
||||
|
||||
// Only output separator and value if needed
|
||||
if (_required || (!_required && Value != ulong.MinValue))
|
||||
{
|
||||
// Separator
|
||||
if (useEquals)
|
||||
builder.Append('=');
|
||||
else
|
||||
builder.Append(' ');
|
||||
|
||||
// Value
|
||||
builder.Append(Value.ToString());
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Process(string[] parts, ref int index)
|
||||
{
|
||||
// Check the parts array
|
||||
if (index < 0 || index >= parts.Length)
|
||||
return false;
|
||||
|
||||
// Check for space-separated
|
||||
string part = parts[index];
|
||||
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
|
||||
{
|
||||
// Ensure the value exists
|
||||
if (index + 1 >= parts.Length)
|
||||
{
|
||||
Value = _required ? null : ulong.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// If the next value is valid
|
||||
if (ParseValue(parts[index + 1], out ulong? value) && value != null)
|
||||
{
|
||||
index++;
|
||||
Value = value;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return value based on required flag
|
||||
Value = _required ? null : ulong.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// Check for equal separated
|
||||
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
|
||||
{
|
||||
// Split the string, using the first equal sign as the separator
|
||||
string[] tempSplit = part.Split('=');
|
||||
string key = tempSplit[0];
|
||||
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
|
||||
|
||||
// Ensure the value exists
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
Value = _required ? null : ulong.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// If the next value is valid
|
||||
if (ParseValue(val, out ulong? value) && value != null)
|
||||
{
|
||||
Value = value;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return value based on required flag
|
||||
Value = _required ? null : ulong.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a value from a string
|
||||
/// </summary>
|
||||
private static bool ParseValue(string str, out ulong? output)
|
||||
{
|
||||
// If the next value is valid
|
||||
if (ulong.TryParse(str, out ulong value))
|
||||
{
|
||||
output = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to process as a formatted string
|
||||
string baseVal = ExtractFactorFromValue(str, out long factor);
|
||||
if (ulong.TryParse(baseVal, out value))
|
||||
{
|
||||
output = (ulong)(value * (ulong)factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to process as a hex string
|
||||
string hexValue = RemoveHexIdentifier(baseVal);
|
||||
if (ulong.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
|
||||
{
|
||||
output = (ulong)(value * (ulong)factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// The value could not be parsed
|
||||
output = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
189
MPF.ExecutionContexts/Data/UInt8Input.cs
Normal file
189
MPF.ExecutionContexts/Data/UInt8Input.cs
Normal file
@@ -0,0 +1,189 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace MPF.ExecutionContexts.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an UInt8 flag with an optional trailing value
|
||||
/// </summary>
|
||||
public class UInt8Input : Input<byte?>
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a minimum value (inclusive) for the flag
|
||||
/// </summary>
|
||||
public byte? MinValue { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a maximum value (inclusive) for the flag
|
||||
/// </summary>
|
||||
public byte? MaxValue { get; set; } = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt8Input(string name)
|
||||
: base(name) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt8Input(string name, bool required)
|
||||
: base(name, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt8Input(string shortName, string longName)
|
||||
: base(shortName, longName) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt8Input(string shortName, string longName, bool required)
|
||||
: base(shortName, longName, required) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt8Input(string[] names)
|
||||
: base(names) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UInt8Input(string[] names, bool required)
|
||||
: base(names, required) { }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string Format(bool useEquals)
|
||||
{
|
||||
// Do not output if there is no value
|
||||
if (Value == null)
|
||||
return string.Empty;
|
||||
|
||||
// Build the output format
|
||||
var builder = new StringBuilder();
|
||||
|
||||
// Flag name
|
||||
builder.Append(Name);
|
||||
|
||||
// Only output separator and value if needed
|
||||
if (_required || (!_required && Value != byte.MinValue))
|
||||
{
|
||||
// Separator
|
||||
if (useEquals)
|
||||
builder.Append('=');
|
||||
else
|
||||
builder.Append(' ');
|
||||
|
||||
// Value
|
||||
builder.Append(Value.ToString());
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Process(string[] parts, ref int index)
|
||||
{
|
||||
// Check the parts array
|
||||
if (index < 0 || index >= parts.Length)
|
||||
return false;
|
||||
|
||||
// Check for space-separated
|
||||
string part = parts[index];
|
||||
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
|
||||
{
|
||||
// Ensure the value exists
|
||||
if (index + 1 >= parts.Length)
|
||||
{
|
||||
Value = _required ? null : byte.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// If the next value is valid
|
||||
if (ParseValue(parts[index + 1], out byte? value) && value != null)
|
||||
{
|
||||
index++;
|
||||
Value = value;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return value based on required flag
|
||||
Value = _required ? null : byte.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// Check for equal separated
|
||||
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
|
||||
{
|
||||
// Split the string, using the first equal sign as the separator
|
||||
string[] tempSplit = part.Split('=');
|
||||
string key = tempSplit[0];
|
||||
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
|
||||
|
||||
// Ensure the value exists
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
Value = _required ? null : byte.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
// If the next value is valid
|
||||
if (ParseValue(val, out byte? value) && value != null)
|
||||
{
|
||||
Value = value;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return value based on required flag
|
||||
Value = _required ? null : byte.MinValue;
|
||||
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
|
||||
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
|
||||
return !_required;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a value from a string
|
||||
/// </summary>
|
||||
private static bool ParseValue(string str, out byte? output)
|
||||
{
|
||||
// If the next value is valid
|
||||
if (byte.TryParse(str, out byte value))
|
||||
{
|
||||
output = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to process as a formatted string
|
||||
string baseVal = ExtractFactorFromValue(str, out long factor);
|
||||
if (byte.TryParse(baseVal, out value))
|
||||
{
|
||||
output = (byte)(value * factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to process as a hex string
|
||||
string hexValue = RemoveHexIdentifier(baseVal);
|
||||
if (byte.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
|
||||
{
|
||||
output = (byte)(value * factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// The value could not be parsed
|
||||
output = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
35
MPF.ExecutionContexts/DiscImageCreator/CommandStrings.cs
Normal file
35
MPF.ExecutionContexts/DiscImageCreator/CommandStrings.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
namespace MPF.ExecutionContexts.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";
|
||||
}
|
||||
}
|
||||
100
MPF.ExecutionContexts/DiscImageCreator/Converters.cs
Normal file
100
MPF.ExecutionContexts/DiscImageCreator/Converters.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.ExecutionContexts.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
|
||||
}
|
||||
}
|
||||
1911
MPF.ExecutionContexts/DiscImageCreator/ExecutionContext.cs
Normal file
1911
MPF.ExecutionContexts/DiscImageCreator/ExecutionContext.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,38 +1,5 @@
|
||||
namespace MPF.Core.Modules.DiscImageCreator
|
||||
namespace MPF.ExecutionContexts.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>
|
||||
@@ -43,6 +10,7 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
public const string AtariJaguar = "/aj";
|
||||
public const string BEOpcode = "/be";
|
||||
public const string C2Opcode = "/c2";
|
||||
public const string C2OpcodeNew = "/c2new";
|
||||
public const string CopyrightManagementInformation = "/c";
|
||||
public const string D8Opcode = "/d8";
|
||||
public const string DatExpand = "/d";
|
||||
@@ -50,7 +18,9 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
public const string DVDReread = "/rr";
|
||||
public const string ExtractMicroSoftCabFile = "/mscf";
|
||||
public const string Fix = "/fix";
|
||||
public const string ForceDescrambleSector = "/fdesc";
|
||||
public const string ForceUnitAccess = "/f";
|
||||
public const string FullToc = "/fulltoc";
|
||||
public const string MultiSectorRead = "/mr";
|
||||
public const string NoFixSubP = "/np";
|
||||
public const string NoFixSubQ = "/nq";
|
||||
@@ -69,9 +39,12 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
public const string SeventyFour = "/74";
|
||||
public const string SkipSector = "/sk";
|
||||
public const string SubchannelReadLevel = "/s";
|
||||
public const string Tages = "/t";
|
||||
public const string Toc = "/toc";
|
||||
public const string TryReadingPregap = "/trp";
|
||||
public const string UseAnchorVolumeDescriptorPointer = "/avdp";
|
||||
public const string VideoNow = "/vn";
|
||||
public const string VideoNowColor = "/vnc";
|
||||
public const string VideoNowXP = "/vnx";
|
||||
}
|
||||
}
|
||||
}
|
||||
26
MPF.ExecutionContexts/DiscImageCreator/SettingConstants.cs
Normal file
26
MPF.ExecutionContexts/DiscImageCreator/SettingConstants.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
namespace MPF.ExecutionContexts.DiscImageCreator
|
||||
{
|
||||
public static class SettingConstants
|
||||
{
|
||||
public const string DVDRereadCount = "DICDVDRereadCount";
|
||||
public const int DVDRereadCountDefault = 10;
|
||||
|
||||
public const string MultiSectorRead = "DICMultiSectorRead";
|
||||
public const bool MultiSectorReadDefault = false;
|
||||
|
||||
public const string MultiSectorReadValue = "DICMultiSectorReadValue";
|
||||
public const int MultiSectorReadValueDefault = 0;
|
||||
|
||||
public const string ParanoidMode = "DICParanoidMode";
|
||||
public const bool ParanoidModeDefault = false;
|
||||
|
||||
public const string QuietMode = "DICQuietMode";
|
||||
public const bool QuietModeDefault = false;
|
||||
|
||||
public const string RereadCount = "DICRereadCount";
|
||||
public const int RereadCountDefault = 20;
|
||||
|
||||
public const string UseCMIFlag = "DICUseCMIFlag";
|
||||
public const bool UseCMIFlagDefault = false;
|
||||
}
|
||||
}
|
||||
38
MPF.ExecutionContexts/MPF.ExecutionContexts.csproj
Normal file
38
MPF.ExecutionContexts/MPF.ExecutionContexts.csproj
Normal file
@@ -0,0 +1,38 @@
|
||||
<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;net9.0;net10.0</TargetFrameworks>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<VersionPrefix>3.6.0</VersionPrefix>
|
||||
<WarningsNotAsErrors>NU5104</WarningsNotAsErrors>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
<Description>Common code for all MPF execution contexts</Description>
|
||||
<Copyright>Copyright (c) Matt Nadareski 2019-2025</Copyright>
|
||||
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="README.md" Pack="true" PackagePath="" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="MPF.ExecutionContexts.Test" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="[1.9.0]" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
13
MPF.ExecutionContexts/README.md
Normal file
13
MPF.ExecutionContexts/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# MPF.ExecutionContexts
|
||||
|
||||
This library represents the logic needed to invoke 3 different dumping programs:
|
||||
|
||||
- [Aaru](github.com/aaru-dps/Aaru)
|
||||
- [DiscImageCreator](github.com/saramibreak/DiscImageCreator)
|
||||
- [Redumper](https://github.com/superg/redumper)
|
||||
|
||||
These execution wrappers allow for generating valid parameters for each of the programs as well as provide some helpers that make it easier to determine what those parameters are.
|
||||
|
||||
External options are defined in order to help create reasonable default parameter sets for different combinations of media type and system.
|
||||
|
||||
Paths to the programs need to be provided if they are expected to be invoked as a part of another program. The expected versions of these programs can be found in either the changelog or the publish script in the parent project.
|
||||
32
MPF.ExecutionContexts/Redumper/CommandStrings.cs
Normal file
32
MPF.ExecutionContexts/Redumper/CommandStrings.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
namespace MPF.ExecutionContexts.Redumper
|
||||
{
|
||||
/// <summary>
|
||||
/// Top-level commands for Redumper
|
||||
/// </summary>
|
||||
public static class CommandStrings
|
||||
{
|
||||
public const string NONE = "";
|
||||
public const string Disc = "disc";
|
||||
public const string Rings = "rings";
|
||||
public const string Dump = "dump";
|
||||
public const string DumpExtra = "dump::extra";
|
||||
public const string Refine = "refine";
|
||||
public const string Verify = "verify";
|
||||
public const string DVDKey = "dvdkey";
|
||||
public const string Eject = "eject";
|
||||
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";
|
||||
public const string FlashMT1339 = "flash::mt1339";
|
||||
public const string FlashSD616 = "flash::sd616";
|
||||
public const string FlashPlextor = "flash::plextor";
|
||||
public const string Subchannel = "subchannel";
|
||||
public const string Debug = "debug";
|
||||
public const string FixMSF = "fixmsf";
|
||||
public const string DebugFlip = "debug::flip";
|
||||
public const string DriveTest = "drive::test";
|
||||
}
|
||||
}
|
||||
32
MPF.ExecutionContexts/Redumper/Converters.cs
Normal file
32
MPF.ExecutionContexts/Redumper/Converters.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.ExecutionContexts.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
|
||||
or MediaType.GDROM => ".bin",
|
||||
MediaType.DVD
|
||||
or MediaType.HDDVD
|
||||
or MediaType.BluRay
|
||||
or MediaType.NintendoWiiOpticalDisc => ".iso",
|
||||
MediaType.NintendoGameCubeGameDisc => ".raw",
|
||||
MediaType.NintendoWiiUOpticalDisc => ".wud",
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
42
MPF.ExecutionContexts/Redumper/Enumerations.cs
Normal file
42
MPF.ExecutionContexts/Redumper/Enumerations.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
namespace MPF.ExecutionContexts.Redumper
|
||||
{
|
||||
/// <summary>
|
||||
/// Drive type option
|
||||
/// </summary>
|
||||
public enum DriveType
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
GENERIC,
|
||||
PLEXTOR,
|
||||
LG_ASU8A,
|
||||
LG_ASU8B,
|
||||
LG_ASU8C,
|
||||
LG_ASU3,
|
||||
LG_ASU2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drive read method option
|
||||
/// </summary>
|
||||
public enum ReadMethod
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
BE,
|
||||
D8,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drive sector order option
|
||||
/// </summary>
|
||||
public enum SectorOrder
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
DATA_C2_SUB,
|
||||
DATA_SUB_C2,
|
||||
DATA_SUB,
|
||||
DATA_C2,
|
||||
}
|
||||
}
|
||||
524
MPF.ExecutionContexts/Redumper/ExecutionContext.cs
Normal file
524
MPF.ExecutionContexts/Redumper/ExecutionContext.cs
Normal file
@@ -0,0 +1,524 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using MPF.ExecutionContexts.Data;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.ExecutionContexts.Redumper
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic set of Redumper parameters
|
||||
/// </summary>
|
||||
public sealed class ExecutionContext : BaseExecutionContext
|
||||
{
|
||||
#region Generic Dumping Information
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string? InputPath
|
||||
=> (_inputs[FlagStrings.Drive] as StringInput)?.Value?.Trim('"');
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string? OutputPath => Path.Combine(
|
||||
(_inputs[FlagStrings.ImagePath] as StringInput)?.Value?.Trim('"') ?? string.Empty,
|
||||
(_inputs[FlagStrings.ImageName] as StringInput)?.Value?.Trim('"') ?? string.Empty)
|
||||
+ GetDefaultExtension(MediaType);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int? Speed
|
||||
{
|
||||
get
|
||||
{
|
||||
return (_inputs[FlagStrings.Speed] as Int32Input)?.Value;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != null && value > 0)
|
||||
{
|
||||
this[FlagStrings.Speed] = true;
|
||||
(_inputs[FlagStrings.Speed] as Int32Input)?.SetValue(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
this[FlagStrings.Speed] = false;
|
||||
(_inputs[FlagStrings.Speed] as Int32Input)?.SetValue(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Flag Values
|
||||
|
||||
/// <summary>
|
||||
/// Set of all command flags
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, Input> _inputs = new()
|
||||
{
|
||||
// General
|
||||
[FlagStrings.HelpLong] = new FlagInput(FlagStrings.HelpShort, FlagStrings.HelpLong),
|
||||
[FlagStrings.Version] = new FlagInput(FlagStrings.Version),
|
||||
[FlagStrings.Verbose] = new FlagInput(FlagStrings.Verbose),
|
||||
[FlagStrings.ListRecommendedDrives] = new FlagInput(FlagStrings.ListRecommendedDrives),
|
||||
[FlagStrings.ListAllDrives] = new FlagInput(FlagStrings.ListAllDrives),
|
||||
[FlagStrings.AutoEject] = new FlagInput(FlagStrings.AutoEject),
|
||||
[FlagStrings.Skeleton] = new FlagInput(FlagStrings.Skeleton),
|
||||
[FlagStrings.Drive] = new StringInput(FlagStrings.Drive),
|
||||
[FlagStrings.Speed] = new Int32Input(FlagStrings.Speed),
|
||||
[FlagStrings.Retries] = new Int32Input(FlagStrings.Retries),
|
||||
[FlagStrings.ImagePath] = new StringInput(FlagStrings.ImagePath) { Quotes = true },
|
||||
[FlagStrings.ImageName] = new StringInput(FlagStrings.ImageName) { Quotes = true },
|
||||
[FlagStrings.Overwrite] = new FlagInput(FlagStrings.Overwrite),
|
||||
[FlagStrings.DiscType] = new StringInput(FlagStrings.DiscType),
|
||||
|
||||
// Drive Configuration
|
||||
[FlagStrings.DriveType] = new StringInput(FlagStrings.DriveType),
|
||||
[FlagStrings.DriveReadOffset] = new Int32Input(FlagStrings.DriveReadOffset),
|
||||
[FlagStrings.DriveC2Shift] = new Int32Input(FlagStrings.DriveC2Shift),
|
||||
[FlagStrings.DrivePregapStart] = new Int32Input(FlagStrings.DrivePregapStart),
|
||||
[FlagStrings.DriveReadMethod] = new StringInput(FlagStrings.DriveReadMethod),
|
||||
[FlagStrings.DriveSectorOrder] = new StringInput(FlagStrings.DriveSectorOrder),
|
||||
|
||||
// Drive Specific
|
||||
[FlagStrings.PlextorSkipLeadin] = new FlagInput(FlagStrings.PlextorSkipLeadin),
|
||||
[FlagStrings.PlextorLeadinRetries] = new Int32Input(FlagStrings.PlextorLeadinRetries),
|
||||
[FlagStrings.PlextorLeadinForceStore] = new FlagInput(FlagStrings.PlextorLeadinForceStore),
|
||||
[FlagStrings.KreonPartialSS] = new FlagInput(FlagStrings.KreonPartialSS),
|
||||
[FlagStrings.AsusSkipLeadout] = new FlagInput(FlagStrings.AsusSkipLeadout),
|
||||
[FlagStrings.AsusLeadoutRetries] = new Int32Input(FlagStrings.AsusLeadoutRetries),
|
||||
[FlagStrings.DisableCDText] = new FlagInput(FlagStrings.DisableCDText),
|
||||
|
||||
// Offset
|
||||
[FlagStrings.ForceOffset] = new Int32Input(FlagStrings.ForceOffset),
|
||||
[FlagStrings.AudioSilenceThreshold] = new Int32Input(FlagStrings.AudioSilenceThreshold),
|
||||
[FlagStrings.CorrectOffsetShift] = new FlagInput(FlagStrings.CorrectOffsetShift),
|
||||
[FlagStrings.OffsetShiftRelocate] = new FlagInput(FlagStrings.OffsetShiftRelocate),
|
||||
|
||||
// Split
|
||||
[FlagStrings.ForceSplit] = new FlagInput(FlagStrings.ForceSplit),
|
||||
[FlagStrings.LeaveUnchanged] = new FlagInput(FlagStrings.LeaveUnchanged),
|
||||
[FlagStrings.ForceQTOC] = new FlagInput(FlagStrings.ForceQTOC),
|
||||
[FlagStrings.SkipFill] = new UInt8Input(FlagStrings.SkipFill),
|
||||
[FlagStrings.ISO9660Trim] = new FlagInput(FlagStrings.ISO9660Trim),
|
||||
|
||||
// Drive Test
|
||||
[FlagStrings.DriveTestSkipPlextorLeadin] = new FlagInput(FlagStrings.DriveTestSkipPlextorLeadin),
|
||||
[FlagStrings.DriveTestSkipCacheRead] = new FlagInput(FlagStrings.DriveTestSkipCacheRead),
|
||||
|
||||
// Miscellaneous
|
||||
[FlagStrings.Continue] = new StringInput(FlagStrings.Continue),
|
||||
[FlagStrings.LBAStart] = new Int32Input(FlagStrings.LBAStart),
|
||||
[FlagStrings.LBAEnd] = new Int32Input(FlagStrings.LBAEnd),
|
||||
[FlagStrings.RefineSubchannel] = new FlagInput(FlagStrings.RefineSubchannel),
|
||||
[FlagStrings.RefineSectorMode] = new FlagInput(FlagStrings.RefineSectorMode),
|
||||
[FlagStrings.Skip] = new StringInput(FlagStrings.Skip),
|
||||
[FlagStrings.DumpWriteOffset] = new Int32Input(FlagStrings.DumpWriteOffset),
|
||||
[FlagStrings.DumpReadSize] = new Int32Input(FlagStrings.DumpReadSize),
|
||||
[FlagStrings.OverreadLeadout] = new FlagInput(FlagStrings.OverreadLeadout),
|
||||
[FlagStrings.ForceUnscrambled] = new FlagInput(FlagStrings.ForceUnscrambled),
|
||||
[FlagStrings.ForceRefine] = new FlagInput(FlagStrings.ForceRefine),
|
||||
//[FlagStrings.Firmware] = new StringInput(FlagStrings.Firmware) { Quotes = true },
|
||||
[FlagStrings.SkipSubcodeDesync] = new FlagInput(FlagStrings.SkipSubcodeDesync),
|
||||
[FlagStrings.Rings] = new FlagInput(FlagStrings.Rings),
|
||||
[FlagStrings.CdrErrorThreshold] = new Int32Input(FlagStrings.CdrErrorThreshold),
|
||||
|
||||
// Undocumented
|
||||
[FlagStrings.Debug] = new FlagInput(FlagStrings.Debug),
|
||||
[FlagStrings.LegacySubs] = new FlagInput(FlagStrings.LegacySubs),
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ExecutionContext(string? parameters) : base(parameters) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ExecutionContext(RedumpSystem? system,
|
||||
MediaType? type,
|
||||
string? drivePath,
|
||||
string filename,
|
||||
int? driveSpeed,
|
||||
Dictionary<string, string?> options)
|
||||
: base(system, type, drivePath, filename, driveSpeed, options)
|
||||
{
|
||||
}
|
||||
|
||||
#region BaseExecutionContext Implementations
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <remarks>Command support is irrelevant for redumper</remarks>
|
||||
public override Dictionary<string, List<string>> GetCommandSupport()
|
||||
{
|
||||
return new Dictionary<string, List<string>>()
|
||||
{
|
||||
[CommandStrings.NONE] =
|
||||
[
|
||||
// General
|
||||
FlagStrings.HelpLong,
|
||||
FlagStrings.HelpShort,
|
||||
FlagStrings.Version,
|
||||
FlagStrings.Verbose,
|
||||
FlagStrings.ListRecommendedDrives,
|
||||
FlagStrings.ListAllDrives,
|
||||
FlagStrings.AutoEject,
|
||||
FlagStrings.Skeleton,
|
||||
FlagStrings.Drive,
|
||||
FlagStrings.Speed,
|
||||
FlagStrings.Retries,
|
||||
FlagStrings.ImagePath,
|
||||
FlagStrings.ImageName,
|
||||
FlagStrings.Overwrite,
|
||||
FlagStrings.DiscType,
|
||||
|
||||
// Drive Configuration
|
||||
FlagStrings.DriveType,
|
||||
FlagStrings.DriveReadOffset,
|
||||
FlagStrings.DriveC2Shift,
|
||||
FlagStrings.DrivePregapStart,
|
||||
FlagStrings.DriveReadMethod,
|
||||
FlagStrings.DriveSectorOrder,
|
||||
|
||||
// Drive Specific
|
||||
FlagStrings.PlextorSkipLeadin,
|
||||
FlagStrings.PlextorLeadinRetries,
|
||||
FlagStrings.PlextorLeadinForceStore,
|
||||
FlagStrings.KreonPartialSS,
|
||||
FlagStrings.AsusSkipLeadout,
|
||||
FlagStrings.AsusLeadoutRetries,
|
||||
FlagStrings.DisableCDText,
|
||||
|
||||
// Offset
|
||||
FlagStrings.ForceOffset,
|
||||
FlagStrings.AudioSilenceThreshold,
|
||||
FlagStrings.CorrectOffsetShift,
|
||||
FlagStrings.OffsetShiftRelocate,
|
||||
|
||||
// Split
|
||||
FlagStrings.ForceSplit,
|
||||
FlagStrings.LeaveUnchanged,
|
||||
FlagStrings.ForceQTOC,
|
||||
FlagStrings.SkipFill,
|
||||
FlagStrings.ISO9660Trim,
|
||||
|
||||
// Drive Test
|
||||
FlagStrings.DriveTestSkipPlextorLeadin,
|
||||
FlagStrings.DriveTestSkipCacheRead,
|
||||
|
||||
// Miscellaneous
|
||||
FlagStrings.Continue,
|
||||
FlagStrings.LBAStart,
|
||||
FlagStrings.LBAEnd,
|
||||
FlagStrings.RefineSubchannel,
|
||||
FlagStrings.RefineSectorMode,
|
||||
FlagStrings.Skip,
|
||||
FlagStrings.DumpWriteOffset,
|
||||
FlagStrings.DumpReadSize,
|
||||
FlagStrings.OverreadLeadout,
|
||||
FlagStrings.ForceUnscrambled,
|
||||
FlagStrings.ForceRefine,
|
||||
//FlagStrings.Firmware,
|
||||
FlagStrings.SkipSubcodeDesync,
|
||||
FlagStrings.Rings,
|
||||
FlagStrings.CdrErrorThreshold,
|
||||
|
||||
// Undocumented
|
||||
FlagStrings.Debug,
|
||||
FlagStrings.LegacySubs,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <remarks>
|
||||
/// Redumper is unique in that the base command can be multiple
|
||||
/// modes all listed together. It is also unique in that "all
|
||||
/// flags are supported for everything" and it filters out internally
|
||||
/// </remarks>
|
||||
public override string GenerateParameters()
|
||||
{
|
||||
var parameters = new StringBuilder();
|
||||
|
||||
// Command Mode
|
||||
BaseCommand ??= CommandStrings.NONE;
|
||||
if (BaseCommand != CommandStrings.NONE)
|
||||
parameters.Append($"{BaseCommand} ");
|
||||
|
||||
// Loop though and append all existing
|
||||
foreach (var kvp in _inputs)
|
||||
{
|
||||
// If the value doesn't exist
|
||||
string formatted = kvp.Value.Format(useEquals: true);
|
||||
if (formatted.Length == 0)
|
||||
continue;
|
||||
|
||||
// Append the parameter
|
||||
parameters.Append($"{formatted} ");
|
||||
}
|
||||
|
||||
return parameters.ToString().TrimEnd();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string? GetDefaultExtension(MediaType? mediaType) => Converters.Extension(mediaType);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override MediaType? GetMediaType() => null;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool IsDumpingCommand()
|
||||
{
|
||||
// `dump` command does not provide hashes so will error out after dump if run via MPF
|
||||
return BaseCommand == CommandStrings.NONE
|
||||
|| BaseCommand == CommandStrings.Disc;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void ResetValues()
|
||||
{
|
||||
BaseCommand = CommandStrings.NONE;
|
||||
|
||||
flags = [];
|
||||
|
||||
foreach (var kvp in _inputs)
|
||||
kvp.Value.ClearValue();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void SetDefaultParameters(string? drivePath,
|
||||
string filename,
|
||||
int? driveSpeed,
|
||||
Dictionary<string, string?> options)
|
||||
{
|
||||
BaseCommand = CommandStrings.Disc;
|
||||
|
||||
if (drivePath != null)
|
||||
{
|
||||
this[FlagStrings.Drive] = true;
|
||||
(_inputs[FlagStrings.Drive] as StringInput)?.SetValue(drivePath);
|
||||
}
|
||||
|
||||
if (driveSpeed != null && driveSpeed > 0)
|
||||
{
|
||||
this[FlagStrings.Speed] = true;
|
||||
(_inputs[FlagStrings.Speed] as Int32Input)?.SetValue(driveSpeed);
|
||||
}
|
||||
else
|
||||
{
|
||||
this[FlagStrings.Speed] = false;
|
||||
(_inputs[FlagStrings.Speed] as Int32Input)?.SetValue(null);
|
||||
}
|
||||
|
||||
// Set user-defined options
|
||||
if (GetBooleanSetting(options, SettingConstants.EnableVerbose, SettingConstants.EnableVerboseDefault))
|
||||
{
|
||||
this[FlagStrings.Verbose] = true;
|
||||
(_inputs[FlagStrings.Verbose] as FlagInput)?.SetValue(true);
|
||||
}
|
||||
if (GetBooleanSetting(options, SettingConstants.EnableSkeleton, SettingConstants.EnableSkeletonDefault))
|
||||
{
|
||||
switch (RedumpSystem)
|
||||
{
|
||||
// Systems known to have significant data outside the ISO9660 filesystem
|
||||
case SabreTools.RedumpLib.Data.RedumpSystem.MicrosoftXbox:
|
||||
case SabreTools.RedumpLib.Data.RedumpSystem.MicrosoftXbox360:
|
||||
case SabreTools.RedumpLib.Data.RedumpSystem.PlaymajiPolymega:
|
||||
// Skeletons from newer BD-based consoles unnecessary
|
||||
case SabreTools.RedumpLib.Data.RedumpSystem.MicrosoftXboxOne:
|
||||
case SabreTools.RedumpLib.Data.RedumpSystem.MicrosoftXboxSeriesXS:
|
||||
case SabreTools.RedumpLib.Data.RedumpSystem.SonyPlayStation3:
|
||||
case SabreTools.RedumpLib.Data.RedumpSystem.SonyPlayStation4:
|
||||
case SabreTools.RedumpLib.Data.RedumpSystem.SonyPlayStation5:
|
||||
case SabreTools.RedumpLib.Data.RedumpSystem.NintendoWiiU:
|
||||
break;
|
||||
|
||||
default:
|
||||
// Enable skeleton for CD and DVD only, by default
|
||||
switch (MediaType)
|
||||
{
|
||||
case SabreTools.RedumpLib.Data.MediaType.CDROM:
|
||||
case SabreTools.RedumpLib.Data.MediaType.DVD:
|
||||
{
|
||||
this[FlagStrings.Skeleton] = true;
|
||||
(_inputs[FlagStrings.Skeleton] as FlagInput)?.SetValue(true);
|
||||
}
|
||||
break;
|
||||
|
||||
// If the type is unknown, also enable
|
||||
case null:
|
||||
this[FlagStrings.Skeleton] = true;
|
||||
(_inputs[FlagStrings.Skeleton] as FlagInput)?.SetValue(true);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
string? readMethod = GetStringSetting(options, SettingConstants.ReadMethod, SettingConstants.ReadMethodDefault);
|
||||
if (!string.IsNullOrEmpty(readMethod) && readMethod != ReadMethod.NONE.ToString())
|
||||
{
|
||||
this[FlagStrings.DriveReadMethod] = true;
|
||||
(_inputs[FlagStrings.DriveReadMethod] as StringInput)?.SetValue(readMethod!);
|
||||
}
|
||||
|
||||
int drivePregapStart = GetInt32Setting(options, SettingConstants.DrivePregapStart, SettingConstants.DrivePregapStartDefault);
|
||||
if (drivePregapStart != SettingConstants.DrivePregapStartDefault)
|
||||
{
|
||||
this[FlagStrings.DrivePregapStart] = true;
|
||||
(_inputs[FlagStrings.DrivePregapStart] as Int32Input)?.SetValue(drivePregapStart);
|
||||
}
|
||||
|
||||
string? sectorOrder = GetStringSetting(options, SettingConstants.SectorOrder, SettingConstants.SectorOrderDefault);
|
||||
if (!string.IsNullOrEmpty(sectorOrder) && sectorOrder != SectorOrder.NONE.ToString())
|
||||
{
|
||||
this[FlagStrings.DriveSectorOrder] = true;
|
||||
(_inputs[FlagStrings.DriveSectorOrder] as StringInput)?.SetValue(sectorOrder!);
|
||||
}
|
||||
|
||||
string? driveType = GetStringSetting(options, SettingConstants.DriveType, SettingConstants.DriveTypeDefault);
|
||||
if (!string.IsNullOrEmpty(driveType) && driveType != DriveType.NONE.ToString())
|
||||
{
|
||||
this[FlagStrings.DriveType] = true;
|
||||
(_inputs[FlagStrings.DriveType] as StringInput)?.SetValue(driveType!);
|
||||
}
|
||||
|
||||
// Set the output paths
|
||||
if (!string.IsNullOrEmpty(filename))
|
||||
{
|
||||
var imagePath = Path.GetDirectoryName(filename);
|
||||
if (!string.IsNullOrEmpty(imagePath))
|
||||
{
|
||||
this[FlagStrings.ImagePath] = true;
|
||||
(_inputs[FlagStrings.ImagePath] as StringInput)?.SetValue(imagePath!);
|
||||
}
|
||||
|
||||
string imageName = Path.GetFileNameWithoutExtension(filename);
|
||||
if (!string.IsNullOrEmpty(imageName))
|
||||
{
|
||||
this[FlagStrings.ImageName] = true;
|
||||
(_inputs[FlagStrings.ImageName] as StringInput)?.SetValue(imageName!);
|
||||
}
|
||||
}
|
||||
|
||||
int retries = GetInt32Setting(options, SettingConstants.RereadCount, SettingConstants.RereadCountDefault);
|
||||
if (retries > 0)
|
||||
{
|
||||
this[FlagStrings.Retries] = true;
|
||||
(_inputs[FlagStrings.Retries] as Int32Input)?.SetValue(retries);
|
||||
}
|
||||
|
||||
int leadinRetries = GetInt32Setting(options, SettingConstants.LeadinRetryCount, SettingConstants.LeadinRetryCountDefault);
|
||||
if (leadinRetries != SettingConstants.LeadinRetryCountDefault)
|
||||
{
|
||||
this[FlagStrings.PlextorLeadinRetries] = true;
|
||||
(_inputs[FlagStrings.PlextorLeadinRetries] as Int32Input)?.SetValue(leadinRetries);
|
||||
}
|
||||
|
||||
if (GetBooleanSetting(options, SettingConstants.RefineSectorMode, SettingConstants.RefineSectorModeDefault))
|
||||
{
|
||||
this[FlagStrings.RefineSectorMode] = true;
|
||||
(_inputs[FlagStrings.RefineSectorMode] as FlagInput)?.SetValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override bool ValidateAndSetParameters(string? parameters)
|
||||
{
|
||||
// The string has to be valid by itself first
|
||||
if (string.IsNullOrEmpty(parameters))
|
||||
return false;
|
||||
|
||||
// Now split the string into parts for easier validation
|
||||
string[] parts = SplitParameterString(parameters!);
|
||||
|
||||
// Setup the modes
|
||||
BaseCommand = null;
|
||||
|
||||
// All modes should be cached separately
|
||||
int index = 0;
|
||||
for (; index < parts.Length; index++)
|
||||
{
|
||||
// Flag to see if we have a flag
|
||||
bool isFlag = false;
|
||||
|
||||
string part = parts[index];
|
||||
switch (part)
|
||||
{
|
||||
case CommandStrings.Disc:
|
||||
case CommandStrings.Rings:
|
||||
case CommandStrings.Dump:
|
||||
case CommandStrings.DumpExtra:
|
||||
case CommandStrings.Refine:
|
||||
case CommandStrings.Verify:
|
||||
case CommandStrings.DVDKey:
|
||||
case CommandStrings.Eject:
|
||||
case CommandStrings.DVDIsoKey:
|
||||
case CommandStrings.Protection:
|
||||
case CommandStrings.Split:
|
||||
case CommandStrings.Hash:
|
||||
case CommandStrings.Info:
|
||||
case CommandStrings.Skeleton:
|
||||
case CommandStrings.FlashMT1339:
|
||||
case CommandStrings.FlashSD616:
|
||||
case CommandStrings.FlashPlextor:
|
||||
case CommandStrings.Subchannel:
|
||||
case CommandStrings.Debug:
|
||||
case CommandStrings.FixMSF:
|
||||
case CommandStrings.DebugFlip:
|
||||
case CommandStrings.DriveTest:
|
||||
// Only allow one mode per command
|
||||
if (BaseCommand != null)
|
||||
continue;
|
||||
|
||||
BaseCommand = part;
|
||||
break;
|
||||
|
||||
// Default is either a flag or an invalid mode
|
||||
default:
|
||||
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
|
||||
if (part.StartsWith('-'))
|
||||
#else
|
||||
if (part.StartsWith("-"))
|
||||
#endif
|
||||
{
|
||||
isFlag = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If we had a flag, break out
|
||||
if (isFlag)
|
||||
break;
|
||||
}
|
||||
|
||||
// Loop through all auxiliary flags, if necessary
|
||||
for (int i = index; i < parts.Length; i++)
|
||||
{
|
||||
// Match all possible flags
|
||||
foreach (var kvp in _inputs)
|
||||
{
|
||||
// If the value was not a match
|
||||
if (!kvp.Value.Process(parts, ref i))
|
||||
continue;
|
||||
|
||||
// Set the flag
|
||||
this[kvp.Key] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If the image name was not set, set it with a default value
|
||||
if (string.IsNullOrEmpty((_inputs[FlagStrings.ImageName] as StringInput)?.Value))
|
||||
(_inputs[FlagStrings.ImageName] as StringInput)?.SetValue($"track_{DateTime.Now:yyyyMMdd-HHmm}");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,43 +1,32 @@
|
||||
namespace MPF.Core.Modules.Redumper
|
||||
namespace MPF.ExecutionContexts.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 Dump = "dump";
|
||||
public const string Info = "info";
|
||||
public const string Protection = "protection";
|
||||
public const string Refine = "refine";
|
||||
public const string Split = "split";
|
||||
public const string Verify = "verify";
|
||||
public const string DVDKey = "dvdkey";
|
||||
public const string DVDIsoKey = "dvdisokey";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dumping flags for Redumper
|
||||
/// </summary>
|
||||
public static class FlagStrings
|
||||
{
|
||||
// General
|
||||
#region 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 ListRecommendedDrives = "--list-recommended-drives";
|
||||
public const string ListAllDrives = "--list-all-drives";
|
||||
public const string AutoEject = "--auto-eject";
|
||||
public const string Skeleton = "--skeleton";
|
||||
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";
|
||||
public const string DiscType = "--disc-type";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Drive Configuration
|
||||
|
||||
// Drive Configuration
|
||||
public const string DriveType = "--drive-type";
|
||||
public const string DriveReadOffset = "--drive-read-offset";
|
||||
public const string DriveC2Shift = "--drive-c2-shift";
|
||||
@@ -45,30 +34,71 @@ namespace MPF.Core.Modules.Redumper
|
||||
public const string DriveReadMethod = "--drive-read-method";
|
||||
public const string DriveSectorOrder = "--drive-sector-order";
|
||||
|
||||
// Drive Specific
|
||||
public const string PlextorLeadinSkip = "--plextor-leadin-skip";
|
||||
public const string PlextorLeadinRetries = "--plextor-leadin-retries";
|
||||
public const string AsusSkipLeadout = "--asus-skip-leadout";
|
||||
#endregion
|
||||
|
||||
#region Drive Specific
|
||||
|
||||
public const string PlextorSkipLeadin = "--plextor-skip-leadin";
|
||||
public const string PlextorLeadinRetries = "--plextor-leadin-retries";
|
||||
public const string PlextorLeadinForceStore = "--plextor-leadin-force-store";
|
||||
public const string KreonPartialSS = "--kreon-partial-ss";
|
||||
public const string AsusSkipLeadout = "--asus-skip-leadout";
|
||||
public const string AsusLeadoutRetries = "--asus-leadout-retries";
|
||||
public const string DisableCDText = "--disable-cdtext";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Offset
|
||||
|
||||
// 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
|
||||
#endregion
|
||||
|
||||
#region 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
|
||||
#endregion
|
||||
|
||||
#region Drive Test
|
||||
|
||||
public const string DriveTestSkipPlextorLeadin = "--drive-test-skip-plextor-leadin";
|
||||
public const string DriveTestSkipCacheRead = "--drive-test-skip-cache-read";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Miscellaneous
|
||||
|
||||
public const string Continue = "--continue";
|
||||
public const string LBAStart = "--lba-start";
|
||||
public const string LBAEnd = "--lba-end";
|
||||
public const string RefineSubchannel = "--refine-subchannel";
|
||||
public const string RefineSectorMode = "--refine-sector-mode";
|
||||
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 ForceUnscrambled = "--force-unscrambled";
|
||||
public const string ForceRefine = "--force-refine";
|
||||
public const string Firmware = "--firmware";
|
||||
public const string SkipSubcodeDesync = "--skip-subcode-desync";
|
||||
public const string Rings = "--rings";
|
||||
public const string CdrErrorThreshold = "--cdr-error-threshold";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Undocumented
|
||||
|
||||
public const string Debug = "--debug";
|
||||
public const string LegacySubs = "--legacy-subs";
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
32
MPF.ExecutionContexts/Redumper/SettingConstants.cs
Normal file
32
MPF.ExecutionContexts/Redumper/SettingConstants.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
namespace MPF.ExecutionContexts.Redumper
|
||||
{
|
||||
public static class SettingConstants
|
||||
{
|
||||
public const string DriveType = "RedumperDriveType";
|
||||
public static readonly string DriveTypeDefault = Redumper.DriveType.NONE.ToString();
|
||||
|
||||
public const string EnableSkeleton = "RedumperEnableSkeleton";
|
||||
public const bool EnableSkeletonDefault = true;
|
||||
|
||||
public const string EnableVerbose = "RedumperEnableVerbose";
|
||||
public const bool EnableVerboseDefault = false;
|
||||
|
||||
public const string LeadinRetryCount = "RedumperLeadinRetryCount";
|
||||
public const int LeadinRetryCountDefault = 4;
|
||||
|
||||
public const string DrivePregapStart = "RedumperDrivePregapStart";
|
||||
public const int DrivePregapStartDefault = 0;
|
||||
|
||||
public const string ReadMethod = "RedumperReadMethod";
|
||||
public static readonly string ReadMethodDefault = Redumper.ReadMethod.NONE.ToString();
|
||||
|
||||
public const string RefineSectorMode = "RedumperRefineSectorMode";
|
||||
public const bool RefineSectorModeDefault = false;
|
||||
|
||||
public const string RereadCount = "RedumperRereadCount";
|
||||
public const int RereadCountDefault = 20;
|
||||
|
||||
public const string SectorOrder = "RedumperSectorOrder";
|
||||
public static readonly string SectorOrderDefault = Redumper.SectorOrder.NONE.ToString();
|
||||
}
|
||||
}
|
||||
59
MPF.Frontend.Test/DriveTests.cs
Normal file
59
MPF.Frontend.Test/DriveTests.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Frontend.Test
|
||||
{
|
||||
public class DriveTests
|
||||
{
|
||||
#region ToInternalDriveType
|
||||
|
||||
/// <summary>
|
||||
/// DiscType values that map to InternalDriveType
|
||||
/// </summary>
|
||||
private static readonly DriveType[] _mappableDriveTypes =
|
||||
[
|
||||
DriveType.CDRom,
|
||||
DriveType.Fixed,
|
||||
DriveType.Removable,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Check that every supported DriveType maps to an InternalDriveType
|
||||
/// </summary>
|
||||
/// <param name="driveType">DriveType value to check</param>
|
||||
/// <param name="expectNull">True to expect a null mapping, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateDriveTypeMappingTestData))]
|
||||
public void ToInternalDriveTypeTest(DriveType driveType, bool expectNull)
|
||||
{
|
||||
var actual = Drive.ToInternalDriveType(driveType);
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of DriveType values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of DriveType values</returns>
|
||||
public static List<object?[]> GenerateDriveTypeMappingTestData()
|
||||
{
|
||||
var testData = new List<object?[]>() { new object?[] { null, true } };
|
||||
foreach (DriveType driveType in Enum.GetValues<DriveType>())
|
||||
{
|
||||
if (Array.IndexOf(_mappableDriveTypes, driveType) > -1)
|
||||
testData.Add([driveType, false]);
|
||||
else
|
||||
testData.Add([driveType, true]);
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
using MPF.Core;
|
||||
using MPF.Core.Data;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Library
|
||||
namespace MPF.Frontend.Test
|
||||
{
|
||||
public class DumpEnvironmentTests
|
||||
{
|
||||
@@ -11,10 +9,11 @@ namespace MPF.Test.Library
|
||||
[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("cd F test.bin 8 /c2new 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)
|
||||
public void ParametersValidTest(string? parameters, char letter, bool isFloppy, MediaType? mediaType, bool expected)
|
||||
{
|
||||
var options = new Options() { InternalProgram = InternalProgram.DiscImageCreator };
|
||||
|
||||
@@ -23,9 +22,15 @@ namespace MPF.Test.Library
|
||||
? Drive.Create(InternalDriveType.Floppy, letter.ToString())
|
||||
: Drive.Create(InternalDriveType.Optical, letter.ToString());
|
||||
|
||||
var env = new DumpEnvironment(options, string.Empty, drive, RedumpSystem.IBMPCcompatible, mediaType, null, parameters);
|
||||
var env = new DumpEnvironment(options,
|
||||
string.Empty,
|
||||
drive,
|
||||
RedumpSystem.IBMPCcompatible,
|
||||
null);
|
||||
env.SetExecutionContext(mediaType, parameters);
|
||||
env.SetProcessor();
|
||||
|
||||
bool actual = env.ParametersValid();
|
||||
bool actual = env.ParametersValid(mediaType);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
293
MPF.Frontend.Test/EnumExtensionsTests.cs
Normal file
293
MPF.Frontend.Test/EnumExtensionsTests.cs
Normal file
@@ -0,0 +1,293 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
using Xunit;
|
||||
using LogCompression = MPF.Processors.LogCompression;
|
||||
using RedumperDriveType = MPF.ExecutionContexts.Redumper.DriveType;
|
||||
using RedumperReadMethod = MPF.ExecutionContexts.Redumper.ReadMethod;
|
||||
using RedumperSectorOrder = MPF.ExecutionContexts.Redumper.SectorOrder;
|
||||
|
||||
namespace MPF.Frontend.Test
|
||||
{
|
||||
public class EnumExtensionsTests
|
||||
{
|
||||
#region Long Name
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, "Unknown")]
|
||||
[InlineData(InterfaceLanguage.AutoDetect, "Auto Detect")]
|
||||
[InlineData(InterfaceLanguage.English, "English")]
|
||||
[InlineData(InterfaceLanguage.French, "Français")]
|
||||
[InlineData(InterfaceLanguage.German, "Deutsch")]
|
||||
[InlineData(InterfaceLanguage.Italian, "Italiano")]
|
||||
[InlineData(InterfaceLanguage.Japanese, "日本語")]
|
||||
[InlineData(InterfaceLanguage.Korean, "한국어")]
|
||||
[InlineData(InterfaceLanguage.Polish, "Polski")]
|
||||
[InlineData(InterfaceLanguage.Russian, "Русский")]
|
||||
[InlineData(InterfaceLanguage.Spanish, "Español")]
|
||||
[InlineData(InterfaceLanguage.Swedish, "Svenska")]
|
||||
[InlineData(InterfaceLanguage.Ukrainian, "Українська")]
|
||||
[InlineData(InterfaceLanguage.L337, "L337")]
|
||||
public void LongName_InterfaceLanguage(InterfaceLanguage? lang, string? expected)
|
||||
{
|
||||
string? actual = lang.LongName();
|
||||
Assert.Equal(expected, actual);
|
||||
|
||||
if (lang != null)
|
||||
{
|
||||
actual = EnumExtensions.GetLongName(lang);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, "Unknown")]
|
||||
[InlineData(InternalProgram.NONE, "Unknown")]
|
||||
[InlineData(InternalProgram.Aaru, "Aaru")]
|
||||
[InlineData(InternalProgram.DiscImageCreator, "DiscImageCreator")]
|
||||
[InlineData(InternalProgram.Redumper, "Redumper")]
|
||||
[InlineData(InternalProgram.CleanRip, "CleanRip")]
|
||||
[InlineData(InternalProgram.PS3CFW, "PS3 CFW")]
|
||||
[InlineData(InternalProgram.UmdImageCreator, "UmdImageCreator")]
|
||||
[InlineData(InternalProgram.XboxBackupCreator, "XboxBackupCreator")]
|
||||
public void LongName_InternalProgram(InternalProgram? prog, string? expected)
|
||||
{
|
||||
string? actual = prog.LongName();
|
||||
Assert.Equal(expected, actual);
|
||||
|
||||
if (prog != null)
|
||||
{
|
||||
actual = EnumExtensions.GetLongName(prog);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, "Unknown")]
|
||||
[InlineData(LogCompression.DeflateDefault, "ZIP using Deflate (Level 5)")]
|
||||
[InlineData(LogCompression.DeflateMaximum, "ZIP using Deflate (Level 9)")]
|
||||
[InlineData(LogCompression.Zstd19, "ZIP using Zstd (Level 19)")]
|
||||
public void LongName_LogCompression(LogCompression? comp, string? expected)
|
||||
{
|
||||
string? actual = comp.LongName();
|
||||
Assert.Equal(expected, actual);
|
||||
|
||||
if (comp != null)
|
||||
{
|
||||
actual = EnumExtensions.GetLongName(comp);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, "Unknown")]
|
||||
[InlineData(RedumperReadMethod.NONE, "Default")]
|
||||
[InlineData(RedumperReadMethod.D8, "D8")]
|
||||
[InlineData(RedumperReadMethod.BE, "BE")]
|
||||
public void LongName_RedumperReadMethod(RedumperReadMethod? method, string? expected)
|
||||
{
|
||||
string? actual = method.LongName();
|
||||
Assert.Equal(expected, actual);
|
||||
|
||||
if (method != null)
|
||||
{
|
||||
actual = EnumExtensions.GetLongName(method);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, "Unknown")]
|
||||
[InlineData(RedumperSectorOrder.NONE, "Default")]
|
||||
[InlineData(RedumperSectorOrder.DATA_C2_SUB, "DATA_C2_SUB")]
|
||||
[InlineData(RedumperSectorOrder.DATA_SUB_C2, "DATA_SUB_C2")]
|
||||
[InlineData(RedumperSectorOrder.DATA_SUB, "DATA_SUB")]
|
||||
[InlineData(RedumperSectorOrder.DATA_C2, "DATA_C2")]
|
||||
public void LongName_RedumperSectorOrder(RedumperSectorOrder? order, string? expected)
|
||||
{
|
||||
string? actual = order.LongName();
|
||||
Assert.Equal(expected, actual);
|
||||
|
||||
if (order != null)
|
||||
{
|
||||
actual = EnumExtensions.GetLongName(order);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, "Unknown")]
|
||||
[InlineData(RedumperDriveType.NONE, "Default")]
|
||||
[InlineData(RedumperDriveType.GENERIC, "GENERIC")]
|
||||
[InlineData(RedumperDriveType.PLEXTOR, "PLEXTOR")]
|
||||
[InlineData(RedumperDriveType.LG_ASU8A, "LG_ASU8A")]
|
||||
[InlineData(RedumperDriveType.LG_ASU8B, "LG_ASU8B")]
|
||||
[InlineData(RedumperDriveType.LG_ASU8C, "LG_ASU8C")]
|
||||
[InlineData(RedumperDriveType.LG_ASU3, "LG_ASU3")]
|
||||
[InlineData(RedumperDriveType.LG_ASU2, "LG_ASU2")]
|
||||
public void LongName_RedumperDriveType(RedumperDriveType? type, string? expected)
|
||||
{
|
||||
string? actual = type.LongName();
|
||||
Assert.Equal(expected, actual);
|
||||
|
||||
if (type != null)
|
||||
{
|
||||
actual = EnumExtensions.GetLongName(type);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Short Name
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, "Unknown")]
|
||||
[InlineData(InterfaceLanguage.AutoDetect, "auto")]
|
||||
[InlineData(InterfaceLanguage.English, "eng")]
|
||||
[InlineData(InterfaceLanguage.French, "fra")]
|
||||
[InlineData(InterfaceLanguage.German, "deu")]
|
||||
[InlineData(InterfaceLanguage.Italian, "ita")]
|
||||
[InlineData(InterfaceLanguage.Japanese, "jpn")]
|
||||
[InlineData(InterfaceLanguage.Korean, "kor")]
|
||||
[InlineData(InterfaceLanguage.Polish, "pol")]
|
||||
[InlineData(InterfaceLanguage.Russian, "rus")]
|
||||
[InlineData(InterfaceLanguage.Spanish, "spa")]
|
||||
[InlineData(InterfaceLanguage.Swedish, "swe")]
|
||||
[InlineData(InterfaceLanguage.Ukrainian, "ukr")]
|
||||
[InlineData(InterfaceLanguage.L337, "l37")]
|
||||
public void ShortName_InterfaceLanguage(InterfaceLanguage? lang, string? expected)
|
||||
{
|
||||
string? actual = lang.ShortName();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, "Unknown")]
|
||||
[InlineData(InternalProgram.NONE, "Unknown")]
|
||||
[InlineData(InternalProgram.Aaru, "aaru")]
|
||||
[InlineData(InternalProgram.DiscImageCreator, "dic")]
|
||||
[InlineData(InternalProgram.Redumper, "redumper")]
|
||||
[InlineData(InternalProgram.CleanRip, "cleanrip")]
|
||||
[InlineData(InternalProgram.PS3CFW, "ps3cfw")]
|
||||
[InlineData(InternalProgram.UmdImageCreator, "uic")]
|
||||
[InlineData(InternalProgram.XboxBackupCreator, "xbc")]
|
||||
public void ShortName_InternalProgram(InternalProgram? prog, string? expected)
|
||||
{
|
||||
string? actual = prog.ShortName();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region From String
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, InterfaceLanguage.AutoDetect)]
|
||||
[InlineData("", InterfaceLanguage.AutoDetect)]
|
||||
[InlineData("auto", InterfaceLanguage.AutoDetect)]
|
||||
[InlineData("eng", InterfaceLanguage.English)]
|
||||
[InlineData("fra", InterfaceLanguage.French)]
|
||||
[InlineData("deu", InterfaceLanguage.German)]
|
||||
[InlineData("ita", InterfaceLanguage.Italian)]
|
||||
[InlineData("jpn", InterfaceLanguage.Japanese)]
|
||||
[InlineData("kor", InterfaceLanguage.Korean)]
|
||||
[InlineData("pol", InterfaceLanguage.Polish)]
|
||||
[InlineData("rus", InterfaceLanguage.Russian)]
|
||||
[InlineData("spa", InterfaceLanguage.Spanish)]
|
||||
[InlineData("swe", InterfaceLanguage.Swedish)]
|
||||
[InlineData("ukr", InterfaceLanguage.Ukrainian)]
|
||||
[InlineData("l37", InterfaceLanguage.L337)]
|
||||
public void ToInterfaceLanguageTest(string? interfaceLanguage, InterfaceLanguage expected)
|
||||
{
|
||||
InterfaceLanguage actual = interfaceLanguage.ToInterfaceLanguage();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, InternalProgram.NONE)]
|
||||
[InlineData("", InternalProgram.NONE)]
|
||||
[InlineData("aaru", InternalProgram.Aaru)]
|
||||
[InlineData("dic", InternalProgram.DiscImageCreator)]
|
||||
[InlineData("redumper", InternalProgram.Redumper)]
|
||||
[InlineData("cleanrip", InternalProgram.CleanRip)]
|
||||
[InlineData("ps3cfw", InternalProgram.PS3CFW)]
|
||||
[InlineData("uic", InternalProgram.UmdImageCreator)]
|
||||
[InlineData("xbc", InternalProgram.XboxBackupCreator)]
|
||||
public void ToInternalProgramTest(string? internalProgram, InternalProgram expected)
|
||||
{
|
||||
InternalProgram actual = internalProgram.ToInternalProgram();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
// TODO: Write remaining from-string tests
|
||||
|
||||
#endregion
|
||||
|
||||
#region Functionality Support
|
||||
|
||||
private static readonly RedumpSystem?[] _antiModchipSystems =
|
||||
[
|
||||
RedumpSystem.SonyPlayStation,
|
||||
];
|
||||
|
||||
private static readonly RedumpSystem?[] _copyProtectionSystems =
|
||||
[
|
||||
RedumpSystem.AppleMacintosh,
|
||||
RedumpSystem.DVDVideo,
|
||||
RedumpSystem.EnhancedCD ,
|
||||
RedumpSystem.IBMPCcompatible,
|
||||
RedumpSystem.PalmOS,
|
||||
RedumpSystem.PocketPC,
|
||||
RedumpSystem.RainbowDisc,
|
||||
RedumpSystem.SonyElectronicBook,
|
||||
];
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateSupportsAntiModchipScansData))]
|
||||
public void SupportsAntiModchipScansTest(RedumpSystem? redumpSystem, bool expected)
|
||||
{
|
||||
bool actual = redumpSystem.SupportsAntiModchipScans();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateSupportsCopyProtectionScansData))]
|
||||
public void SupportsCopyProtectionScansTest(RedumpSystem? redumpSystem, bool expected)
|
||||
{
|
||||
bool actual = redumpSystem.SupportsCopyProtectionScans();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
public static List<object?[]> GenerateSupportsAntiModchipScansData()
|
||||
{
|
||||
var testData = new List<object?[]>() { new object?[] { null, false } };
|
||||
foreach (RedumpSystem redumpSystem in Enum.GetValues<RedumpSystem>())
|
||||
{
|
||||
if (_antiModchipSystems.Contains(redumpSystem))
|
||||
testData.Add([redumpSystem, true]);
|
||||
else
|
||||
testData.Add([redumpSystem, false]);
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
public static List<object?[]> GenerateSupportsCopyProtectionScansData()
|
||||
{
|
||||
var testData = new List<object?[]>() { new object?[] { null, false } };
|
||||
foreach (RedumpSystem redumpSystem in Enum.GetValues<RedumpSystem>())
|
||||
{
|
||||
if (_copyProtectionSystems.Contains(redumpSystem))
|
||||
testData.Add([redumpSystem, true]);
|
||||
else
|
||||
testData.Add([redumpSystem, false]);
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
24
MPF.Frontend.Test/InterfaceConstantsTests.cs
Normal file
24
MPF.Frontend.Test/InterfaceConstantsTests.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using SabreTools.RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Frontend.Test
|
||||
{
|
||||
public class InterfaceConstantsTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(MediaType.CDROM, 72)]
|
||||
[InlineData(MediaType.DVD, 24)]
|
||||
[InlineData(MediaType.NintendoGameCubeGameDisc, 24)]
|
||||
[InlineData(MediaType.NintendoWiiOpticalDisc, 24)]
|
||||
[InlineData(MediaType.HDDVD, 24)]
|
||||
[InlineData(MediaType.BluRay, 16)]
|
||||
[InlineData(MediaType.NintendoWiiUOpticalDisc, 16)]
|
||||
[InlineData(MediaType.LaserDisc, 72)]
|
||||
[InlineData(null, 72)]
|
||||
public void GetAllowedDriveSpeedForMediaTypeTest(MediaType? mediaType, int maxExpected)
|
||||
{
|
||||
var actual = InterfaceConstants.GetSpeedsForMediaType(mediaType);
|
||||
Assert.Equal(maxExpected, actual[^1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
38
MPF.Frontend.Test/MPF.Frontend.Test.csproj
Normal file
38
MPF.Frontend.Test/MPF.Frontend.Test.csproj
Normal file
@@ -0,0 +1,38 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MPF.Frontend\MPF.Frontend.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeCoverage" Version="18.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="[1.9.0]" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
|
||||
<PackageReference Include="xunit.analyzers" Version="1.25.0" />
|
||||
<PackageReference Include="xunit.assert" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.core" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.extensibility.core" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.extensibility.execution" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.console" Version="2.9.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
47
MPF.Frontend.Test/OptionsTests.cs
Normal file
47
MPF.Frontend.Test/OptionsTests.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System.Collections.Generic;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Frontend.Test
|
||||
{
|
||||
public class OptionsTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("key2", null, "key", false, false)]
|
||||
[InlineData("key", null, "key", false, false)]
|
||||
[InlineData("key", "", "key", false, false)]
|
||||
[InlineData("key", "INVALID", "key", false, false)]
|
||||
[InlineData("key", "true", "key", false, true)]
|
||||
public void GetBooleanSettingTest(string key, string? value, string expectedKey, bool defaultValue, bool expectedValue)
|
||||
{
|
||||
Dictionary<string, string?> settings = new() { [key] = value };
|
||||
bool actual = Options.GetBooleanSetting(settings, expectedKey, defaultValue);
|
||||
Assert.Equal(expectedValue, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("key2", null, "key", -1, -1)]
|
||||
[InlineData("key", null, "key", -1, -1)]
|
||||
[InlineData("key", "", "key", -1, -1)]
|
||||
[InlineData("key", "INVALID", "key", -1, -1)]
|
||||
[InlineData("key", "12345", "key", -1, 12345)]
|
||||
public void GetInt32SettingTest(string key, string? value, string expectedKey, int defaultValue, int expectedValue)
|
||||
{
|
||||
Dictionary<string, string?> settings = new() { [key] = value };
|
||||
int actual = Options.GetInt32Setting(settings, expectedKey, defaultValue);
|
||||
Assert.Equal(expectedValue, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("key2", null, "key", null, null)]
|
||||
[InlineData("key", null, "key", null, null)]
|
||||
[InlineData("key", "", "key", null, "")]
|
||||
[InlineData("key", "INVALID", "key", null, "INVALID")]
|
||||
[InlineData("key", "String", "key", null, "String")]
|
||||
public void GetStringSettingTest(string key, string? value, string expectedKey, string? defaultValue, string? expectedValue)
|
||||
{
|
||||
Dictionary<string, string?> settings = new() { [key] = value };
|
||||
string? actual = Options.GetStringSetting(settings, expectedKey, defaultValue);
|
||||
Assert.Equal(expectedValue, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
using MPF.Core.Data;
|
||||
using Xunit;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Core.Data
|
||||
namespace MPF.Frontend.Test
|
||||
{
|
||||
public class ResultTests
|
||||
public class ResultEventArgsTests
|
||||
{
|
||||
[Fact]
|
||||
public void EmptySuccessTest()
|
||||
{
|
||||
var actual = Result.Success();
|
||||
var actual = ResultEventArgs.Success();
|
||||
Assert.True(actual);
|
||||
Assert.Empty(actual.Message);
|
||||
}
|
||||
@@ -17,7 +16,7 @@ namespace MPF.Test.Core.Data
|
||||
public void CustomMessageSuccessTest()
|
||||
{
|
||||
string message = "Success!";
|
||||
var actual = Result.Success(message);
|
||||
var actual = ResultEventArgs.Success(message);
|
||||
Assert.True(actual);
|
||||
Assert.Equal(message, actual.Message);
|
||||
}
|
||||
@@ -25,7 +24,7 @@ namespace MPF.Test.Core.Data
|
||||
[Fact]
|
||||
public void EmptyFailureTest()
|
||||
{
|
||||
var actual = Result.Failure();
|
||||
var actual = ResultEventArgs.Failure();
|
||||
Assert.False(actual);
|
||||
Assert.Empty(actual.Message);
|
||||
}
|
||||
@@ -34,7 +33,7 @@ namespace MPF.Test.Core.Data
|
||||
public void CustomMessageFailureTest()
|
||||
{
|
||||
string message = "Failure!";
|
||||
var actual = Result.Failure(message);
|
||||
var actual = ResultEventArgs.Failure(message);
|
||||
Assert.False(actual);
|
||||
Assert.Equal(message, actual.Message);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user