mirror of
https://github.com/SabreTools/MPF.git
synced 2026-02-04 05:35:52 +00:00
Compare commits
1383 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 | ||
|
|
229db5dda2 | ||
|
|
4f2a8d354a | ||
|
|
b886471d72 | ||
|
|
2bab266ae2 | ||
|
|
6c5fd9bac8 | ||
|
|
08e93d7f13 | ||
|
|
7a510e084b | ||
|
|
da46d20ffc | ||
|
|
234c0bfbab | ||
|
|
82d60dbf4a | ||
|
|
6dffb80609 | ||
|
|
267c0e3184 | ||
|
|
033ccbbe67 | ||
|
|
c31b3f5894 | ||
|
|
9b1a303fea | ||
|
|
80a0f6da35 | ||
|
|
0c30eb7a60 | ||
|
|
7a8125bb71 | ||
|
|
c4beffd845 | ||
|
|
f97c112a53 | ||
|
|
5ef43ab6be | ||
|
|
2c399f99bf | ||
|
|
42e9eb0b96 | ||
|
|
e67d65f908 | ||
|
|
4ec8954b14 | ||
|
|
1a6abb039c | ||
|
|
bb5d1e5ac8 | ||
|
|
03c4c475eb | ||
|
|
04d7817d28 | ||
|
|
7cd100bc53 | ||
|
|
019924232a | ||
|
|
b5fc9f0275 | ||
|
|
44509b72ed | ||
|
|
d532a63dbd | ||
|
|
227785b079 | ||
|
|
0e364be998 | ||
|
|
7ae1f64ee3 | ||
|
|
92463a103d | ||
|
|
101cdb7b34 | ||
|
|
e924299f85 | ||
|
|
b983f7eb4a | ||
|
|
33b4be8b24 | ||
|
|
71a4edc8ba | ||
|
|
ceb305eb54 | ||
|
|
0b0d13dcf3 | ||
|
|
9f02368622 | ||
|
|
152010ee14 | ||
|
|
c6d5f0aea5 | ||
|
|
8c2ad64bb8 | ||
|
|
fa54d694b6 | ||
|
|
dc35b08624 | ||
|
|
4429515ba2 | ||
|
|
fdbc7b34e5 | ||
|
|
a1ab442cf0 | ||
|
|
9ed5c297f6 | ||
|
|
4ce9b214b0 | ||
|
|
7dcdadda75 | ||
|
|
f87a4d9fe2 | ||
|
|
e4e5d173f0 | ||
|
|
115b242d59 | ||
|
|
706bf8a431 | ||
|
|
87ecf1aa99 | ||
|
|
b5cf274333 | ||
|
|
4f4b6879b6 | ||
|
|
3b19463913 | ||
|
|
37386cd182 | ||
|
|
e04bdad16c | ||
|
|
e37f12705d | ||
|
|
5c8dc2c23a | ||
|
|
e9121f3b03 | ||
|
|
d68175db4e | ||
|
|
9d8181b0e2 | ||
|
|
6d657f268a | ||
|
|
3b3c5f823d | ||
|
|
09fc313492 | ||
|
|
316d0f6e54 | ||
|
|
a0033238bd | ||
|
|
5b1c6a7f46 | ||
|
|
8c0dff6552 | ||
|
|
43b230c84a | ||
|
|
f1b657011d | ||
|
|
e4d8ac8e1c | ||
|
|
08f44173dd | ||
|
|
54765c71fd | ||
|
|
01f8b49214 | ||
|
|
e8b0b3efaa | ||
|
|
f637938858 | ||
|
|
ae326c1d2f | ||
|
|
a4a1e6bf0a | ||
|
|
ecee44966e | ||
|
|
83437977ba | ||
|
|
8fcac1d425 | ||
|
|
705b5f1049 | ||
|
|
367d0c104b | ||
|
|
5d4bed2d9e | ||
|
|
63756192d8 | ||
|
|
b68ec78184 | ||
|
|
c55d5183fb | ||
|
|
f82e925944 | ||
|
|
c19f9ea173 | ||
|
|
76b2dd79ab | ||
|
|
c96ff23ad1 | ||
|
|
cd68b55b93 | ||
|
|
cad14d96f7 | ||
|
|
daaf9f1932 | ||
|
|
cb7502b450 | ||
|
|
ece142bbf1 | ||
|
|
611fee4605 | ||
|
|
791e2d0272 | ||
|
|
81742a4676 | ||
|
|
1ff3f2210c | ||
|
|
be9e4b91d5 | ||
|
|
854dcc5f95 | ||
|
|
29b71db33a | ||
|
|
2ee64b222a | ||
|
|
afda54f97b | ||
|
|
ad37c573b6 | ||
|
|
b6cb3104ae | ||
|
|
af9b0dc214 | ||
|
|
b5440032de | ||
|
|
a8e783235c | ||
|
|
fc97fe99e3 | ||
|
|
1c73b1133f | ||
|
|
908eccaafa | ||
|
|
e114d126c5 | ||
|
|
c07b4e4a28 | ||
|
|
06491a6611 | ||
|
|
b9a35850ad | ||
|
|
17a0c5d083 | ||
|
|
1b9523c799 | ||
|
|
ae80ecefc8 | ||
|
|
50ae32e3db | ||
|
|
2d43873398 | ||
|
|
a3df433fef | ||
|
|
35e71d8527 | ||
|
|
c5d07e4be1 | ||
|
|
0df5093b45 | ||
|
|
05d920d095 | ||
|
|
d2f7ac9843 | ||
|
|
857a302aad | ||
|
|
46de589791 | ||
|
|
f14961061c | ||
|
|
453fcf5cb1 | ||
|
|
24cdb27cdb | ||
|
|
24235c5896 | ||
|
|
c226f8cf58 | ||
|
|
b8f6c9f65f | ||
|
|
bb42e2db10 | ||
|
|
db544fd4b7 | ||
|
|
370c6bde5a | ||
|
|
d7965ee37f | ||
|
|
b2c6e07ed1 | ||
|
|
19cef20ceb | ||
|
|
058a1aeeaa | ||
|
|
d185077925 | ||
|
|
e3948ba91b | ||
|
|
4a30f94007 | ||
|
|
1ae27bf9e3 | ||
|
|
bc88103471 | ||
|
|
9ec6fbfe52 | ||
|
|
ebdb8de6b3 | ||
|
|
b8b56f6308 | ||
|
|
0726f5a402 | ||
|
|
90da5d1a7e | ||
|
|
bd3c518fa0 | ||
|
|
44272f60bf | ||
|
|
640ce8d854 | ||
|
|
74732058f2 | ||
|
|
22e480ccd1 | ||
|
|
32a0cb0394 | ||
|
|
88551bc2ed | ||
|
|
039af56f6a | ||
|
|
7a428e2add | ||
|
|
c8dd85eb72 | ||
|
|
7c7a19c5a0 | ||
|
|
9bedd26b24 | ||
|
|
09afdf52fb | ||
|
|
c69afe69dd | ||
|
|
ab18c7920a | ||
|
|
5af1841d13 | ||
|
|
8c324e3b8b | ||
|
|
d99099d587 | ||
|
|
fa7b46a516 | ||
|
|
f7c746b536 | ||
|
|
b6e109133f | ||
|
|
0d694c1bde | ||
|
|
47f45fa46f | ||
|
|
481f4b41d1 | ||
|
|
359ad87faa | ||
|
|
ba47cb7da2 | ||
|
|
8927c49963 | ||
|
|
21f9668093 | ||
|
|
371571d13f | ||
|
|
b231f82c4c | ||
|
|
1741326253 | ||
|
|
1878ef5ad6 | ||
|
|
ae42f5edd7 | ||
|
|
4362ed71e0 | ||
|
|
f02904ea49 | ||
|
|
abf4eb9b7c | ||
|
|
1f942977cc | ||
|
|
7edadd4739 | ||
|
|
cb09816c63 | ||
|
|
48f0a826ca | ||
|
|
9c10842924 | ||
|
|
def499769f | ||
|
|
5e1e61a441 | ||
|
|
4896a12ec5 | ||
|
|
b28ad5d3cd | ||
|
|
4cdbbcedf0 | ||
|
|
6ab63ba651 | ||
|
|
d36c5099f3 | ||
|
|
8ba8347a0c | ||
|
|
4c5184eac5 | ||
|
|
9914b94716 | ||
|
|
150e69eca5 | ||
|
|
f09923974b | ||
|
|
d98bc28930 | ||
|
|
ee4a7ab653 | ||
|
|
6b20aee320 | ||
|
|
a5849325f3 | ||
|
|
86d2d83fbe | ||
|
|
308e0d6937 | ||
|
|
3541bca2d0 | ||
|
|
2496099532 | ||
|
|
6001395181 | ||
|
|
fa2192a284 | ||
|
|
f09155936e | ||
|
|
a07fca6a7b | ||
|
|
5fe7a1dac8 | ||
|
|
16ed2f9595 | ||
|
|
9004d2bc7b | ||
|
|
cc98b38290 | ||
|
|
18ef0cddff | ||
|
|
d9ca55d96c | ||
|
|
816c94de58 | ||
|
|
c2ba58148a | ||
|
|
d9533f2448 | ||
|
|
5126d1854c | ||
|
|
6baaf132a7 | ||
|
|
98a30e6558 | ||
|
|
0912b78568 | ||
|
|
d92a1d566d | ||
|
|
ff40d18ed3 | ||
|
|
4d9cd85ba6 | ||
|
|
b6ae390cee | ||
|
|
4692028cfb | ||
|
|
3ada7db916 | ||
|
|
aa4b2f415d | ||
|
|
56e91bf177 | ||
|
|
228c752585 | ||
|
|
6ce7ccfa91 | ||
|
|
c8c98278b6 | ||
|
|
0fc57c58cf | ||
|
|
3dcac28488 | ||
|
|
4cd7073bf6 | ||
|
|
1af21e7aba | ||
|
|
52adcd0b46 | ||
|
|
8a91593e58 | ||
|
|
729f8273fc | ||
|
|
78df6f6583 | ||
|
|
dc8dae4df7 | ||
|
|
53db9dbf81 | ||
|
|
22755a4af9 | ||
|
|
ba28b414ba | ||
|
|
95d10ecb1e | ||
|
|
c5ab2c747a | ||
|
|
476c494f4e | ||
|
|
758c49c1cc | ||
|
|
d80ad3b3cf | ||
|
|
3d06f80703 | ||
|
|
7344460409 | ||
|
|
19f58d9dde | ||
|
|
ad9f39f832 | ||
|
|
d51117b058 | ||
|
|
0d65d5114a | ||
|
|
30fec3c3d0 | ||
|
|
8eb86fde90 |
4
.editorconfig
Normal file
4
.editorconfig
Normal file
@@ -0,0 +1,4 @@
|
||||
[*.cs]
|
||||
|
||||
# SYSLIB1045: Convert to 'GeneratedRegexAttribute'.
|
||||
dotnet_diagnostic.SYSLIB1045.severity = silent
|
||||
6
.github/ISSUE_TEMPLATE/feature-request.md
vendored
6
.github/ISSUE_TEMPLATE/feature-request.md
vendored
@@ -8,9 +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.
|
||||
- .NET 6.0 has known limitations, so make sure that what you're asking for isn't already in another build.
|
||||
|
||||
- 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...
|
||||
|
||||
8
.github/ISSUE_TEMPLATE/informational.md
vendored
8
.github/ISSUE_TEMPLATE/informational.md
vendored
@@ -8,9 +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.
|
||||
- .NET 6.0 has known limitations, so make sure that what you're giving information on isn't already in another build.
|
||||
|
||||
- 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...
|
||||
@@ -19,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,16 +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.
|
||||
- .NET 6.0 has known issues, please try using another build to reproduce the error
|
||||
|
||||
- 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)
|
||||
@@ -25,14 +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 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",
|
||||
|
||||
15
.vscode/tasks.json
vendored
15
.vscode/tasks.json
vendored
@@ -3,22 +3,11 @@
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"command": "msbuild",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/MPF.sln",
|
||||
"-property:RuntimeIdentifiers=win7-x64"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "publish",
|
||||
"command": "msbuild",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"${workspaceFolder}/MPF/MPF.csproj",
|
||||
"-target:Publish",
|
||||
"-property:RuntimeIdentifiers=win7-x64"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
|
||||
1413
CHANGELIST.md
1413
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,50 +1,50 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net48;net6.0</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win7-x64;win8-x64;win81-x64;win10-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<OutputType>Exe</OutputType>
|
||||
<Title>MPF Check</Title>
|
||||
<AssemblyName>MPF.Check</AssemblyName>
|
||||
<Description>Validator for various dumping programs</Description>
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
<Copyright>Copyright (c)2019-2023</Copyright>
|
||||
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
|
||||
<Version>2.6</Version>
|
||||
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||
<FileVersion>$(Version)</FileVersion>
|
||||
<IncludeSource>true</IncludeSource>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
</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>
|
||||
<NrtRevisionFormat>$(Version)-{chash:8}</NrtRevisionFormat>
|
||||
<NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes>
|
||||
<NrtShowRevision>false</NrtShowRevision>
|
||||
</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>
|
||||
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="2.8.0" GeneratePathProperty="true">
|
||||
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="$(PkgBurnOutSharp)\content\**" PackagePath="contentFiles\any\any;content" CopyToOutputDirectory="Always" PackageCopyToOutput="true" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MPF.Frontend\MPF.Frontend.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
|
||||
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj" />
|
||||
<ProjectReference Include="..\RedumpLib\RedumpLib.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SabreTools.CommandLine" Version="[1.4.0]" />
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="[1.9.0]" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp;
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.Utilities;
|
||||
using MPF.Library;
|
||||
using RedumpLib.Data;
|
||||
using 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
|
||||
{
|
||||
@@ -14,181 +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
|
||||
if (ProcessStandaloneArguments(args))
|
||||
return;
|
||||
|
||||
// Try processing the common arguments
|
||||
(bool success, MediaType mediaType, RedumpSystem? knownSystem) = ProcessCommonArguments(args);
|
||||
if (!success)
|
||||
return;
|
||||
|
||||
// Loop through and process options
|
||||
(Core.Data.Options options, string path, int startIndex) = OptionsLoader.LoadFromArguments(args, startIndex: 2);
|
||||
|
||||
// Make new Progress objects
|
||||
var resultProgress = new Progress<Result>();
|
||||
resultProgress.ProgressChanged += ProgressUpdated;
|
||||
var protectionProgress = new Progress<ProtectionProgress>();
|
||||
protectionProgress.ProgressChanged += ProgressUpdated;
|
||||
|
||||
// Validate the supplied credentials
|
||||
#if NET48 || NETSTANDARD2_1
|
||||
(bool? _, string message) = RedumpWebClient.ValidateCredentials(options?.RedumpUsername, options?.RedumpPassword);
|
||||
#else
|
||||
(bool? _, string message) = RedumpHttpClient.ValidateCredentials(options?.RedumpUsername, options?.RedumpPassword).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++)
|
||||
var topLevel = commandSet.GetTopLevel(featureName);
|
||||
switch (topLevel)
|
||||
{
|
||||
// Check for a file
|
||||
if (!File.Exists(args[i].Trim('"')))
|
||||
{
|
||||
DisplayHelp($"{args[i].Trim('"')} does not exist");
|
||||
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;
|
||||
|
||||
// Get the full file path
|
||||
string filepath = Path.GetFullPath(args[i].Trim('"'));
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Now populate an environment
|
||||
Drive drive = null;
|
||||
if (!string.IsNullOrWhiteSpace(path))
|
||||
drive = Drive.Create(null, path);
|
||||
break;
|
||||
|
||||
var env = new DumpEnvironment(options, filepath, drive, knownSystem, mediaType, internalProgram: null, parameters: null);
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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>
|
||||
private static void DisplayHelp(string error = null)
|
||||
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);
|
||||
|
||||
/// <summary>
|
||||
/// Process common arguments for all functionality
|
||||
/// </summary>
|
||||
/// <returns>True if all arguments pass, false otherwise</returns>
|
||||
private static (bool, MediaType, RedumpSystem?) ProcessCommonArguments(string[] args)
|
||||
{
|
||||
// All other use requires at least 3 arguments
|
||||
if (args.Length < 3)
|
||||
{
|
||||
DisplayHelp("Invalid number of arguments");
|
||||
return (false, MediaType.NONE, null);
|
||||
}
|
||||
// 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 the MediaType
|
||||
var mediaType = EnumConverter.ToMediaType(args[0].Trim('"'));
|
||||
if (mediaType == MediaType.NONE)
|
||||
{
|
||||
DisplayHelp($"{args[0]} is not a recognized media type");
|
||||
return (false, MediaType.NONE, null);
|
||||
}
|
||||
// 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);
|
||||
|
||||
// Check the RedumpSystem
|
||||
var knownSystem = Extensions.ToRedumpSystem(args[1].Trim('"'));
|
||||
if (knownSystem == null)
|
||||
{
|
||||
DisplayHelp($"{args[1]} is not a recognized system");
|
||||
return (false, MediaType.NONE, null);
|
||||
}
|
||||
|
||||
return (true, mediaType, knownSystem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process any standalone arguments for the program
|
||||
/// </summary>
|
||||
/// <returns>True if one of the arguments was processed, false otherwise</returns>
|
||||
private static bool ProcessStandaloneArguments(string[] args)
|
||||
{
|
||||
// Help options
|
||||
if (args.Length == 0 || args[0] == "-h" || args[0] == "-?")
|
||||
{
|
||||
DisplayHelp();
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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>
|
||||
/// Simple process counter to write to console
|
||||
/// </summary>
|
||||
private static void ProgressUpdated(object sender, Result value)
|
||||
{
|
||||
Console.WriteLine(value.Message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple process counter to write to console
|
||||
/// </summary>
|
||||
private static void ProgressUpdated(object sender, ProtectionProgress value)
|
||||
{
|
||||
Console.WriteLine($"{value.Percentage * 100:N2}%: {value.Filename} - {value.Protection}");
|
||||
return commandSet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"profiles": {
|
||||
"MPF.Check": {
|
||||
"commandName": "Project"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Anything marked as internal can be used by the test methods
|
||||
[assembly: InternalsVisibleTo("MPF.Test")]
|
||||
@@ -1,385 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
#if NETFRAMEWORK
|
||||
using IMAPI2;
|
||||
#endif
|
||||
using MPF.Core.Data;
|
||||
using 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;
|
||||
}
|
||||
}
|
||||
|
||||
#if NETFRAMEWORK
|
||||
/// <summary>
|
||||
/// Convert IMAPI physical media type to a MediaType
|
||||
/// </summary>
|
||||
/// <param name="type">IMAPI_MEDIA_PHYSICAL_TYPE value to check</param>
|
||||
/// <returns>MediaType if possible, null on error</returns>
|
||||
public static MediaType? IMAPIToMediaType(this IMAPI_MEDIA_PHYSICAL_TYPE type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_UNKNOWN:
|
||||
return MediaType.NONE;
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_CDROM:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_CDR:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_CDRW:
|
||||
return MediaType.CDROM;
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDROM:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDRAM:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDPLUSR:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDPLUSRW:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDPLUSR_DUALLAYER:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDDASHR:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDDASHRW:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDDASHR_DUALLAYER:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DISK:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDPLUSRW_DUALLAYER:
|
||||
return MediaType.DVD;
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_HDDVDROM:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_HDDVDR:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_HDDVDRAM:
|
||||
return MediaType.HDDVD;
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_BDROM:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_BDR:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_BDRE:
|
||||
return MediaType.BluRay;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region Convert to Long Name
|
||||
|
||||
/// <summary>
|
||||
/// Long name method cache
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<Type, MethodInfo> LongNameMethods = new ConcurrentDictionary<Type, MethodInfo>();
|
||||
|
||||
/// <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 MethodInfo method))
|
||||
{
|
||||
method = typeof(RedumpLib.Data.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;
|
||||
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.DD:
|
||||
return "dd";
|
||||
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>
|
||||
public static InternalProgram ToInternalProgram(string internalProgram)
|
||||
{
|
||||
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 "dd":
|
||||
return InternalProgram.DD;
|
||||
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,120 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using 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 };
|
||||
|
||||
// Private lists of known drive speed ranges
|
||||
private static IReadOnlyList<int> CD { get; } = new List<int> { 1, 2, 3, 4, 6, 8, 12, 16, 20, 24, 32, 40, 44, 48, 52, 56, 72 };
|
||||
private static IReadOnlyList<int> DVD { get; } = CD.Where(s => s <= 24).ToList();
|
||||
private static IReadOnlyList<int> HDDVD { get; } = CD.Where(s => s <= 24).ToList();
|
||||
private static IReadOnlyList<int> BD { get; } = CD.Where(s => s <= 16).ToList();
|
||||
private static IReadOnlyList<int> Unknown { get; } = 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 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,650 +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 MPF.Core.Utilities;
|
||||
using RedumpLib.Data;
|
||||
#if NETFRAMEWORK
|
||||
using IMAPI2;
|
||||
#endif
|
||||
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents information for a single drive
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// TODO: This needs to be less Windows-centric. Devices do not always have a single letter that can be used.
|
||||
/// TODO: Can the Aaru models be used instead of the ones I've created here?
|
||||
/// </remarks>
|
||||
public class Drive
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Represents drive type
|
||||
/// </summary>
|
||||
public InternalDriveType? InternalDriveType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Drive partition format
|
||||
/// </summary>
|
||||
public string DriveFormat { get; private set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Windows drive path
|
||||
/// </summary>
|
||||
public string Name { get; private set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Represents if Windows has marked the drive as active
|
||||
/// </summary>
|
||||
public bool MarkedActive { get; private set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the total size of the drive
|
||||
/// </summary>
|
||||
public long TotalSize { get; private set; } = default;
|
||||
|
||||
/// <summary>
|
||||
/// Media label as read by Windows
|
||||
/// </summary>
|
||||
/// <remarks>The try/catch is needed because Windows will throw an exception if the drive is not marked as active</remarks>
|
||||
public string VolumeLabel { get; private set; } = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Derived Fields
|
||||
|
||||
/// <summary>
|
||||
/// Media label as read by Windows, formatted to avoid odd outputs
|
||||
/// </summary>
|
||||
public string FormattedVolumeLabel
|
||||
{
|
||||
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>
|
||||
/// Windows drive letter
|
||||
/// </summary>
|
||||
public char Letter => this.Name == null || this.Name.Length == 0 ? '\0' : this.Name[0];
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Protected constructor
|
||||
/// </summary>
|
||||
protected Drive() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new Drive object from a drive type and device path
|
||||
/// </summary>
|
||||
/// <param name="driveType">InternalDriveType value representing the drive type</param>
|
||||
/// <param name="devicePath">Path to the device according to the local machine</param>
|
||||
public static Drive Create(InternalDriveType? driveType, string devicePath)
|
||||
{
|
||||
// Create a new, empty drive object
|
||||
var drive = new Drive()
|
||||
{
|
||||
InternalDriveType = driveType,
|
||||
};
|
||||
|
||||
// If we have an invalid device path, return null
|
||||
if (string.IsNullOrWhiteSpace(devicePath))
|
||||
return null;
|
||||
|
||||
// Sanitize a Windows-formatted long device path
|
||||
if (devicePath.StartsWith("\\\\.\\"))
|
||||
devicePath = devicePath.Substring("\\\\.\\".Length);
|
||||
|
||||
// Create and validate the drive info object
|
||||
var driveInfo = new DriveInfo(devicePath);
|
||||
if (driveInfo == null || driveInfo == default)
|
||||
return null;
|
||||
|
||||
// Fill in the rest of the data
|
||||
drive.PopulateFromDriveInfo(driveInfo);
|
||||
|
||||
return drive;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populate all fields from a DriveInfo object
|
||||
/// </summary>
|
||||
/// <param name="driveInfo">DriveInfo object to populate from</param>
|
||||
private void PopulateFromDriveInfo(DriveInfo driveInfo)
|
||||
{
|
||||
// If we have an invalid DriveInfo, just return
|
||||
if (driveInfo == null || driveInfo == default)
|
||||
return;
|
||||
|
||||
// Populate the data fields
|
||||
this.Name = driveInfo.Name;
|
||||
this.MarkedActive = driveInfo.IsReady;
|
||||
if (this.MarkedActive)
|
||||
{
|
||||
this.DriveFormat = driveInfo.DriveFormat;
|
||||
this.TotalSize = driveInfo.TotalSize;
|
||||
this.VolumeLabel = driveInfo.VolumeLabel;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.DriveFormat = string.Empty;
|
||||
this.TotalSize = default;
|
||||
this.VolumeLabel = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
#region Public Functionality
|
||||
|
||||
/// <summary>
|
||||
/// Create a list of active drives matched to their volume labels
|
||||
/// </summary>
|
||||
/// <param name="ignoreFixedDrives">True to ignore fixed drives from population, false otherwise</param>
|
||||
/// <returns>Active drives, matched to labels, if possible</returns>
|
||||
public static List<Drive> CreateListOfDrives(bool ignoreFixedDrives)
|
||||
{
|
||||
var drives = GetDriveList(ignoreFixedDrives);
|
||||
drives = drives?.OrderBy(i => i.Letter)?.ToList();
|
||||
return drives;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current media type from drive letter
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public (MediaType?, string) GetMediaType()
|
||||
{
|
||||
// Take care of the non-optical stuff first
|
||||
// TODO: See if any of these can be more granular, like Optical is
|
||||
if (this.InternalDriveType == Data.InternalDriveType.Floppy)
|
||||
return (MediaType.FloppyDisk, null);
|
||||
else if (this.InternalDriveType == Data.InternalDriveType.HardDisk)
|
||||
return (MediaType.HardDisk, null);
|
||||
else if (this.InternalDriveType == Data.InternalDriveType.Removable)
|
||||
return (MediaType.FlashDrive, null);
|
||||
#if NET6_0_OR_GREATER
|
||||
else
|
||||
return GetMediaTypeFromSize();
|
||||
#endif
|
||||
|
||||
// Get the current drive information
|
||||
string deviceId = null;
|
||||
bool loaded = false;
|
||||
try
|
||||
{
|
||||
// Get the device ID first
|
||||
CimSession session = CimSession.Create(null);
|
||||
var collection = session.QueryInstances("root\\CIMV2", "WQL", $"SELECT * FROM Win32_CDROMDrive WHERE Id = '{this.Letter}:\'");
|
||||
|
||||
foreach (CimInstance instance in collection)
|
||||
{
|
||||
CimKeyedCollection<CimProperty> properties = instance.CimInstanceProperties;
|
||||
deviceId = (string)properties["DeviceID"]?.Value;
|
||||
loaded = (bool)properties["MediaLoaded"]?.Value;
|
||||
}
|
||||
|
||||
// If we got no valid device, we don't care and just return
|
||||
if (deviceId == null)
|
||||
return (null, "Device could not be found");
|
||||
else if (!loaded)
|
||||
return (null, "Device is not reporting media loaded");
|
||||
|
||||
#if NETFRAMEWORK
|
||||
|
||||
MsftDiscMaster2 discMaster = new MsftDiscMaster2();
|
||||
deviceId = deviceId.ToLower().Replace('\\', '#').Replace('/', '#');
|
||||
string id = null;
|
||||
foreach (var disc in discMaster)
|
||||
{
|
||||
if (disc.ToString().Contains(deviceId))
|
||||
id = disc.ToString();
|
||||
}
|
||||
|
||||
// If we couldn't find the drive, we don't care and return
|
||||
if (id == null)
|
||||
return (null, "Device ID could not be found");
|
||||
|
||||
// Create the required objects for reading from the drive
|
||||
MsftDiscRecorder2 recorder = new MsftDiscRecorder2();
|
||||
recorder.InitializeDiscRecorder(id);
|
||||
MsftDiscFormat2Data dataWriter = new MsftDiscFormat2Data();
|
||||
|
||||
// If the recorder is not supported, just return
|
||||
if (!dataWriter.IsRecorderSupported(recorder))
|
||||
return (null, "IMAPI2 recorder not supported");
|
||||
|
||||
// Otherwise, set the recorder to get information from
|
||||
dataWriter.Recorder = recorder;
|
||||
|
||||
var media = dataWriter.CurrentPhysicalMediaType;
|
||||
return (media.IMAPIToMediaType(), null);
|
||||
|
||||
#else
|
||||
|
||||
return (null, "IMAPI2 recorder not supported");
|
||||
|
||||
#endif
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (null, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current system from drive
|
||||
/// </summary>
|
||||
/// <param name="defaultValue"></param>
|
||||
/// <returns></returns>
|
||||
public RedumpSystem? GetRedumpSystem(RedumpSystem? defaultValue)
|
||||
{
|
||||
string drivePath = $"{this.Letter}:\\";
|
||||
|
||||
// If we can't read the media in that drive, we can't do anything
|
||||
if (!Directory.Exists(drivePath))
|
||||
return defaultValue;
|
||||
|
||||
// We're going to assume for floppies, HDDs, and removable drives
|
||||
// TODO: Try to be smarter about this
|
||||
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(drivePath, "*", 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(drivePath, "iXL", "iXLUpdater.exe")))
|
||||
{
|
||||
return RedumpSystem.MattelFisherPriceiXL;
|
||||
}
|
||||
|
||||
// Microsoft Xbox 360
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(drivePath, "$SystemUpdate"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(drivePath, "$SystemUpdate")).Any()
|
||||
&& this.TotalSize <= 500_000_000)
|
||||
{
|
||||
return RedumpSystem.MicrosoftXbox360;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Microsoft Xbox One
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(drivePath, "MSXC"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(drivePath, "MSXC")).Any())
|
||||
{
|
||||
return RedumpSystem.MicrosoftXboxOne;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Sega Dreamcast
|
||||
if (File.Exists(Path.Combine(drivePath, "IP.BIN")))
|
||||
{
|
||||
return RedumpSystem.SegaDreamcast;
|
||||
}
|
||||
|
||||
// Sega Mega-CD / Sega-CD
|
||||
if (File.Exists(Path.Combine(drivePath, "_BOOT", "IP.BIN"))
|
||||
|| File.Exists(Path.Combine(drivePath, "_BOOT", "SP.BIN"))
|
||||
|| File.Exists(Path.Combine(drivePath, "_BOOT", "SP_AS.BIN"))
|
||||
|| File.Exists(Path.Combine(drivePath, "FILESYSTEM.BIN")))
|
||||
{
|
||||
return RedumpSystem.SegaMegaCDSegaCD;
|
||||
}
|
||||
|
||||
// Sega Saturn
|
||||
try
|
||||
{
|
||||
byte[] sector = ReadSector(0);
|
||||
if (sector != null)
|
||||
{
|
||||
if (sector.StartsWith(Interface.SaturnSectorZeroStart))
|
||||
return RedumpSystem.SegaSaturn;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Sony PlayStation and Sony PlayStation 2
|
||||
string psxExePath = Path.Combine(drivePath, "PSX.EXE");
|
||||
string systemCnfPath = Path.Combine(drivePath, "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(drivePath, "PS3_GAME"))
|
||||
|| Directory.Exists(Path.Combine(drivePath, "PS3_UPDATE"))
|
||||
|| File.Exists(Path.Combine(drivePath, "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(drivePath, "PS4", "UPDATE", "PS4UPDATE.PUP")))
|
||||
{
|
||||
return RedumpSystem.SonyPlayStation4;
|
||||
}
|
||||
|
||||
// V.Tech V.Flash / V.Smile Pro
|
||||
if (File.Exists(Path.Combine(drivePath, "0SYSTEM")))
|
||||
{
|
||||
return RedumpSystem.VTechVFlashVSmilePro;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Computers
|
||||
|
||||
// Sharp X68000
|
||||
if (File.Exists(Path.Combine(drivePath, "COMMAND.X")))
|
||||
{
|
||||
return RedumpSystem.SharpX68000;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Video Formats
|
||||
|
||||
// BD-Video
|
||||
if (Directory.Exists(Path.Combine(drivePath, "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(drivePath, "AUDIO_TS"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(drivePath, "AUDIO_TS")).Any())
|
||||
{
|
||||
return RedumpSystem.DVDAudio;
|
||||
}
|
||||
|
||||
else if (Directory.Exists(Path.Combine(drivePath, "VIDEO_TS"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(drivePath, "VIDEO_TS")).Any())
|
||||
{
|
||||
return RedumpSystem.DVDVideo;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// HD-DVD-Video
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(drivePath, "HVDVD_TS"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(drivePath, "HVDVD_TS")).Any())
|
||||
{
|
||||
return RedumpSystem.HDDVDVideo;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// VCD
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(drivePath, "VCD"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(drivePath, "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>
|
||||
/// Read a sector with a specified size from the drive
|
||||
/// </summary>
|
||||
/// <param name="num">Sector number, non-negative</param>
|
||||
/// <param name="size">Size of a sector in bytes</param>
|
||||
/// <returns>Byte array representing the sector, null on error</returns>
|
||||
public byte[] ReadSector(long num, int size = 2048)
|
||||
{
|
||||
// Missing drive leter is not supported
|
||||
if (string.IsNullOrEmpty(this.Name))
|
||||
return null;
|
||||
|
||||
// We don't support negative sectors
|
||||
if (num < 0)
|
||||
return null;
|
||||
|
||||
// Wrap the following in case of device access errors
|
||||
Stream fs = null;
|
||||
try
|
||||
{
|
||||
// Open the drive as a device
|
||||
fs = File.OpenRead($"\\\\?\\{this.Letter}:");
|
||||
|
||||
// Seek to the start of the sector, if possible
|
||||
long start = num * size;
|
||||
fs.Seek(start, SeekOrigin.Begin);
|
||||
|
||||
// Read and return the sector
|
||||
byte[] buffer = new byte[size];
|
||||
fs.Read(buffer, 0, size);
|
||||
return buffer;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
fs?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 the media type for a device path based on size
|
||||
/// </summary>
|
||||
/// <returns>MediaType, null on error</returns>
|
||||
private (MediaType?, string) GetMediaTypeFromSize()
|
||||
{
|
||||
if (this.TotalSize >= 0 && this.TotalSize < 800_000_000 && this.DriveFormat == "CDFS")
|
||||
return (MediaType.CDROM, null);
|
||||
else if (this.TotalSize >= 400_000_000 && this.TotalSize <= 8_540_000_000 && this.DriveFormat == "UDF")
|
||||
return (MediaType.DVD, null);
|
||||
else
|
||||
return (MediaType.BluRay, null);
|
||||
}
|
||||
|
||||
/// <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
|
||||
List<Drive> 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))
|
||||
.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)[0];
|
||||
drives.ForEach(d => { if (d.Letter == devId) { d.InternalDriveType = Data.InternalDriveType.Floppy; } });
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
|
||||
return drives;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Drive type for dumping
|
||||
/// </summary>
|
||||
public enum InternalDriveType
|
||||
{
|
||||
Optical,
|
||||
Floppy,
|
||||
HardDisk,
|
||||
Removable,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Program that is being used to dump media
|
||||
/// </summary>
|
||||
public enum InternalProgram
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
// Dumping support
|
||||
Aaru,
|
||||
DD,
|
||||
DiscImageCreator,
|
||||
Redumper,
|
||||
|
||||
// Verification support only
|
||||
CleanRip,
|
||||
DCDumper,
|
||||
UmdImageCreator,
|
||||
}
|
||||
}
|
||||
@@ -1,296 +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>
|
||||
{
|
||||
private Dictionary<string, string> _keyValuePairs = new Dictionary<string, string>();
|
||||
|
||||
public string this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_keyValuePairs == null)
|
||||
_keyValuePairs = new Dictionary<string, string>();
|
||||
|
||||
key = key.ToLowerInvariant();
|
||||
if (_keyValuePairs.ContainsKey(key))
|
||||
return _keyValuePairs[key];
|
||||
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_keyValuePairs == null)
|
||||
_keyValuePairs = new Dictionary<string, string>();
|
||||
|
||||
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 (StreamReader sr = new StreamReader(stream))
|
||||
{
|
||||
string section = string.Empty;
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
string line = sr.ReadLine().Trim();
|
||||
|
||||
// Comments start with ';'
|
||||
if (line.StartsWith(";"))
|
||||
{
|
||||
// No-op, we don't process comments
|
||||
}
|
||||
|
||||
// Section titles are surrounded by square brackets
|
||||
else if (line.StartsWith("["))
|
||||
{
|
||||
section = line.TrimStart('[').TrimEnd(']');
|
||||
}
|
||||
|
||||
// Valid INI lines are in the format key=value
|
||||
else if (line.Contains("="))
|
||||
{
|
||||
// Split the line by '=' for key-value pairs
|
||||
string[] data = line.Split('=');
|
||||
|
||||
// If the value field contains an '=', we need to put them back in
|
||||
string key = data[0].Trim();
|
||||
string value = string.Join("=", data.Skip(1)).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 (StreamWriter 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)
|
||||
{
|
||||
return ((IDictionary<string, string>)_keyValuePairs).TryGetValue(key.ToLowerInvariant(), out value);
|
||||
}
|
||||
|
||||
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,700 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using MPF.Core.Converters;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
public class Options : IDictionary<string, string>, ICloneable
|
||||
{
|
||||
private readonly Dictionary<string, string> _settings;
|
||||
|
||||
#region Internal Program
|
||||
|
||||
/// <summary>
|
||||
/// Path to Aaru
|
||||
/// </summary>
|
||||
public string AaruPath
|
||||
{
|
||||
get { return GetStringSetting(_settings, "AaruPath", "Programs\\Aaru\\Aaru.exe"); }
|
||||
set { _settings["AaruPath"] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Path to DiscImageCreator
|
||||
/// </summary>
|
||||
public string DiscImageCreatorPath
|
||||
{
|
||||
get { return GetStringSetting(_settings, "DiscImageCreatorPath", "Programs\\Creator\\DiscImageCreator.exe"); }
|
||||
set { _settings["DiscImageCreatorPath"] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Path to dd for Windows
|
||||
/// </summary>
|
||||
public string DDPath
|
||||
{
|
||||
get { return GetStringSetting(_settings, "DDPath", "Programs\\DD\\dd.exe"); }
|
||||
set { _settings["DDPath"] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Path to Redumper
|
||||
/// </summary>
|
||||
public string RedumperPath
|
||||
{
|
||||
get { return GetStringSetting(_settings, "RedumperPath", "Programs\\Redumper\\redumper.exe"); }
|
||||
set { _settings["RedumperPath"] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected dumping program
|
||||
/// </summary>
|
||||
public InternalProgram InternalProgram
|
||||
{
|
||||
get
|
||||
{
|
||||
string valueString = GetStringSetting(_settings, "InternalProgram", InternalProgram.DiscImageCreator.ToString());
|
||||
var valueEnum = EnumConverter.ToInternalProgram(valueString);
|
||||
return valueEnum == InternalProgram.NONE ? InternalProgram.DiscImageCreator : valueEnum;
|
||||
}
|
||||
set
|
||||
{
|
||||
_settings["InternalProgram"] = value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI Defaults
|
||||
|
||||
/// <summary>
|
||||
/// Enable dark mode for UI elements
|
||||
/// </summary>
|
||||
public bool EnableDarkMode
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "EnableDarkMode", false); }
|
||||
set { _settings["EnableDarkMode"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check for updates on startup
|
||||
/// </summary>
|
||||
public bool CheckForUpdatesOnStartup
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "CheckForUpdatesOnStartup", true); }
|
||||
set { _settings["CheckForUpdatesOnStartup"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fast update label - Skips disc checks and updates path only
|
||||
/// </summary>
|
||||
public bool FastUpdateLabel
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "FastUpdateLabel", false); }
|
||||
set { _settings["FastUpdateLabel"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default output path for dumps
|
||||
/// </summary>
|
||||
public string DefaultOutputPath
|
||||
{
|
||||
get { return GetStringSetting(_settings, "DefaultOutputPath", "ISO"); }
|
||||
set { _settings["DefaultOutputPath"] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default system if none can be detected
|
||||
/// </summary>
|
||||
public RedumpSystem? DefaultSystem
|
||||
{
|
||||
get
|
||||
{
|
||||
string valueString = GetStringSetting(_settings, "DefaultSystem", null);
|
||||
var valueEnum = Extensions.ToRedumpSystem(valueString);
|
||||
return valueEnum;
|
||||
}
|
||||
set
|
||||
{
|
||||
_settings["DefaultSystem"] = value.LongName();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default output path for dumps
|
||||
/// </summary>
|
||||
/// <remarks>This is a hidden setting</remarks>
|
||||
public bool ShowDebugViewMenuItem
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "ShowDebugViewMenuItem", false); }
|
||||
set { _settings["ShowDebugViewMenuItem"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dumping Speeds
|
||||
|
||||
/// <summary>
|
||||
/// Default CD dumping speed
|
||||
/// </summary>
|
||||
public int PreferredDumpSpeedCD
|
||||
{
|
||||
get { return GetInt32Setting(_settings, "PreferredDumpSpeedCD", 24); }
|
||||
set { _settings["PreferredDumpSpeedCD"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default DVD dumping speed
|
||||
/// </summary>
|
||||
public int PreferredDumpSpeedDVD
|
||||
{
|
||||
get { return GetInt32Setting(_settings, "PreferredDumpSpeedDVD", 16); }
|
||||
set { _settings["PreferredDumpSpeedDVD"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default HD-DVD dumping speed
|
||||
/// </summary>
|
||||
public int PreferredDumpSpeedHDDVD
|
||||
{
|
||||
get { return GetInt32Setting(_settings, "PreferredDumpSpeedHDDVD", 8); }
|
||||
set { _settings["PreferredDumpSpeedHDDVD"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default BD dumping speed
|
||||
/// </summary>
|
||||
public int PreferredDumpSpeedBD
|
||||
{
|
||||
get { return GetInt32Setting(_settings, "PreferredDumpSpeedBD", 8); }
|
||||
set { _settings["PreferredDumpSpeedBD"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Aaru
|
||||
|
||||
/// <summary>
|
||||
/// Enable debug output while dumping by default
|
||||
/// </summary>
|
||||
public bool AaruEnableDebug
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "AaruEnableDebug", false); }
|
||||
set { _settings["AaruEnableDebug"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable verbose output while dumping by default
|
||||
/// </summary>
|
||||
public bool AaruEnableVerbose
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "AaruEnableVerbose", false); }
|
||||
set { _settings["AaruEnableVerbose"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable force dumping of media by default
|
||||
/// </summary>
|
||||
public bool AaruForceDumping
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "AaruForceDumping", true); }
|
||||
set { _settings["AaruForceDumping"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default number of sector/subchannel rereads
|
||||
/// </summary>
|
||||
public int AaruRereadCount
|
||||
{
|
||||
get { return GetInt32Setting(_settings, "AaruRereadCount", 5); }
|
||||
set { _settings["AaruRereadCount"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strip personal data information from Aaru metadata by default
|
||||
/// </summary>
|
||||
public bool AaruStripPersonalData
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "AaruStripPersonalData", false); }
|
||||
set { _settings["AaruStripPersonalData"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DiscImageCreator
|
||||
|
||||
/// <summary>
|
||||
/// Enable multi-sector read flag by default
|
||||
/// </summary>
|
||||
public bool DICMultiSectorRead
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "DICMultiSectorRead", false); }
|
||||
set { _settings["DICMultiSectorRead"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Include a default multi-sector read value
|
||||
/// </summary>
|
||||
public int DICMultiSectorReadValue
|
||||
{
|
||||
get { return GetInt32Setting(_settings, "DICMultiSectorReadValue", 0); }
|
||||
set { _settings["DICMultiSectorReadValue"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable overly-secure dumping flags by default
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Split this into component parts later. Currently does:
|
||||
/// - Scan sector protection and set subchannel read level to 2 for CD
|
||||
/// - Set scan file protect flag for DVD
|
||||
/// </remarks>
|
||||
public bool DICParanoidMode
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "DICParanoidMode", false); }
|
||||
set { _settings["DICParanoidMode"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable the Quiet flag by default
|
||||
/// </summary>
|
||||
public bool DICQuietMode
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "DICQuietMode", false); }
|
||||
set { _settings["DICQuietMode"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default number of C2 rereads
|
||||
/// </summary>
|
||||
public int DICRereadCount
|
||||
{
|
||||
get { return GetInt32Setting(_settings, "DICRereadCount", 20); }
|
||||
set { _settings["DICRereadCount"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default number of DVD/HD-DVD/BD rereads
|
||||
/// </summary>
|
||||
public int DICDVDRereadCount
|
||||
{
|
||||
get { return GetInt32Setting(_settings, "DICDVDRereadCount", 10); }
|
||||
set { _settings["DICDVDRereadCount"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset drive after dumping (useful for older drives)
|
||||
/// </summary>
|
||||
public bool DICResetDriveAfterDump
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "DICResetDriveAfterDump", false); }
|
||||
set { _settings["DICResetDriveAfterDump"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use the CMI flag for supported disc types
|
||||
/// </summary>
|
||||
public bool DICUseCMIFlag
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "DICUseCMIFlag", false); }
|
||||
set { _settings["DICUseCMIFlag"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Redumper
|
||||
|
||||
/// <summary>
|
||||
/// Enable debug output while dumping by default
|
||||
/// </summary>
|
||||
public bool RedumperEnableDebug
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "RedumperEnableDebug", false); }
|
||||
set { _settings["RedumperEnableDebug"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable verbose output while dumping by default
|
||||
/// </summary>
|
||||
public bool RedumperEnableVerbose
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "RedumperEnableVerbose", false); }
|
||||
set { _settings["RedumperEnableVerbose"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default number of rereads
|
||||
/// </summary>
|
||||
public int RedumperRereadCount
|
||||
{
|
||||
get { return GetInt32Setting(_settings, "RedumperRereadCount", 20); }
|
||||
set { _settings["RedumperRereadCount"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extra Dumping Options
|
||||
|
||||
/// <summary>
|
||||
/// Scan the disc for protection after dumping
|
||||
/// </summary>
|
||||
public bool ScanForProtection
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "ScanForProtection", true); }
|
||||
set { _settings["ScanForProtection"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Output all found protections to a separate file in the directory
|
||||
/// </summary>
|
||||
public bool OutputSeparateProtectionFile
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "OutputSeparateProtectionFile", true); }
|
||||
set { _settings["OutputSeparateProtectionFile"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add placeholder values in the submission info
|
||||
/// </summary>
|
||||
public bool AddPlaceholders
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "AddPlaceholders", true); }
|
||||
set { _settings["AddPlaceholders"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show the disc information window after dumping
|
||||
/// </summary>
|
||||
public bool PromptForDiscInformation
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "PromptForDiscInformation", true); }
|
||||
set { _settings["PromptForDiscInformation"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable tabs in all input fields
|
||||
/// </summary>
|
||||
public bool EnableTabsInInputFields
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "EnableTabsInInputFields", false); }
|
||||
set { _settings["EnableTabsInInputFields"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Limit outputs to Redump-supported values only
|
||||
/// </summary>
|
||||
public bool EnableRedumpCompatibility
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "EnableRedumpCompatibility", true); }
|
||||
set { _settings["EnableRedumpCompatibility"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show disc eject reminder before the disc information window is shown
|
||||
/// </summary>
|
||||
public bool ShowDiscEjectReminder
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "ShowDiscEjectReminder", true); }
|
||||
set { _settings["ShowDiscEjectReminder"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Eject the disc after dumping
|
||||
/// </summary>
|
||||
public bool EjectAfterDump
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "EjectAfterDump", false); }
|
||||
set { _settings["EjectAfterDump"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ignore fixed drives when populating the list
|
||||
/// </summary>
|
||||
public bool IgnoreFixedDrives
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "IgnoreFixedDrives", true); }
|
||||
set { _settings["IgnoreFixedDrives"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show dumping tools in their own window instead of in the log
|
||||
/// </summary>
|
||||
public bool ToolsInSeparateWindow
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "ToolsInSeparateWindow", true); }
|
||||
set { _settings["ToolsInSeparateWindow"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Output the compressed JSON version of the submission info
|
||||
/// </summary>
|
||||
public bool OutputSubmissionJSON
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "OutputSubmissionJSON", false); }
|
||||
set { _settings["OutputSubmissionJSON"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Include log files in serialized JSON data
|
||||
/// </summary>
|
||||
public bool IncludeArtifacts
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "IncludeArtifacts", false); }
|
||||
set { _settings["IncludeArtifacts"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compress output log files to reduce space
|
||||
/// </summary>
|
||||
public bool CompressLogFiles
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "CompressLogFiles", true); }
|
||||
set { _settings["CompressLogFiles"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Skip Options
|
||||
|
||||
/// <summary>
|
||||
/// Skip detecting media type on disc scan
|
||||
/// </summary>
|
||||
public bool SkipMediaTypeDetection
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "SkipMediaTypeDetection", false); }
|
||||
set { _settings["SkipMediaTypeDetection"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Skip detecting known system on disc scan
|
||||
/// </summary>
|
||||
public bool SkipSystemDetection
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "SkipSystemDetection", false); }
|
||||
set { _settings["SkipSystemDetection"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protection Scanning Options
|
||||
|
||||
/// <summary>
|
||||
/// Scan archive contents during protection scanning
|
||||
/// </summary>
|
||||
public bool ScanArchivesForProtection
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "ScanArchivesForProtection", true); }
|
||||
set { _settings["ScanArchivesForProtection"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scan for executable packers during protection scanning
|
||||
/// </summary>
|
||||
public bool ScanPackersForProtection
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "ScanPackersForProtection", false); }
|
||||
set { _settings["ScanPackersForProtection"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Include debug information with scan results
|
||||
/// </summary>
|
||||
public bool IncludeDebugProtectionInformation
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "IncludeDebugProtectionInformation", false); }
|
||||
set { _settings["IncludeDebugProtectionInformation"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Logging Options
|
||||
|
||||
/// <summary>
|
||||
/// Enable verbose and debug logs to be written
|
||||
/// </summary>
|
||||
public bool VerboseLogging
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "VerboseLogging", true); }
|
||||
set { _settings["VerboseLogging"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Have the log panel expanded by default on startup
|
||||
/// </summary>
|
||||
public bool OpenLogWindowAtStartup
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "OpenLogWindowAtStartup", true); }
|
||||
set { _settings["OpenLogWindowAtStartup"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable fancy formatting of log statements
|
||||
/// Disables EnableProgressProcessing if disabled
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is mainly for outputting redirected console outputs. Not many
|
||||
/// other bits of the logs include any specially handled outputs.
|
||||
/// </remarks>
|
||||
public bool EnableLogFormatting
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "EnableLogFormatting", false); }
|
||||
set { _settings["EnableLogFormatting"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable progress bar updating based on log text
|
||||
/// Disabled if EnableLogFormatting is disabled
|
||||
/// </summary>
|
||||
public bool EnableProgressProcessing
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "EnableProgressProcessing", false); }
|
||||
set { _settings["EnableProgressProcessing"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Redump Login Information
|
||||
|
||||
public string RedumpUsername
|
||||
{
|
||||
get { return GetStringSetting(_settings, "RedumpUsername", ""); }
|
||||
set { _settings["RedumpUsername"] = value; }
|
||||
}
|
||||
|
||||
// TODO: Figure out a way to keep this encrypted in some way, BASE64 to start?
|
||||
public string RedumpPassword
|
||||
{
|
||||
get { return GetStringSetting(_settings, "RedumpPassword", ""); }
|
||||
set { _settings["RedumpPassword"] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if a complete set of Redump credentials might exist
|
||||
/// </summary>
|
||||
public bool HasRedumpLogin { get => !string.IsNullOrWhiteSpace(RedumpUsername) && !string.IsNullOrWhiteSpace(RedumpPassword); }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor taking a dictionary for settings
|
||||
/// </summary>
|
||||
/// <param name="settings"></param>
|
||||
public Options(Dictionary<string, string> settings = null)
|
||||
{
|
||||
this._settings = settings ?? new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a clone of the object
|
||||
/// </summary>
|
||||
public object Clone()
|
||||
{
|
||||
return new Options(new Dictionary<string, string>(_settings));
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Get a Boolean setting from a settings, dictionary
|
||||
/// </summary>
|
||||
/// <param name="settings">Dictionary representing the settings</param>
|
||||
/// <param name="key">Setting key to get a value for</param>
|
||||
/// <param name="defaultValue">Default value to return if no value is found</param>
|
||||
/// <returns>Setting value if possible, default value otherwise</returns>
|
||||
private bool GetBooleanSetting(Dictionary<string, string> settings, string key, bool defaultValue)
|
||||
{
|
||||
if (settings.ContainsKey(key))
|
||||
{
|
||||
if (Boolean.TryParse(settings[key], out bool value))
|
||||
return value;
|
||||
else
|
||||
return defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an Int32 setting from a settings, dictionary
|
||||
/// </summary>
|
||||
/// <param name="settings">Dictionary representing the settings</param>
|
||||
/// <param name="key">Setting key to get a value for</param>
|
||||
/// <param name="defaultValue">Default value to return if no value is found</param>
|
||||
/// <returns>Setting value if possible, default value otherwise</returns>
|
||||
private int GetInt32Setting(Dictionary<string, string> settings, string key, int defaultValue)
|
||||
{
|
||||
if (settings.ContainsKey(key))
|
||||
{
|
||||
if (Int32.TryParse(settings[key], out int value))
|
||||
return value;
|
||||
else
|
||||
return defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a String setting from a settings, dictionary
|
||||
/// </summary>
|
||||
/// <param name="settings">Dictionary representing the settings</param>
|
||||
/// <param name="key">Setting key to get a value for</param>
|
||||
/// <param name="defaultValue">Default value to return if no value is found</param>
|
||||
/// <returns>Setting value if possible, default value otherwise</returns>
|
||||
private string GetStringSetting(Dictionary<string, string> settings, string key, string defaultValue)
|
||||
{
|
||||
if (settings.ContainsKey(key))
|
||||
return settings[key];
|
||||
else
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDictionary implementations
|
||||
|
||||
public ICollection<string> Keys => _settings.Keys;
|
||||
|
||||
public ICollection<string> Values => _settings.Values;
|
||||
|
||||
public int Count => _settings.Count;
|
||||
|
||||
public bool IsReadOnly => ((IDictionary<string, string>)_settings).IsReadOnly;
|
||||
|
||||
public string this[string key]
|
||||
{
|
||||
get { return (_settings.ContainsKey(key) ? _settings[key] : null); }
|
||||
set { _settings[key] = value; }
|
||||
}
|
||||
|
||||
public bool ContainsKey(string key) => _settings.ContainsKey(key);
|
||||
|
||||
public void Add(string key, string value) => _settings.Add(key, value);
|
||||
|
||||
public bool Remove(string key) => _settings.Remove(key);
|
||||
|
||||
public bool TryGetValue(string key, out string value) => _settings.TryGetValue(key, out value);
|
||||
|
||||
public void Add(KeyValuePair<string, string> item) => _settings.Add(item.Key, item.Value);
|
||||
|
||||
public void Clear() => _settings.Clear();
|
||||
|
||||
public bool Contains(KeyValuePair<string, string> item) => ((IDictionary<string, string>)_settings).Contains(item);
|
||||
|
||||
public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex) => ((IDictionary<string, string>)_settings).CopyTo(array, arrayIndex);
|
||||
|
||||
public bool Remove(KeyValuePair<string, string> item) => ((IDictionary<string, string>)_settings).Remove(item);
|
||||
|
||||
public IEnumerator<KeyValuePair<string, string>> GetEnumerator() => _settings.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => _settings.GetEnumerator();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Disc Information and Emergency Brake data shall be read from the PIC zone. DI units that
|
||||
/// contain physical information shall be returned.Emergency Brake data shall be returned.The
|
||||
/// information shall be collected from the layer specified in the Layer field of the CDB. If any data
|
||||
/// can be returned, 4 100 bytes shall be returned.
|
||||
/// </summary>
|
||||
/// <see href="https://www.t10.org/ftp/t10/document.05/05-206r0.pdf"/>
|
||||
/// <see href="https://github.com/aaru-dps/Aaru.Decoders/blob/devel/Bluray/DI.cs"/>
|
||||
public class PICDiscInformation
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// 2048 bytes for BD-ROM, 3584 bytes for BD-R/RE
|
||||
/// </summary>
|
||||
/// <remarks>Big-endian format</remarks>
|
||||
public ushort DataStructureLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Should be 0x00
|
||||
/// </summary>
|
||||
public byte Reserved0 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Should be 0x00
|
||||
/// </summary>
|
||||
public byte Reserved1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Disc information and emergency brake units
|
||||
/// </summary>
|
||||
public PICDiscInformationUnit[] Units { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
/// <see href="https://www.t10.org/ftp/t10/document.05/05-206r0.pdf"/>
|
||||
/// <see href="https://github.com/aaru-dps/Aaru.Decoders/blob/devel/Bluray/DI.cs"/>
|
||||
public class PICDiscInformationUnit
|
||||
{
|
||||
#region Fields
|
||||
|
||||
#region Header
|
||||
|
||||
/// <summary>
|
||||
/// Disc Information Identifier "DI"
|
||||
/// Emergency Brake Identifier "EB"
|
||||
/// </summary>
|
||||
public string DiscInformationIdentifier { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Disc Information Format
|
||||
/// </summary>
|
||||
public byte DiscInformationFormat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of DI units in each DI block
|
||||
/// </summary>
|
||||
public byte NumberOfUnitsInBlock { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Should be 0x00
|
||||
/// </summary>
|
||||
public byte Reserved0 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// DI unit Sequence Number
|
||||
/// </summary>
|
||||
public byte SequenceNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of bytes in use in this DI unit
|
||||
/// </summary>
|
||||
public byte BytesInUse { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Should be 0x00
|
||||
/// </summary>
|
||||
public byte Reserved1 { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
// TODO: Write models for the dependent contents, if possible
|
||||
#region Body
|
||||
|
||||
/// <summary>
|
||||
/// Disc Type Identifier
|
||||
/// = "BDO" for BD-ROM
|
||||
/// = "BDU" for BD-ROM Ultra
|
||||
/// = "BDW" for BD-RE
|
||||
/// = "BDR" for BD-R
|
||||
/// </summary>
|
||||
public string DiscTypeIdentifier { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Disc Size/Class/Version
|
||||
/// </summary>
|
||||
public byte DiscSizeClassVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// DI Unit Format dependent contents
|
||||
/// </summary>
|
||||
/// <remarks>52 bytes for BD-ROM, 100 bytes for BD-R/RE</remarks>
|
||||
public byte[] FormatDependentContents { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Trailer (BD-R/RE only)
|
||||
|
||||
/// <summary>
|
||||
/// Disc Manufacturer ID
|
||||
/// </summary>
|
||||
/// <remarks>6 bytes</remarks>
|
||||
public byte[] DiscManufacturerID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Media Type ID
|
||||
/// </summary>
|
||||
/// <remarks>3 bytes</remarks>
|
||||
public byte[] MediaTypeID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Time Stamp
|
||||
/// </summary>
|
||||
public ushort TimeStamp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Product Revision Number
|
||||
/// </summary>
|
||||
public byte ProductRevisionNumber { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constants
|
||||
|
||||
public const string DiscTypeIdentifierROM = "BDO";
|
||||
|
||||
public const string DiscTypeIdentifierROMUltra = "BDU";
|
||||
|
||||
public const string DiscTypeIdentifierReWritable = "BDW";
|
||||
|
||||
public const string DiscTypeIdentifierRecordable = "BDR";
|
||||
|
||||
#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 (!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 T nextItem))
|
||||
continue;
|
||||
|
||||
// Invoke the lambda, if possible
|
||||
this.CustomProcessing?.Invoke(nextItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,423 +0,0 @@
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains information specific to an XGD disc
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// XGD1 XMID Format Information:
|
||||
///
|
||||
/// AABBBCCD
|
||||
/// - AA => The two-ASCII-character publisher identifier (see GetPublisher for details)
|
||||
/// - BBB => Game ID
|
||||
/// - CC => Version number
|
||||
/// - D => Region identifier (see GetRegion for details)
|
||||
///
|
||||
/// XGD2/3 XeMID Format Information:
|
||||
///
|
||||
/// AABCCCDDEFFGHH(IIIIIIII)
|
||||
/// - AA => The two-ASCII-character publisher identifier (see GetPublisher for details)
|
||||
/// - B => Platform identifier; 2 indicates Xbox 360.
|
||||
/// - CCC => Game ID
|
||||
/// - DD => SKU number (unique per SKU of a title)
|
||||
/// - E => Region identifier (see GetRegion for details)
|
||||
/// - FF => Base version; usually starts at 01 (can be 1 or 2 characters)
|
||||
/// - G => Media type identifier (see GetMediaSubtype for details)
|
||||
/// - HH => Disc number stored in [disc number][total discs] format
|
||||
/// - IIIIIIII => 8-hex-digit certification submission identifier; usually on test discs only
|
||||
/// </remarks>
|
||||
public class XgdInfo
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the information in this object is fully instantiated or not
|
||||
/// </summary>
|
||||
public bool Initialized { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Raw XMID/XeMID string that all other information is derived from
|
||||
/// </summary>
|
||||
public string XMID { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 2-character publisher identifier
|
||||
/// </summary>
|
||||
public string PublisherIdentifier { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Platform disc is made for, 2 indicates Xbox 360
|
||||
/// </summary>
|
||||
public char? PlatformIdentifier { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Game ID
|
||||
/// </summary>
|
||||
public string GameID { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// For XGD1: Internal version number
|
||||
/// For XGD2/3: Title-specific SKU
|
||||
/// </summary>
|
||||
public string SKU { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Region identifier character
|
||||
/// </summary>
|
||||
public char RegionIdentifier { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Base version of executables, usually starts at 01
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// TODO: Check if this is always 2 characters for XGD2/3
|
||||
/// </remarks>
|
||||
public string BaseVersion { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Media subtype identifier
|
||||
/// </summary>
|
||||
public char MediaSubtypeIdentifier { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Disc number stored in [disc number][total discs] format
|
||||
/// </summary>
|
||||
public string DiscNumberIdentifier { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 8-hex-digit certification submission identifier; usually on test discs only
|
||||
/// </summary>
|
||||
public string CertificationSubmissionIdentifier { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Auto-Generated Information
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable name derived from the publisher identifier
|
||||
/// </summary>
|
||||
public string PublisherName => GetPublisher(this.PublisherIdentifier);
|
||||
|
||||
/// <summary>
|
||||
/// Internally represented region
|
||||
/// </summary>
|
||||
public Region? InternalRegion => GetRegion(this.RegionIdentifier);
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable subtype derived from the media identifier
|
||||
/// </summary>
|
||||
public string MediaSubtype => GetMediaSubtype(this.MediaSubtypeIdentifier);
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Populate a set of XGD information from a Master ID (XMID/XeMID) string
|
||||
/// </summary>
|
||||
/// <param name="xmid">XMID/XeMID string representing the DMI information</param>
|
||||
/// <param name="validate">True if value validation should be performed, false otherwise</param>
|
||||
public XgdInfo(string xmid, bool validate = false)
|
||||
{
|
||||
this.Initialized = false;
|
||||
if (string.IsNullOrWhiteSpace(xmid))
|
||||
return;
|
||||
|
||||
this.XMID = xmid.TrimEnd('\0');
|
||||
if (string.IsNullOrWhiteSpace(this.XMID))
|
||||
return;
|
||||
|
||||
// XGD1 information is 8 characters
|
||||
if (this.XMID.Length == 8)
|
||||
this.Initialized = ParseXGD1XMID(this.XMID, validate);
|
||||
|
||||
// XGD2/3 information is semi-variable length
|
||||
else if (this.XMID.Length == 13 || this.XMID.Length == 14 || this.XMID.Length == 21 || this.XMID.Length == 22)
|
||||
this.Initialized = ParseXGD23XeMID(this.XMID, validate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the human-readable serial string
|
||||
/// </summary>
|
||||
/// <returns>Formatted serial string, null on error</returns>
|
||||
public string GetSerial()
|
||||
{
|
||||
if (!this.Initialized)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
// XGD1 doesn't use PlatformIdentifier
|
||||
if (this.PlatformIdentifier == null)
|
||||
return $"{this.PublisherIdentifier}-{this.GameID}";
|
||||
|
||||
// XGD2/3 uses a specific identifier
|
||||
else if (this.PlatformIdentifier == '2')
|
||||
return $"{this.PublisherIdentifier}-{this.PlatformIdentifier}{this.GameID}";
|
||||
|
||||
return null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the human-readable version string
|
||||
/// </summary>
|
||||
/// <returns>Formatted version string, null on error</returns>
|
||||
/// <remarks>This may differ for XGD2/3 in the future</remarks>
|
||||
public string GetVersion()
|
||||
{
|
||||
if (!this.Initialized)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
// XGD1 doesn't use PlatformIdentifier
|
||||
if (this.PlatformIdentifier == null)
|
||||
return $"1.{this.SKU}";
|
||||
|
||||
// XGD2/3 uses a specific identifier
|
||||
else if (this.PlatformIdentifier == '2')
|
||||
return $"1.{this.SKU}";
|
||||
|
||||
return null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse an XGD1 XMID string
|
||||
/// </summary>
|
||||
/// <param name="xmid">XMID string to attempt to parse</param>
|
||||
/// <param name="validate">True if value validation should be performed, false otherwise</param>
|
||||
/// <returns>True if the XMID could be parsed, false otherwise</returns>
|
||||
private bool ParseXGD1XMID(string xmid, bool validate)
|
||||
{
|
||||
if (xmid == null || xmid.Length != 8)
|
||||
return false;
|
||||
|
||||
this.PublisherIdentifier = xmid.Substring(0, 2);
|
||||
if (validate && string.IsNullOrEmpty(this.PublisherName))
|
||||
return false;
|
||||
|
||||
this.GameID = xmid.Substring(2, 3);
|
||||
this.SKU = xmid.Substring(5, 2);
|
||||
this.RegionIdentifier = xmid[7];
|
||||
if (validate && this.InternalRegion == null)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse an XGD2/3 XeMID string
|
||||
/// </summary>
|
||||
/// <param name="xemid">XeMID string to attempt to parse</param>
|
||||
/// <param name="validate">True if value validation should be performed, false otherwise</param>
|
||||
/// <returns>True if the XeMID could be parsed, false otherwise</returns>
|
||||
private bool ParseXGD23XeMID(string xemid, bool validate)
|
||||
{
|
||||
if (xemid == null
|
||||
|| (xemid.Length != 13 && xemid.Length != 14
|
||||
&& xemid.Length != 21 && xemid.Length != 22))
|
||||
return false;
|
||||
|
||||
this.PublisherIdentifier = xemid.Substring(0, 2);
|
||||
if (validate && string.IsNullOrEmpty(this.PublisherName))
|
||||
return false;
|
||||
|
||||
this.PlatformIdentifier = xemid[2];
|
||||
if (validate && this.PlatformIdentifier != '2')
|
||||
return false;
|
||||
|
||||
this.GameID = xemid.Substring(3, 3);
|
||||
this.SKU = xemid.Substring(6, 2);
|
||||
this.RegionIdentifier = xemid[8];
|
||||
if (validate && this.InternalRegion == null)
|
||||
return false;
|
||||
|
||||
if (xemid.Length == 13 || xemid.Length == 21)
|
||||
{
|
||||
this.BaseVersion = xemid.Substring(9, 1);
|
||||
this.MediaSubtypeIdentifier = xemid[10];
|
||||
if (validate && string.IsNullOrEmpty(this.MediaSubtype))
|
||||
return false;
|
||||
|
||||
this.DiscNumberIdentifier = xemid.Substring(11, 2);
|
||||
}
|
||||
else if (xemid.Length == 14 || xemid.Length == 22)
|
||||
{
|
||||
this.BaseVersion = xemid.Substring(9, 2);
|
||||
this.MediaSubtypeIdentifier = xemid[11];
|
||||
if (validate && string.IsNullOrEmpty(this.MediaSubtype))
|
||||
return false;
|
||||
|
||||
this.DiscNumberIdentifier = xemid.Substring(12, 2);
|
||||
}
|
||||
|
||||
if (xemid.Length == 21)
|
||||
this.CertificationSubmissionIdentifier = xemid.Substring(13);
|
||||
else if (xemid.Length == 22)
|
||||
this.CertificationSubmissionIdentifier = xemid.Substring(14);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Determine the XGD type based on the XGD2/3 media type identifier character
|
||||
/// </summary>
|
||||
/// <param name="mediaTypeIdentifier">Character denoting the media type</param>
|
||||
/// <returns>Media subtype as a string, if possible</returns>
|
||||
private static string GetMediaSubtype(char mediaTypeIdentifier)
|
||||
{
|
||||
switch (mediaTypeIdentifier)
|
||||
{
|
||||
case 'F': return "XGD3";
|
||||
case 'X': return "XGD2";
|
||||
case 'Z': return "Games on Demand / Marketplace Demo";
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the full name of the publisher from the 2-character identifier
|
||||
/// </summary>
|
||||
/// <param name="publisherIdentifier">Case-sensitive 2-character identifier</param>
|
||||
/// <returns>Publisher name, if possible</returns>
|
||||
/// <see cref="https://xboxdevwiki.net/Xbe#Title_ID"/>
|
||||
private static string GetPublisher(string publisherIdentifier)
|
||||
{
|
||||
switch (publisherIdentifier)
|
||||
{
|
||||
case "AC": return "Acclaim Entertainment";
|
||||
case "AH": return "ARUSH Entertainment";
|
||||
case "AQ": return "Aqua System";
|
||||
case "AS": return "ASK";
|
||||
case "AT": return "Atlus";
|
||||
case "AV": return "Activision";
|
||||
case "AY": return "Aspyr Media";
|
||||
case "BA": return "Bandai";
|
||||
case "BL": return "Black Box";
|
||||
case "BM": return "BAM! Entertainment";
|
||||
case "BR": return "Broccoli Co.";
|
||||
case "BS": return "Bethesda Softworks";
|
||||
case "BU": return "Bunkasha Co.";
|
||||
case "BV": return "Buena Vista Games";
|
||||
case "BW": return "BBC Multimedia";
|
||||
case "BZ": return "Blizzard";
|
||||
case "CC": return "Capcom";
|
||||
case "CK": return "Kemco Corporation"; // TODO: Confirm
|
||||
case "CM": return "Codemasters";
|
||||
case "CV": return "Crave Entertainment";
|
||||
case "DC": return "DreamCatcher Interactive";
|
||||
case "DX": return "Davilex";
|
||||
case "EA": return "Electronic Arts (EA)";
|
||||
case "EC": return "Encore inc";
|
||||
case "EL": return "Enlight Software";
|
||||
case "EM": return "Empire Interactive";
|
||||
case "ES": return "Eidos Interactive";
|
||||
case "FI": return "Fox Interactive";
|
||||
case "FS": return "From Software";
|
||||
case "GE": return "Genki Co.";
|
||||
case "GV": return "Groove Games";
|
||||
case "HE": return "Tru Blu (Entertainment division of Home Entertainment Suppliers)";
|
||||
case "HP": return "Hip games";
|
||||
case "HU": return "Hudson Soft";
|
||||
case "HW": return "Highwaystar";
|
||||
case "IA": return "Mad Catz Interactive";
|
||||
case "IF": return "Idea Factory";
|
||||
case "IG": return "Infogrames";
|
||||
case "IL": return "Interlex Corporation";
|
||||
case "IM": return "Imagine Media";
|
||||
case "IO": return "Ignition Entertainment";
|
||||
case "IP": return "Interplay Entertainment";
|
||||
case "IX": return "InXile Entertainment"; // TODO: Confirm
|
||||
case "JA": return "Jaleco";
|
||||
case "JW": return "JoWooD";
|
||||
case "KB": return "Kemco"; // TODO: Confirm
|
||||
case "KI": return "Kids Station Inc."; // TODO: Confirm
|
||||
case "KN": return "Konami";
|
||||
case "KO": return "KOEI";
|
||||
case "KU": return "Kobi and / or GAE (formerly Global A Entertainment)"; // TODO: Confirm
|
||||
case "LA": return "LucasArts";
|
||||
case "LS": return "Black Bean Games (publishing arm of Leader S.p.A.)";
|
||||
case "MD": return "Metro3D";
|
||||
case "ME": return "Medix";
|
||||
case "MI": return "Microïds";
|
||||
case "MJ": return "Majesco Entertainment";
|
||||
case "MM": return "Myelin Media";
|
||||
case "MP": return "MediaQuest"; // TODO: Confirm
|
||||
case "MS": return "Microsoft Game Studios";
|
||||
case "MW": return "Midway Games";
|
||||
case "MX": return "Empire Interactive"; // TODO: Confirm
|
||||
case "NK": return "NewKidCo";
|
||||
case "NL": return "NovaLogic";
|
||||
case "NM": return "Namco";
|
||||
case "OX": return "Oxygen Interactive";
|
||||
case "PC": return "Playlogic Entertainment";
|
||||
case "PL": return "Phantagram Co., Ltd.";
|
||||
case "RA": return "Rage";
|
||||
case "SA": return "Sammy";
|
||||
case "SC": return "SCi Games";
|
||||
case "SE": return "SEGA";
|
||||
case "SN": return "SNK";
|
||||
case "SS": return "Simon & Schuster";
|
||||
case "SU": return "Success Corporation";
|
||||
case "SW": return "Swing! Deutschland";
|
||||
case "TA": return "Takara";
|
||||
case "TC": return "Tecmo";
|
||||
case "TD": return "The 3DO Company (or just 3DO)";
|
||||
case "TK": return "Takuyo";
|
||||
case "TM": return "TDK Mediactive";
|
||||
case "TQ": return "THQ";
|
||||
case "TS": return "Titus Interactive";
|
||||
case "TT": return "Take-Two Interactive Software";
|
||||
case "US": return "Ubisoft";
|
||||
case "VC": return "Victor Interactive Software";
|
||||
case "VN": return "Vivendi Universal (just took Interplays publishing rights)"; // TODO: Confirm
|
||||
case "VU": return "Vivendi Universal Games";
|
||||
case "VV": return "Vivendi Universal Games"; // TODO: Confirm
|
||||
case "WE": return "Wanadoo Edition";
|
||||
case "WR": return "Warner Bros. Interactive Entertainment"; // TODO: Confirm
|
||||
case "XI": return "XPEC Entertainment and Idea Factory";
|
||||
case "XK": return "Xbox kiosk disk?"; // TODO: Confirm
|
||||
case "XL": return "Xbox special bundled or live demo disk?"; // TODO: Confirm
|
||||
case "XM": return "Evolved Games"; // TODO: Confirm
|
||||
case "XP": return "XPEC Entertainment";
|
||||
case "XR": return "Panorama";
|
||||
case "YB": return "YBM Sisa (South-Korea)";
|
||||
case "ZD": return "Zushi Games (formerly Zoo Digital Publishing)";
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine the region based on the XGD serial character
|
||||
/// </summary>
|
||||
/// <param name="region">Character denoting the region</param>
|
||||
/// <returns>Region, if possible</returns>
|
||||
private static Region? GetRegion(char region)
|
||||
{
|
||||
switch (region)
|
||||
{
|
||||
case 'W': return Region.World;
|
||||
case 'A': return Region.UnitedStatesOfAmerica;
|
||||
case 'J': return Region.JapanAsia;
|
||||
case 'E': return Region.Europe;
|
||||
case 'K': return Region.USAJapan;
|
||||
case 'L': return Region.USAEurope;
|
||||
case 'H': return Region.JapanEurope;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace MPF.Core.Hashing
|
||||
{
|
||||
/// <summary>
|
||||
/// Available hashing types
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum Hash
|
||||
{
|
||||
CRC = 1 << 0,
|
||||
MD5 = 1 << 1,
|
||||
SHA1 = 1 << 2,
|
||||
SHA256 = 1 << 3,
|
||||
SHA384 = 1 << 4,
|
||||
SHA512 = 1 << 5,
|
||||
|
||||
// Special combinations
|
||||
Standard = CRC | MD5 | SHA1,
|
||||
All = CRC | MD5 | SHA1 | SHA256 | SHA384 | SHA512,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Async hashing class wraper
|
||||
/// </summary>
|
||||
public class Hasher
|
||||
{
|
||||
public Hash HashType { get; private set; }
|
||||
private IDisposable _hasher;
|
||||
|
||||
public Hasher(Hash hashType)
|
||||
{
|
||||
this.HashType = hashType;
|
||||
GetHasher();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the correct hashing class based on the hash type
|
||||
/// </summary>
|
||||
private void GetHasher()
|
||||
{
|
||||
switch (HashType)
|
||||
{
|
||||
case Hash.CRC:
|
||||
_hasher = new OptimizedCRC();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_hasher.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process a buffer of some length with the internal hash algorithm
|
||||
/// </summary>
|
||||
public void Process(byte[] buffer, int size)
|
||||
{
|
||||
switch (HashType)
|
||||
{
|
||||
case Hash.CRC:
|
||||
(_hasher as OptimizedCRC).Update(buffer, 0, size);
|
||||
break;
|
||||
|
||||
case Hash.MD5:
|
||||
case Hash.SHA1:
|
||||
case Hash.SHA256:
|
||||
case Hash.SHA384:
|
||||
case Hash.SHA512:
|
||||
(_hasher as HashAlgorithm).TransformBlock(buffer, 0, size, null, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalize the internal hash algorigthm
|
||||
/// </summary>
|
||||
public void Terminate()
|
||||
{
|
||||
byte[] emptyBuffer = new byte[0];
|
||||
switch (HashType)
|
||||
{
|
||||
case Hash.CRC:
|
||||
(_hasher as OptimizedCRC).Update(emptyBuffer, 0, 0);
|
||||
break;
|
||||
|
||||
case Hash.MD5:
|
||||
case Hash.SHA1:
|
||||
case Hash.SHA256:
|
||||
case Hash.SHA384:
|
||||
case Hash.SHA512:
|
||||
(_hasher as HashAlgorithm).TransformFinalBlock(emptyBuffer, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get internal hash as a byte array
|
||||
/// </summary>
|
||||
public byte[] GetHash()
|
||||
{
|
||||
switch (HashType)
|
||||
{
|
||||
case Hash.CRC:
|
||||
return BitConverter.GetBytes((_hasher as OptimizedCRC).Value).Reverse().ToArray();
|
||||
|
||||
case Hash.MD5:
|
||||
case Hash.SHA1:
|
||||
case Hash.SHA256:
|
||||
case Hash.SHA384:
|
||||
case Hash.SHA512:
|
||||
return (_hasher as HashAlgorithm).Hash;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get internal hash as a string
|
||||
/// </summary>
|
||||
public string GetHashString()
|
||||
{
|
||||
byte[] hash = GetHash();
|
||||
if (hash == null)
|
||||
return null;
|
||||
|
||||
return ByteArrayToString(hash);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
private static string ByteArrayToString(byte[] bytes)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2012-2015 Eugene Larchenko (spct@mail.ru)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
//namespace OptimizedCRC
|
||||
namespace MPF.Core.Hashing
|
||||
{
|
||||
internal class OptimizedCRC : IDisposable
|
||||
{
|
||||
private const uint kCrcPoly = 0xEDB88320;
|
||||
private const uint kInitial = 0xFFFFFFFF;
|
||||
private const int CRC_NUM_TABLES = 8;
|
||||
private static readonly uint[] Table;
|
||||
|
||||
static OptimizedCRC()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
Table = new uint[256 * CRC_NUM_TABLES];
|
||||
int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
uint r = (uint)i;
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
|
||||
}
|
||||
Table[i] = r;
|
||||
}
|
||||
for (; i < 256 * CRC_NUM_TABLES; i++)
|
||||
{
|
||||
uint r = Table[i - 256];
|
||||
Table[i] = Table[r & 0xFF] ^ (r >> 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public uint UnsignedValue;
|
||||
|
||||
public OptimizedCRC()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset CRC
|
||||
/// </summary>
|
||||
public void Init()
|
||||
{
|
||||
UnsignedValue = kInitial;
|
||||
}
|
||||
|
||||
public int Value
|
||||
{
|
||||
get { return (int)~UnsignedValue; }
|
||||
}
|
||||
|
||||
public void Update(byte[] data, int offset, int count)
|
||||
{
|
||||
new ArraySegment<byte>(data, offset, count); // check arguments
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var table = OptimizedCRC.Table;
|
||||
|
||||
uint crc = UnsignedValue;
|
||||
|
||||
for (; (offset & 7) != 0 && count != 0; count--)
|
||||
{
|
||||
crc = (crc >> 8) ^ table[(byte)crc ^ data[offset++]];
|
||||
}
|
||||
|
||||
if (count >= 8)
|
||||
{
|
||||
/*
|
||||
* Idea from 7-zip project sources (http://7-zip.org/sdk.html)
|
||||
*/
|
||||
|
||||
int end = (count - 8) & ~7;
|
||||
count -= end;
|
||||
end += offset;
|
||||
|
||||
while (offset != end)
|
||||
{
|
||||
crc ^= (uint)(data[offset] + (data[offset + 1] << 8) + (data[offset + 2] << 16) + (data[offset + 3] << 24));
|
||||
uint high = (uint)(data[offset + 4] + (data[offset + 5] << 8) + (data[offset + 6] << 16) + (data[offset + 7] << 24));
|
||||
offset += 8;
|
||||
|
||||
crc = table[(byte)crc + 0x700]
|
||||
^ table[(byte)(crc >>= 8) + 0x600]
|
||||
^ table[(byte)(crc >>= 8) + 0x500]
|
||||
^ table[/*(byte)*/(crc >> 8) + 0x400]
|
||||
^ table[(byte)(high) + 0x300]
|
||||
^ table[(byte)(high >>= 8) + 0x200]
|
||||
^ table[(byte)(high >>= 8) + 0x100]
|
||||
^ table[/*(byte)*/(high >> 8) + 0x000];
|
||||
}
|
||||
}
|
||||
|
||||
while (count-- != 0)
|
||||
{
|
||||
crc = (crc >> 8) ^ table[(byte)crc ^ data[offset++]];
|
||||
}
|
||||
|
||||
UnsignedValue = crc;
|
||||
}
|
||||
|
||||
static public int Compute(byte[] data, int offset, int count)
|
||||
{
|
||||
var crc = new OptimizedCRC();
|
||||
crc.Update(data, offset, count);
|
||||
return crc.Value;
|
||||
}
|
||||
|
||||
static public int Compute(byte[] data)
|
||||
{
|
||||
return Compute(data, 0, data.Length);
|
||||
}
|
||||
|
||||
static public int Compute(ArraySegment<byte> block)
|
||||
{
|
||||
return Compute(block.Array, block.Offset, block.Count);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
UnsignedValue = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,80 +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;
|
||||
|
||||
private byte[] _buffer;
|
||||
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
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net48;net6.0</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win7-x64;win8-x64;win81-x64;win10-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
<Copyright>Copyright (c)2019-2023</Copyright>
|
||||
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
|
||||
<Version>2.6</Version>
|
||||
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||
<FileVersion>$(Version)</FileVersion>
|
||||
<IncludeSource>true</IncludeSource>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<NrtRevisionFormat>$(Version)-{chash:8}</NrtRevisionFormat>
|
||||
<NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes>
|
||||
<NrtShowRevision>false</NrtShowRevision>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='net48'">
|
||||
<COMReference Include="IMAPI2">
|
||||
<Guid>{2735412F-7F64-5B0F-8F00-5D77AFBE261E}</Guid>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
<COMReference Include="IMAPI2FS">
|
||||
<Guid>{2C941FD0-975B-59BE-A960-9A2A262853A5}</Guid>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RedumpLib\RedumpLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Management.Infrastructure" Version="2.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="7.0.0" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -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,396 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Data;
|
||||
using 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.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,121 +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>
|
||||
public static async Task OutputToLog(TextReader reader, object baseClass, EventHandler<string> handler)
|
||||
{
|
||||
// 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>
|
||||
private static void ProcessNewLines(StringBuilder sb, string line, object baseClass, EventHandler<string> handler)
|
||||
{
|
||||
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>
|
||||
private static void ProcessCarriageReturns(StringBuilder sb, string line, object baseClass, EventHandler<string> handler)
|
||||
{
|
||||
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,182 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Data;
|
||||
|
||||
namespace MPF.Core.Utilities
|
||||
{
|
||||
public static class OptionsLoader
|
||||
{
|
||||
#region Arguments
|
||||
|
||||
/// <summary>
|
||||
/// Load the current set of options from application arguments
|
||||
/// </summary>
|
||||
public static (Options, string, int) LoadFromArguments(string[] args, int startIndex = 0)
|
||||
{
|
||||
// Create the output values with defaults
|
||||
var options = new Options()
|
||||
{
|
||||
RedumpUsername = null,
|
||||
RedumpPassword = null,
|
||||
InternalProgram = InternalProgram.NONE,
|
||||
OutputSubmissionJSON = false,
|
||||
CompressLogFiles = false,
|
||||
};
|
||||
|
||||
string parsedPath = null;
|
||||
|
||||
// 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, 0);
|
||||
|
||||
// If we have an invalid start index, just return
|
||||
if (startIndex < 0 || startIndex >= args.Length)
|
||||
return (options, null, startIndex);
|
||||
|
||||
// Loop through the arguments and parse out values
|
||||
for (; startIndex < args.Length; startIndex++)
|
||||
{
|
||||
// Redump login
|
||||
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;
|
||||
}
|
||||
|
||||
// Use specific program
|
||||
else 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++;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Default, we fall out
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We default to DiscImageCreator currently
|
||||
if (options.InternalProgram == InternalProgram.NONE)
|
||||
options.InternalProgram = InternalProgram.DiscImageCreator;
|
||||
|
||||
// Now deal with the complex options
|
||||
options.ScanForProtection = scan && !string.IsNullOrWhiteSpace(parsedPath);
|
||||
options.OutputSeparateProtectionFile = scan && protectFile && !string.IsNullOrWhiteSpace(parsedPath);
|
||||
|
||||
return (options, parsedPath, startIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a list of supported arguments and descriptions
|
||||
/// </summary>
|
||||
public static List<string> PrintSupportedArguments()
|
||||
{
|
||||
var supportedArguments = new List<string>();
|
||||
|
||||
supportedArguments.Add("-c, --credentials <user> <pw> Redump username and password");
|
||||
supportedArguments.Add("-u, --use <program> Dumping program output type");
|
||||
supportedArguments.Add("-p, --path <drivepath> Physical drive path for additional checks");
|
||||
supportedArguments.Add("-s, --scan Enable copy protection scan (requires --path)");
|
||||
supportedArguments.Add("-f, --protect-file Output protection to separate file (requires --scan)");
|
||||
supportedArguments.Add("-j, --json Enable submission JSON output");
|
||||
supportedArguments.Add("-z, --zip Enable log file compression");
|
||||
|
||||
return supportedArguments;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Configuration
|
||||
|
||||
/// <summary>
|
||||
/// Load the current set of options from the application configuration
|
||||
/// </summary>
|
||||
public static Options LoadFromConfig()
|
||||
{
|
||||
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
|
||||
|
||||
var settings = configFile.AppSettings.Settings;
|
||||
var dict = new Dictionary<string, string>();
|
||||
|
||||
foreach (string key in settings.AllKeys)
|
||||
{
|
||||
dict[key] = settings[key]?.Value ?? string.Empty;
|
||||
}
|
||||
|
||||
return new Options(dict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save the current set of options to the application configuration
|
||||
/// </summary>
|
||||
public static void SaveToConfig(Options options)
|
||||
{
|
||||
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
|
||||
|
||||
// Loop through all settings in Options and save them, overwriting existing settings
|
||||
foreach (var kvp in options)
|
||||
{
|
||||
configFile.AppSettings.Settings.Remove(kvp.Key);
|
||||
configFile.AppSettings.Settings.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
|
||||
configFile.Save(ConfigurationSaveMode.Modified);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using MPF.Core.Data;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using 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
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
#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>
|
||||
public static (bool different, string message, string url) CheckForNewVersion()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get current assembly version
|
||||
var assemblyVersion = Assembly.GetEntryAssembly().GetName().Version;
|
||||
string version = $"{assemblyVersion.Major}.{assemblyVersion.Minor}" + (assemblyVersion.Build != 0 ? $".{assemblyVersion.Build}" : string.Empty);
|
||||
|
||||
// Get the latest tag from GitHub
|
||||
(string tag, string 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>
|
||||
public static string GetCurrentVersion()
|
||||
{
|
||||
try
|
||||
{
|
||||
var assemblyVersion = Attribute.GetCustomAttribute(Assembly.GetEntryAssembly(), 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>
|
||||
private static (string tag, string url) GetRemoteVersionAndUrl()
|
||||
{
|
||||
#if NETFRAMEWORK
|
||||
using (System.Net.WebClient 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 (System.Net.Http.HttpClient 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");
|
||||
string latestReleaseJsonString = hc.Send(message)?.Content?.ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
var latestReleaseJson = JObject.Parse(latestReleaseJsonString);
|
||||
string latestTag = latestReleaseJson["tag_name"].ToString();
|
||||
string releaseUrl = latestReleaseJson["html_url"].ToString();
|
||||
|
||||
return (latestTag, releaseUrl);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,238 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace MPF.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// The audio or data file’s filetype
|
||||
/// </summary>
|
||||
public enum CueFileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Intel binary file (least significant byte first). Use for data files.
|
||||
/// </summary>
|
||||
BINARY,
|
||||
|
||||
/// <summary>
|
||||
/// Motorola binary file (most significant byte first). Use for data files.
|
||||
/// </summary>
|
||||
MOTOROLA,
|
||||
|
||||
/// <summary>
|
||||
/// Audio AIFF file (44.1KHz 16-bit stereo)
|
||||
/// </summary>
|
||||
AIFF,
|
||||
|
||||
/// <summary>
|
||||
/// Audio WAVE file (44.1KHz 16-bit stereo)
|
||||
/// </summary>
|
||||
WAVE,
|
||||
|
||||
/// <summary>
|
||||
/// Audio MP3 file (44.1KHz 16-bit stereo)
|
||||
/// </summary>
|
||||
MP3,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a single FILE in a cuesheet
|
||||
/// </summary>
|
||||
public class CueFile
|
||||
{
|
||||
/// <summary>
|
||||
/// filename
|
||||
/// </summary>
|
||||
public string FileName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// filetype
|
||||
/// </summary>
|
||||
public CueFileType FileType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of TRACK in FILE
|
||||
/// </summary>
|
||||
public List<CueTrack> Tracks { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty FILE
|
||||
/// </summary>
|
||||
public CueFile()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill a FILE from an array of lines
|
||||
/// </summary>
|
||||
/// <param name="fileName">File name to set</param>
|
||||
/// <param name="fileType">File type to set</param>
|
||||
/// <param name="cueLines">Lines array to pull from</param>
|
||||
/// <param name="i">Reference to index in array</param>
|
||||
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
|
||||
public CueFile(string fileName, string fileType, string[] cueLines, ref int i, bool throwOnError = false)
|
||||
{
|
||||
if (cueLines == null)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentNullException(nameof(cueLines));
|
||||
|
||||
return;
|
||||
}
|
||||
else if (i < 0 || i > cueLines.Length)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the current fields
|
||||
this.FileName = fileName.Trim('"');
|
||||
this.FileType = GetFileType(fileType);
|
||||
|
||||
// Increment to start
|
||||
i++;
|
||||
|
||||
for (; i < cueLines.Length; i++)
|
||||
{
|
||||
string line = cueLines[i].Trim();
|
||||
string[] splitLine = line.Split(' ');
|
||||
|
||||
// If we have an empty line, we skip
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
continue;
|
||||
|
||||
switch (splitLine[0])
|
||||
{
|
||||
// Read comments
|
||||
case "REM":
|
||||
// We ignore all comments for now
|
||||
break;
|
||||
|
||||
// Read track information
|
||||
case "TRACK":
|
||||
if (splitLine.Length < 3)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"TRACK line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.Tracks == null)
|
||||
this.Tracks = new List<CueTrack>();
|
||||
|
||||
var track = new CueTrack(splitLine[1], splitLine[2], cueLines, ref i);
|
||||
if (track == default)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"TRACK line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Tracks.Add(track);
|
||||
break;
|
||||
|
||||
// Default means return
|
||||
default:
|
||||
i--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the FILE out to a stream
|
||||
/// </summary>
|
||||
/// <param name="sw">StreamWriter to write to</param>
|
||||
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
|
||||
public void Write(StreamWriter sw, bool throwOnError = false)
|
||||
{
|
||||
// If we don't have any tracks, it's invalid
|
||||
if (this.Tracks == null)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentNullException(nameof(this.Tracks));
|
||||
|
||||
return;
|
||||
}
|
||||
else if (this.Tracks.Count == 0)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentException("No tracks provided to write");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sw.WriteLine($"FILE \"{this.FileName}\" {FromFileType(this.FileType)}");
|
||||
|
||||
foreach (var track in Tracks)
|
||||
{
|
||||
track.Write(sw);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the file type from a given string
|
||||
/// </summary>
|
||||
/// <param name="fileType">String to get value from</param>
|
||||
/// <returns>CueFileType, if possible</returns>
|
||||
private CueFileType GetFileType(string fileType)
|
||||
{
|
||||
switch (fileType.ToLowerInvariant())
|
||||
{
|
||||
case "binary":
|
||||
return CueFileType.BINARY;
|
||||
|
||||
case "motorola":
|
||||
return CueFileType.MOTOROLA;
|
||||
|
||||
case "aiff":
|
||||
return CueFileType.AIFF;
|
||||
|
||||
case "wave":
|
||||
return CueFileType.WAVE;
|
||||
|
||||
case "mp3":
|
||||
return CueFileType.MP3;
|
||||
|
||||
default:
|
||||
return CueFileType.BINARY;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string from a given file type
|
||||
/// </summary>
|
||||
/// <param name="fileType">CueFileType to get value from</param>
|
||||
/// <returns>String, if possible (default BINARY)</returns>
|
||||
private string FromFileType(CueFileType fileType)
|
||||
{
|
||||
switch (fileType)
|
||||
{
|
||||
case CueFileType.BINARY:
|
||||
return "BINARY";
|
||||
|
||||
case CueFileType.MOTOROLA:
|
||||
return "MOTOROLA";
|
||||
|
||||
case CueFileType.AIFF:
|
||||
return "AIFF";
|
||||
|
||||
case CueFileType.WAVE:
|
||||
return "WAVE";
|
||||
|
||||
case CueFileType.MP3:
|
||||
return "MP3";
|
||||
|
||||
default:
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace MPF.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single INDEX in a TRACK
|
||||
/// </summary>
|
||||
public class CueIndex
|
||||
{
|
||||
/// <summary>
|
||||
/// INDEX number, between 0 and 99
|
||||
/// </summary>
|
||||
public int Index { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Starting time of INDEX in minutes
|
||||
/// </summary>
|
||||
public int Minutes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Starting time of INDEX in seconds
|
||||
/// </summary>
|
||||
/// <remarks>There are 60 seconds in a minute</remarks>
|
||||
public int Seconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Starting time of INDEX in frames.
|
||||
/// </summary>
|
||||
/// <remarks>There are 75 frames per second</remarks>
|
||||
public int Frames { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty INDEX
|
||||
/// </summary>
|
||||
public CueIndex()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill a INDEX from an array of lines
|
||||
/// </summary>
|
||||
/// <param name="index">Index to set</param>
|
||||
/// <param name="startTime">Start time to set</param>
|
||||
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
|
||||
public CueIndex(string index, string startTime, bool throwOnError = false)
|
||||
{
|
||||
// Set the current fields
|
||||
if (!int.TryParse(index, out int parsedIndex))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentException($"Index was not a number: {index}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (parsedIndex < 0 || parsedIndex > 99)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Index must be between 0 and 99: {parsedIndex}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore empty lines
|
||||
if (string.IsNullOrWhiteSpace(startTime))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentException("Start time was null or whitespace");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore lines that don't contain the correct information
|
||||
if (startTime.Length != 8 || startTime.Count(c => c == ':') != 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Start time was not in a recognized format: {startTime}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Split the line
|
||||
string[] splitTime = startTime.Split(':');
|
||||
if (splitTime.Length != 3)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Start time was not in a recognized format: {startTime}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the lengths
|
||||
int[] lengthSegments = new int[3];
|
||||
|
||||
// Minutes
|
||||
if (!int.TryParse(splitTime[0], out lengthSegments[0]))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Minutes segment was not a number: {splitTime[0]}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (lengthSegments[0] < 0)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Minutes segment must be 0 or greater: {lengthSegments[0]}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Seconds
|
||||
if (!int.TryParse(splitTime[1], out lengthSegments[1]))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Seconds segment was not a number: {splitTime[1]}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (lengthSegments[1] < 0 || lengthSegments[1] > 60)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Seconds segment must be between 0 and 60: {lengthSegments[1]}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Frames
|
||||
if (!int.TryParse(splitTime[2], out lengthSegments[2]))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Frames segment was not a number: {splitTime[2]}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (lengthSegments[2] < 0 || lengthSegments[2] > 75)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Frames segment must be between 0 and 75: {lengthSegments[2]}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the values
|
||||
this.Index = parsedIndex;
|
||||
this.Minutes = lengthSegments[0];
|
||||
this.Seconds = lengthSegments[1];
|
||||
this.Frames = lengthSegments[2];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the INDEX out to a stream
|
||||
/// </summary>
|
||||
/// <param name="sw">StreamWriter to write to</param>
|
||||
public void Write(StreamWriter sw)
|
||||
{
|
||||
sw.WriteLine($" INDEX {this.Index:D2} {this.Minutes:D2}:{this.Seconds:D2}:{this.Frames:D2}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,250 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace MPF.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single cuesheet
|
||||
/// </summary>
|
||||
public class CueSheet
|
||||
{
|
||||
/// <summary>
|
||||
/// CATALOG
|
||||
/// </summary>
|
||||
public string Catalog { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// CDTEXTFILE
|
||||
/// </summary>
|
||||
public string CdTextFile { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// PERFORMER
|
||||
/// </summary>
|
||||
public string Performer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// SONGWRITER
|
||||
/// </summary>
|
||||
public string Songwriter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// TITLE
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of FILE in cuesheet
|
||||
/// </summary>
|
||||
public List<CueFile> Files { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty cuesheet
|
||||
/// </summary>
|
||||
public CueSheet()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a cuesheet from a file, if possible
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
|
||||
public CueSheet(string filename, bool throwOnError = false)
|
||||
{
|
||||
// Check that the file exists
|
||||
if (!File.Exists(filename))
|
||||
return;
|
||||
|
||||
// Check the extension
|
||||
string ext = Path.GetExtension(filename).TrimStart('.');
|
||||
if (!string.Equals(ext, "cue", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(ext, "txt", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Open the file and begin reading
|
||||
string[] cueLines = File.ReadAllLines(filename);
|
||||
for (int i = 0; i < cueLines.Length; i++)
|
||||
{
|
||||
string line = cueLines[i].Trim();
|
||||
|
||||
// http://stackoverflow.com/questions/554013/regular-expression-to-split-on-spaces-unless-in-quotes
|
||||
string[] splitLine = Regex
|
||||
.Matches(line, @"[^\s""]+|""[^""]*""")
|
||||
.Cast<Match>()
|
||||
.Select(m => m.Groups[0].Value)
|
||||
.ToArray();
|
||||
|
||||
// If we have an empty line, we skip
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
continue;
|
||||
|
||||
switch (splitLine[0])
|
||||
{
|
||||
// Read comments
|
||||
case "REM":
|
||||
// We ignore all comments for now
|
||||
break;
|
||||
|
||||
// Read MCN
|
||||
case "CATALOG":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"CATALOG line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Catalog = splitLine[1];
|
||||
break;
|
||||
|
||||
// Read external CD-Text file path
|
||||
case "CDTEXTFILE":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"CDTEXTFILE line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.CdTextFile = splitLine[1];
|
||||
break;
|
||||
|
||||
// Read CD-Text enhanced performer
|
||||
case "PERFORMER":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"PERFORMER line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Performer = splitLine[1];
|
||||
break;
|
||||
|
||||
// Read CD-Text enhanced songwriter
|
||||
case "SONGWRITER":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"SONGWRITER line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Songwriter = splitLine[1];
|
||||
break;
|
||||
|
||||
// Read CD-Text enhanced title
|
||||
case "TITLE":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"TITLE line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Title = splitLine[1];
|
||||
break;
|
||||
|
||||
// Read file information
|
||||
case "FILE":
|
||||
if (splitLine.Length < 3)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"FILE line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.Files == null)
|
||||
this.Files = new List<CueFile>();
|
||||
|
||||
var file = new CueFile(splitLine[1], splitLine[2], cueLines, ref i);
|
||||
if (file == default)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"FILE line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Files.Add(file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the cuesheet out to a file
|
||||
/// </summary>
|
||||
/// <param name="filename">File path to write to</param>
|
||||
public void Write(string filename)
|
||||
{
|
||||
using (var fs = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
|
||||
{
|
||||
Write(fs);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the cuesheet out to a stream
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream to write to</param>
|
||||
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
|
||||
public void Write(Stream stream, bool throwOnError = false)
|
||||
{
|
||||
// If we don't have any files, it's invalid
|
||||
if (this.Files == null)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentNullException(nameof(this.Files));
|
||||
|
||||
return;
|
||||
}
|
||||
else if (this.Files.Count == 0)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentException("No files provided to write");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
using (var sw = new StreamWriter(stream, Encoding.ASCII, 1024, true))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(this.Catalog))
|
||||
sw.WriteLine($"CATALOG {this.Catalog}");
|
||||
|
||||
if (!string.IsNullOrEmpty(this.CdTextFile))
|
||||
sw.WriteLine($"CDTEXTFILE {this.CdTextFile}");
|
||||
|
||||
if (!string.IsNullOrEmpty(this.Performer))
|
||||
sw.WriteLine($"PERFORMER {this.Performer}");
|
||||
|
||||
if (!string.IsNullOrEmpty(this.Songwriter))
|
||||
sw.WriteLine($"SONGWRITER {this.Songwriter}");
|
||||
|
||||
if (!string.IsNullOrEmpty(this.Title))
|
||||
sw.WriteLine($"TITLE {this.Title}");
|
||||
|
||||
foreach (var file in Files)
|
||||
{
|
||||
file.Write(sw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,554 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace MPF.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Track datatype
|
||||
/// </summary>
|
||||
public enum CueTrackDataType
|
||||
{
|
||||
/// <summary>
|
||||
/// AUDIO, Audio/Music (2352)
|
||||
/// </summary>
|
||||
AUDIO,
|
||||
|
||||
/// <summary>
|
||||
/// CDG, Karaoke CD+G (2448)
|
||||
/// </summary>
|
||||
CDG,
|
||||
|
||||
/// <summary>
|
||||
/// MODE1/2048, CD-ROM Mode1 Data (cooked)
|
||||
/// </summary>
|
||||
MODE1_2048,
|
||||
|
||||
/// <summary>
|
||||
/// MODE1/2352 CD-ROM Mode1 Data (raw)
|
||||
/// </summary>
|
||||
MODE1_2352,
|
||||
|
||||
/// <summary>
|
||||
/// MODE2/2336, CD-ROM XA Mode2 Data
|
||||
/// </summary>
|
||||
MODE2_2336,
|
||||
|
||||
/// <summary>
|
||||
/// MODE2/2352, CD-ROM XA Mode2 Data
|
||||
/// </summary>
|
||||
MODE2_2352,
|
||||
|
||||
/// <summary>
|
||||
/// CDI/2336, CD-I Mode2 Data
|
||||
/// </summary>
|
||||
CDI_2336,
|
||||
|
||||
/// <summary>
|
||||
/// CDI/2352, CD-I Mode2 Data
|
||||
/// </summary>
|
||||
CDI_2352,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Special subcode flags within a track
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum CueTrackFlag
|
||||
{
|
||||
/// <summary>
|
||||
/// DCP, Digital copy permitted
|
||||
/// </summary>
|
||||
DCP = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// 4CH, Four channel audio
|
||||
/// </summary>
|
||||
FourCH = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// PRE, Pre-emphasis enabled (audio tracks only)
|
||||
/// </summary>
|
||||
PRE = 1 << 2,
|
||||
|
||||
/// <summary>
|
||||
/// SCMS, Serial Copy Management System (not supported by all recorders)
|
||||
/// </summary>
|
||||
SCMS = 1 << 3,
|
||||
|
||||
/// <summary>
|
||||
/// DATA, set for data files. This flag is set automatically based on the track’s filetype
|
||||
/// </summary>
|
||||
DATA = 1 << 4,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a single TRACK in a FILE
|
||||
/// </summary>
|
||||
public class CueTrack
|
||||
{
|
||||
/// <summary>
|
||||
/// Track number. The range is 1 to 99.
|
||||
/// </summary>
|
||||
public int Number { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Track datatype
|
||||
/// </summary>
|
||||
public CueTrackDataType DataType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// FLAGS
|
||||
/// </summary>
|
||||
public CueTrackFlag Flags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ISRC
|
||||
/// </summary>
|
||||
/// <remarks>12 characters in length</remarks>
|
||||
public string ISRC { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// PERFORMER
|
||||
/// </summary>
|
||||
public string Performer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// SONGWRITER
|
||||
/// </summary>
|
||||
public string Songwriter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// TITLE
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// PREGAP
|
||||
/// </summary>
|
||||
public PreGap PreGap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of INDEX in TRACK
|
||||
/// </summary>
|
||||
/// <remarks>Must start with 0 or 1 and then sequential</remarks>
|
||||
public List<CueIndex> Indices { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// POSTGAP
|
||||
/// </summary>
|
||||
public PostGap PostGap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty TRACK
|
||||
/// </summary>
|
||||
public CueTrack()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill a TRACK from an array of lines
|
||||
/// </summary>
|
||||
/// <param name="number">Number to set</param>
|
||||
/// <param name="dataType">Data type to set</param>
|
||||
/// <param name="cueLines">Lines array to pull from</param>
|
||||
/// <param name="i">Reference to index in array</param>
|
||||
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
|
||||
public CueTrack(string number, string dataType, string[] cueLines, ref int i, bool throwOnError = false)
|
||||
{
|
||||
if (cueLines == null)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentNullException(nameof(cueLines));
|
||||
|
||||
return;
|
||||
}
|
||||
else if (i < 0 || i > cueLines.Length)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the current fields
|
||||
if (!int.TryParse(number, out int parsedNumber))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentException($"Number was not a number: {number}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (parsedNumber < 1 || parsedNumber > 99)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Index must be between 1 and 99: {parsedNumber}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.Number = parsedNumber;
|
||||
this.DataType = GetDataType(dataType);
|
||||
|
||||
// Increment to start
|
||||
i++;
|
||||
|
||||
for (; i < cueLines.Length; i++)
|
||||
{
|
||||
string line = cueLines[i].Trim();
|
||||
string[] splitLine = line.Split(' ');
|
||||
|
||||
// If we have an empty line, we skip
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
continue;
|
||||
|
||||
switch (splitLine[0])
|
||||
{
|
||||
// Read comments
|
||||
case "REM":
|
||||
// We ignore all comments for now
|
||||
break;
|
||||
|
||||
// Read flag information
|
||||
case "FLAGS":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"FLAGS line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Flags = GetFlags(splitLine);
|
||||
break;
|
||||
|
||||
// Read International Standard Recording Code
|
||||
case "ISRC":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"ISRC line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.ISRC = splitLine[1];
|
||||
break;
|
||||
|
||||
// Read CD-Text enhanced performer
|
||||
case "PERFORMER":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"PERFORMER line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Performer = splitLine[1];
|
||||
break;
|
||||
|
||||
// Read CD-Text enhanced songwriter
|
||||
case "SONGWRITER":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"SONGWRITER line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Songwriter = splitLine[1];
|
||||
break;
|
||||
|
||||
// Read CD-Text enhanced title
|
||||
case "TITLE":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"TITLE line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Title = splitLine[1];
|
||||
break;
|
||||
|
||||
// Read pregap information
|
||||
case "PREGAP":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"PREGAP line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var pregap = new PreGap(splitLine[1]);
|
||||
if (pregap == default)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"PREGAP line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.PreGap = pregap;
|
||||
break;
|
||||
|
||||
// Read index information
|
||||
case "INDEX":
|
||||
if (splitLine.Length < 3)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"INDEX line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.Indices == null)
|
||||
this.Indices = new List<CueIndex>();
|
||||
|
||||
var index = new CueIndex(splitLine[1], splitLine[2]);
|
||||
if (index == default)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"INDEX line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Indices.Add(index);
|
||||
break;
|
||||
|
||||
// Read postgap information
|
||||
case "POSTGAP":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"POSTGAP line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var postgap = new PostGap(splitLine[1]);
|
||||
if (postgap == default)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"POSTGAP line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.PostGap = postgap;
|
||||
break;
|
||||
|
||||
// Default means return
|
||||
default:
|
||||
i--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the TRACK out to a stream
|
||||
/// </summary>
|
||||
/// <param name="sw">StreamWriter to write to</param
|
||||
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
|
||||
public void Write(StreamWriter sw, bool throwOnError = false)
|
||||
{
|
||||
// If we don't have any indices, it's invalid
|
||||
if (this.Indices == null)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentNullException(nameof(this.Indices));
|
||||
|
||||
return;
|
||||
}
|
||||
else if (this.Indices.Count == 0)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentException("No indices provided to write");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sw.WriteLine($" TRACK {this.Number:D2} {FromDataType(this.DataType)}");
|
||||
|
||||
if (this.Flags != 0)
|
||||
sw.WriteLine($" FLAGS {FromFlags(this.Flags)}");
|
||||
|
||||
if (!string.IsNullOrEmpty(this.ISRC))
|
||||
sw.WriteLine($"ISRC {this.ISRC}");
|
||||
|
||||
if (!string.IsNullOrEmpty(this.Performer))
|
||||
sw.WriteLine($"PERFORMER {this.Performer}");
|
||||
|
||||
if (!string.IsNullOrEmpty(this.Songwriter))
|
||||
sw.WriteLine($"SONGWRITER {this.Songwriter}");
|
||||
|
||||
if (!string.IsNullOrEmpty(this.Title))
|
||||
sw.WriteLine($"TITLE {this.Title}");
|
||||
|
||||
if (this.PreGap != null)
|
||||
this.PreGap.Write(sw);
|
||||
|
||||
foreach (var index in Indices)
|
||||
{
|
||||
index.Write(sw);
|
||||
}
|
||||
|
||||
if (this.PostGap != null)
|
||||
this.PostGap.Write(sw);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the data type from a given string
|
||||
/// </summary>
|
||||
/// <param name="dataType">String to get value from</param>
|
||||
/// <returns>CueTrackDataType, if possible (default AUDIO)</returns>
|
||||
private CueTrackDataType GetDataType(string dataType)
|
||||
{
|
||||
switch (dataType.ToLowerInvariant())
|
||||
{
|
||||
case "audio":
|
||||
return CueTrackDataType.AUDIO;
|
||||
|
||||
case "cdg":
|
||||
return CueTrackDataType.CDG;
|
||||
|
||||
case "mode1/2048":
|
||||
return CueTrackDataType.MODE1_2048;
|
||||
|
||||
case "mode1/2352":
|
||||
return CueTrackDataType.MODE1_2352;
|
||||
|
||||
case "mode2/2336":
|
||||
return CueTrackDataType.MODE2_2336;
|
||||
|
||||
case "mode2/2352":
|
||||
return CueTrackDataType.MODE2_2352;
|
||||
|
||||
case "cdi/2336":
|
||||
return CueTrackDataType.CDI_2336;
|
||||
|
||||
case "cdi/2352":
|
||||
return CueTrackDataType.CDI_2352;
|
||||
|
||||
default:
|
||||
return CueTrackDataType.AUDIO;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string from a given data type
|
||||
/// </summary>
|
||||
/// <param name="dataType">CueTrackDataType to get value from</param>
|
||||
/// <returns>string, if possible</returns>
|
||||
private string FromDataType(CueTrackDataType dataType)
|
||||
{
|
||||
switch (dataType)
|
||||
{
|
||||
case CueTrackDataType.AUDIO:
|
||||
return "AUDIO";
|
||||
|
||||
case CueTrackDataType.CDG:
|
||||
return "CDG";
|
||||
|
||||
case CueTrackDataType.MODE1_2048:
|
||||
return "MODE1/2048";
|
||||
|
||||
case CueTrackDataType.MODE1_2352:
|
||||
return "MODE1/2352";
|
||||
|
||||
case CueTrackDataType.MODE2_2336:
|
||||
return "MODE2/2336";
|
||||
|
||||
case CueTrackDataType.MODE2_2352:
|
||||
return "MODE2/2352";
|
||||
|
||||
case CueTrackDataType.CDI_2336:
|
||||
return "CDI/2336";
|
||||
|
||||
case CueTrackDataType.CDI_2352:
|
||||
return "CDI/2352";
|
||||
|
||||
default:
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the flag value for an array of strings
|
||||
/// </summary>
|
||||
/// <param name="flagStrings">Possible flags as strings</param>
|
||||
/// <returns>CueTrackFlag value representing the strings, if possible</returns>
|
||||
private CueTrackFlag GetFlags(string[] flagStrings)
|
||||
{
|
||||
CueTrackFlag flag = 0;
|
||||
|
||||
foreach (string flagString in flagStrings)
|
||||
{
|
||||
switch (flagString.ToLowerInvariant())
|
||||
{
|
||||
case "flags":
|
||||
// No-op since this is the start of the line
|
||||
break;
|
||||
|
||||
case "dcp":
|
||||
flag |= CueTrackFlag.DCP;
|
||||
break;
|
||||
|
||||
case "4ch":
|
||||
flag |= CueTrackFlag.FourCH;
|
||||
break;
|
||||
|
||||
case "pre":
|
||||
flag |= CueTrackFlag.PRE;
|
||||
break;
|
||||
|
||||
case "scms":
|
||||
flag |= CueTrackFlag.SCMS;
|
||||
break;
|
||||
|
||||
case "data":
|
||||
flag |= CueTrackFlag.DATA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for a set of track flags
|
||||
/// </summary>
|
||||
/// <param name="flags">CueTrackFlag to get value from</param>
|
||||
/// <returns>String value representing the CueTrackFlag, if possible</returns>
|
||||
private string FromFlags(CueTrackFlag flags)
|
||||
{
|
||||
string outputFlagString = string.Empty;
|
||||
|
||||
if (flags.HasFlag(CueTrackFlag.DCP))
|
||||
outputFlagString += "DCP ";
|
||||
|
||||
if (flags.HasFlag(CueTrackFlag.FourCH))
|
||||
outputFlagString += "4CH ";
|
||||
|
||||
if (flags.HasFlag(CueTrackFlag.PRE))
|
||||
outputFlagString += "PRE ";
|
||||
|
||||
if (flags.HasFlag(CueTrackFlag.SCMS))
|
||||
outputFlagString += "SCMS ";
|
||||
|
||||
if (flags.HasFlag(CueTrackFlag.DATA))
|
||||
outputFlagString += "DATA ";
|
||||
|
||||
return outputFlagString.Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net48;net6.0</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win7-x64;win8-x64;win81-x64;win10-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
<Copyright>Copyright (c)2019-2023</Copyright>
|
||||
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
|
||||
<Version>2.6</Version>
|
||||
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||
<FileVersion>$(Version)</FileVersion>
|
||||
<IncludeSource>true</IncludeSource>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<NrtRevisionFormat>$(Version)-{chash:8}</NrtRevisionFormat>
|
||||
<NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes>
|
||||
<NrtShowRevision>false</NrtShowRevision>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
|
||||
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,139 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace MPF.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents POSTGAP information of a track
|
||||
/// </summary>
|
||||
public class PostGap
|
||||
{
|
||||
/// <summary>
|
||||
/// Length of POSTGAP in minutes
|
||||
/// </summary>
|
||||
public int Minutes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of POSTGAP in seconds
|
||||
/// </summary>
|
||||
/// <remarks>There are 60 seconds in a minute</remarks>
|
||||
public int Seconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of POSTGAP in frames.
|
||||
/// </summary>
|
||||
/// <remarks>There are 75 frames per second</remarks>
|
||||
public int Frames { get; set; }
|
||||
|
||||
/// Create an empty POSTGAP
|
||||
/// </summary>
|
||||
public PostGap()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a POSTGAP from a mm:ss:ff length
|
||||
/// </summary>
|
||||
/// <param name="length">String to get length information from</param>
|
||||
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
|
||||
public PostGap(string length, bool throwOnError = false)
|
||||
{
|
||||
// Ignore empty lines
|
||||
if (string.IsNullOrWhiteSpace(length))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentException("Length was null or whitespace");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore lines that don't contain the correct information
|
||||
if (length.Length != 8 || length.Count(c => c == ':') != 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Length was not in a recognized format: {length}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Split the line
|
||||
string[] splitLength = length.Split(':');
|
||||
if (splitLength.Length != 3)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Length was not in a recognized format: {length}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the lengths
|
||||
int[] lengthSegments = new int[3];
|
||||
|
||||
// Minutes
|
||||
if (!int.TryParse(splitLength[0], out lengthSegments[0]))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Minutes segment was not a number: {splitLength[0]}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (lengthSegments[0] < 0)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Minutes segment must be 0 or greater: {lengthSegments[0]}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Seconds
|
||||
if (!int.TryParse(splitLength[1], out lengthSegments[1]))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Seconds segment was not a number: {splitLength[1]}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (lengthSegments[1] < 0 || lengthSegments[1] > 60)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Seconds segment must be between 0 and 60: {lengthSegments[1]}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Frames
|
||||
if (!int.TryParse(splitLength[2], out lengthSegments[2]))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Frames segment was not a number: {splitLength[2]}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (lengthSegments[2] < 0 || lengthSegments[2] > 75)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Frames segment must be between 0 and 75: {lengthSegments[2]}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the values
|
||||
this.Minutes = lengthSegments[0];
|
||||
this.Seconds = lengthSegments[1];
|
||||
this.Frames = lengthSegments[2];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the POSTGAP out to a stream
|
||||
/// </summary>
|
||||
/// <param name="sw">StreamWriter to write to</param>
|
||||
public void Write(StreamWriter sw)
|
||||
{
|
||||
sw.WriteLine($" POSTGAP {this.Minutes:D2}:{this.Seconds:D2}:{this.Frames:D2}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace MPF.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents PREGAP information of a track
|
||||
/// </summary>
|
||||
public class PreGap
|
||||
{
|
||||
/// <summary>
|
||||
/// Length of PREGAP in minutes
|
||||
/// </summary>
|
||||
public int Minutes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of PREGAP in seconds
|
||||
/// </summary>
|
||||
/// <remarks>There are 60 seconds in a minute</remarks>
|
||||
public int Seconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of PREGAP in frames.
|
||||
/// </summary>
|
||||
/// <remarks>There are 75 frames per second</remarks>
|
||||
public int Frames { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty PREGAP
|
||||
/// </summary>
|
||||
public PreGap()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a PREGAP from a mm:ss:ff length
|
||||
/// </summary>
|
||||
/// <param name="length">String to get length information from</param>
|
||||
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
|
||||
public PreGap(string length, bool throwOnError = false)
|
||||
{
|
||||
// Ignore empty lines
|
||||
if (string.IsNullOrWhiteSpace(length))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentException("Length was null or whitespace");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore lines that don't contain the correct information
|
||||
if (length.Length != 8 || length.Count(c => c == ':') != 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Length was not in a recognized format: {length}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Split the line
|
||||
string[] splitLength = length.Split(':');
|
||||
if (splitLength.Length != 3)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Length was not in a recognized format: {length}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the lengths
|
||||
int[] lengthSegments = new int[3];
|
||||
|
||||
// Minutes
|
||||
if (!int.TryParse(splitLength[0], out lengthSegments[0]))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Minutes segment was not a number: {splitLength[0]}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (lengthSegments[0] < 0)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Minutes segment must be 0 or greater: {lengthSegments[0]}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Seconds
|
||||
if (!int.TryParse(splitLength[1], out lengthSegments[1]))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Seconds segment was not a number: {splitLength[1]}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (lengthSegments[1] < 0 || lengthSegments[1] > 60)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Seconds segment must be between 0 and 60: {lengthSegments[1]}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Frames
|
||||
if (!int.TryParse(splitLength[2], out lengthSegments[2]))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Frames segment was not a number: {splitLength[2]}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (lengthSegments[2] < 0 || lengthSegments[2] > 75)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Frames segment must be between 0 and 75: {lengthSegments[2]}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the values
|
||||
this.Minutes = lengthSegments[0];
|
||||
this.Seconds = lengthSegments[1];
|
||||
this.Frames = lengthSegments[2];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the PREGAP out to a stream
|
||||
/// </summary>
|
||||
/// <param name="sw">StreamWriter to write to</param>
|
||||
public void Write(StreamWriter sw)
|
||||
{
|
||||
sw.WriteLine($" PREGAP {this.Minutes:D2}:{this.Seconds:D2}:{this.Frames:D2}");
|
||||
}
|
||||
}
|
||||
}
|
||||
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 RedumpLib.Data;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.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;
|
||||
}
|
||||
}
|
||||
1131
MPF.ExecutionContexts/BaseExecutionContext.cs
Normal file
1131
MPF.ExecutionContexts/BaseExecutionContext.cs
Normal file
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.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.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.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.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,42 +1,32 @@
|
||||
namespace MPF.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";
|
||||
}
|
||||
|
||||
/// <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";
|
||||
@@ -44,29 +34,71 @@ namespace MPF.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,10 +1,7 @@
|
||||
using System.IO;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Library;
|
||||
using RedumpLib.Data;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Library
|
||||
namespace MPF.Frontend.Test
|
||||
{
|
||||
public class DumpEnvironmentTests
|
||||
{
|
||||
@@ -12,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 };
|
||||
|
||||
@@ -24,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