mirror of
https://github.com/SabreTools/MPF.git
synced 2026-02-04 13:45:29 +00:00
Compare commits
607 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3dcac28488 | ||
|
|
4cd7073bf6 | ||
|
|
1af21e7aba | ||
|
|
52adcd0b46 | ||
|
|
8a91593e58 | ||
|
|
729f8273fc | ||
|
|
78df6f6583 | ||
|
|
dc8dae4df7 | ||
|
|
53db9dbf81 | ||
|
|
22755a4af9 | ||
|
|
ba28b414ba | ||
|
|
95d10ecb1e | ||
|
|
c5ab2c747a | ||
|
|
476c494f4e | ||
|
|
758c49c1cc | ||
|
|
d80ad3b3cf | ||
|
|
3d06f80703 | ||
|
|
7344460409 | ||
|
|
19f58d9dde | ||
|
|
ad9f39f832 | ||
|
|
d51117b058 | ||
|
|
0d65d5114a | ||
|
|
30fec3c3d0 | ||
|
|
8eb86fde90 | ||
|
|
7616c6b2ba | ||
|
|
e0742cdfc7 | ||
|
|
a19937d630 | ||
|
|
fa92402bc5 | ||
|
|
cdc3da5839 | ||
|
|
3430f8c1db | ||
|
|
12fd55e76c | ||
|
|
0013606d61 | ||
|
|
4d520d7d63 | ||
|
|
7bfe174680 | ||
|
|
4951e7bf42 | ||
|
|
d7d9c468ae | ||
|
|
32faa33ad3 | ||
|
|
8a5475380a | ||
|
|
1dd5542390 | ||
|
|
5156b89eca | ||
|
|
83ea04c880 | ||
|
|
8695d2981e | ||
|
|
e0c299e6f0 | ||
|
|
16ec54f389 | ||
|
|
998bf5d5fa | ||
|
|
07ec821e9a | ||
|
|
56cf8f3574 | ||
|
|
c6ebfcd6d9 | ||
|
|
6ceffce63d | ||
|
|
f43aafc00d | ||
|
|
ab598d8377 | ||
|
|
dbd876a1c1 | ||
|
|
fd102cb56b | ||
|
|
0afb49b657 | ||
|
|
be980fe0c4 | ||
|
|
08b4e8d602 | ||
|
|
e483e1cdc6 | ||
|
|
5c2dce78e2 | ||
|
|
26ea383775 | ||
|
|
64938fd7f1 | ||
|
|
22318ee3c1 | ||
|
|
b2b54a2706 | ||
|
|
40f04e0321 | ||
|
|
a7638b8063 | ||
|
|
2abcad2a0f | ||
|
|
e088b05de4 | ||
|
|
a31d894b79 | ||
|
|
34fae4572d | ||
|
|
1ecf0ad1fa | ||
|
|
7c7509020f | ||
|
|
7c6b118282 | ||
|
|
c154a844e3 | ||
|
|
088f1b8545 | ||
|
|
fc3c636bdd | ||
|
|
14c807c882 | ||
|
|
d0e9c51786 | ||
|
|
b428bc0ba0 | ||
|
|
6dbbb91438 | ||
|
|
2066d36424 | ||
|
|
29552cd39d | ||
|
|
640e7091cc | ||
|
|
af12c18d2e | ||
|
|
f28cf614c3 | ||
|
|
888cb8ec9f | ||
|
|
04035ac524 | ||
|
|
600374eb2d | ||
|
|
6ecb932a82 | ||
|
|
4cbc9ac109 | ||
|
|
5ee0b7345b | ||
|
|
cc55330fad | ||
|
|
6589380fdf | ||
|
|
bd45482bf7 | ||
|
|
e14c8a8f03 | ||
|
|
4ac00e9a1a | ||
|
|
edf983e304 | ||
|
|
01a69ef9b3 | ||
|
|
a368afc14a | ||
|
|
d83fed16f5 | ||
|
|
949df08690 | ||
|
|
ab3abb5b3e | ||
|
|
d16e73a530 | ||
|
|
3f8c55ca47 | ||
|
|
2e9aaa50f9 | ||
|
|
36951dc5da | ||
|
|
b39c8dd738 | ||
|
|
a1155cf9b7 | ||
|
|
1d151d213e | ||
|
|
6dc0c1438a | ||
|
|
8739569db6 | ||
|
|
0dcba9ce71 | ||
|
|
8d37b85e12 | ||
|
|
43cf8e1a45 | ||
|
|
7317553483 | ||
|
|
0b342e265c | ||
|
|
08359dd45f | ||
|
|
a24415cae6 | ||
|
|
59f8161308 | ||
|
|
51f955a14c | ||
|
|
ddebdef00c | ||
|
|
6a4b6d613a | ||
|
|
97aef5e29c | ||
|
|
9549178c3a | ||
|
|
c531539c87 | ||
|
|
fa04461631 | ||
|
|
83d230dfe1 | ||
|
|
ca18bbb72c | ||
|
|
de0f2c1ad9 | ||
|
|
2f0019282e | ||
|
|
72ca479c9f | ||
|
|
de3c4362e7 | ||
|
|
987348fee8 | ||
|
|
100e012fe6 | ||
|
|
af59ebe1ff | ||
|
|
0762c88655 | ||
|
|
bbe9c94545 | ||
|
|
c7efda7da8 | ||
|
|
5c78f9bc29 | ||
|
|
e7c17c7b4b | ||
|
|
7a2497f168 | ||
|
|
5172f6f253 | ||
|
|
9017472fa4 | ||
|
|
6659c410c6 | ||
|
|
8c7b66a2f5 | ||
|
|
8f57d78200 | ||
|
|
ad2ee9efa8 | ||
|
|
192964f65a | ||
|
|
672f30af35 | ||
|
|
a7a17298f2 | ||
|
|
e17ad8e4a1 | ||
|
|
2a544676e6 | ||
|
|
6abfa9581d | ||
|
|
a6de548e5d | ||
|
|
9dc3e579b5 | ||
|
|
c5be7d7f73 | ||
|
|
70c0da703b | ||
|
|
1cbe81fba6 | ||
|
|
420e356f34 | ||
|
|
0e0ff0cb80 | ||
|
|
9003d05ae2 | ||
|
|
c247225cac | ||
|
|
4bccaa8ecf | ||
|
|
b579fec7ab | ||
|
|
37e4525c98 | ||
|
|
2269537848 | ||
|
|
441fb91222 | ||
|
|
89e0473019 | ||
|
|
3e13b35c84 | ||
|
|
fd4910fc36 | ||
|
|
964685770f | ||
|
|
634d64b5a1 | ||
|
|
19ec1c448f | ||
|
|
e3532d6f02 | ||
|
|
aaf0aabb55 | ||
|
|
575a5936ca | ||
|
|
391d265353 | ||
|
|
f90d19821c | ||
|
|
b79babf57e | ||
|
|
a929bb0022 | ||
|
|
975eb97e27 | ||
|
|
49800cf0ed | ||
|
|
de18609e00 | ||
|
|
9911446bf9 | ||
|
|
a9223211ab | ||
|
|
54c4eeba03 | ||
|
|
a30ee3e6ff | ||
|
|
1fa19489a3 | ||
|
|
f6298dfe89 | ||
|
|
79802a53f6 | ||
|
|
54bf43fd6b | ||
|
|
bb2b2f668b | ||
|
|
ecca27e012 | ||
|
|
fe0699ca48 | ||
|
|
73b2f0921f | ||
|
|
c56230c3af | ||
|
|
919b62822d | ||
|
|
21b0c9a08d | ||
|
|
63fafd05b3 | ||
|
|
0a2493a953 | ||
|
|
87ab750714 | ||
|
|
5cf3eca9eb | ||
|
|
b4a079b65f | ||
|
|
7f2d501edf | ||
|
|
c981f94092 | ||
|
|
afba46b8b0 | ||
|
|
4e416df3c8 | ||
|
|
1b54e52351 | ||
|
|
5e1568a148 | ||
|
|
8f0ac56cf8 | ||
|
|
37f0f9d4a4 | ||
|
|
a48f75c704 | ||
|
|
58a683e3c9 | ||
|
|
907637b128 | ||
|
|
85f3e97a44 | ||
|
|
beae9691fd | ||
|
|
b7876d54cc | ||
|
|
5b24223cb5 | ||
|
|
88cadff9ef | ||
|
|
b92b39e7eb | ||
|
|
8d29a29591 | ||
|
|
daf516bf9c | ||
|
|
115d9857af | ||
|
|
b322146e9e | ||
|
|
b6e3c9da82 | ||
|
|
6abdc632dc | ||
|
|
335ca6d5ac | ||
|
|
8752426694 | ||
|
|
5357ba5900 | ||
|
|
f2686096bd | ||
|
|
c4ef14ea3c | ||
|
|
03668bd6af | ||
|
|
2d90a63ca7 | ||
|
|
11e6e37331 | ||
|
|
b229a2d59e | ||
|
|
c61af9316f | ||
|
|
02e3040e1b | ||
|
|
60bbe29435 | ||
|
|
3274ea08aa | ||
|
|
97a61dea32 | ||
|
|
6cccf20b03 | ||
|
|
0a7e17ed00 | ||
|
|
706f75c0eb | ||
|
|
022e87c4bb | ||
|
|
8b29ac7e47 | ||
|
|
4d5b8baf6f | ||
|
|
e199e5a08c | ||
|
|
6cc2351bf7 | ||
|
|
c391dbd3c8 | ||
|
|
709d980b67 | ||
|
|
0903855d5c | ||
|
|
6ad2505bf8 | ||
|
|
5db8756639 | ||
|
|
5d176408a2 | ||
|
|
ab0b569798 | ||
|
|
ee76d49e56 | ||
|
|
c75d2dcae2 | ||
|
|
7c411d36db | ||
|
|
ca767cf576 | ||
|
|
b57e0bb97e | ||
|
|
5f059253a4 | ||
|
|
e0f8443653 | ||
|
|
4c23a4bbf3 | ||
|
|
0c1486bbce | ||
|
|
6f41c9a331 | ||
|
|
2879dd29d6 | ||
|
|
42e1ef45b4 | ||
|
|
19493fdf0c | ||
|
|
5870ad0673 | ||
|
|
cbd2850d1b | ||
|
|
e7c36c104a | ||
|
|
960840d9ba | ||
|
|
b8ac1bc9d4 | ||
|
|
89edf9a8f6 | ||
|
|
eb8db0b311 | ||
|
|
b10cf8b78a | ||
|
|
1dd5c0d6d0 | ||
|
|
a1e00d23a4 | ||
|
|
1a9d38dd0e | ||
|
|
2f3e7d105d | ||
|
|
a72b3c32b1 | ||
|
|
a479b16ae2 | ||
|
|
a9e7b6f5b3 | ||
|
|
60605d7d00 | ||
|
|
9dc7f726e9 | ||
|
|
46134032d6 | ||
|
|
9847c8f351 | ||
|
|
7b506586cd | ||
|
|
40bbd422b7 | ||
|
|
285fd69ab4 | ||
|
|
b436e19bbb | ||
|
|
bf6e079289 | ||
|
|
b623866b6e | ||
|
|
df7046723c | ||
|
|
3cd3047790 | ||
|
|
abd60612c5 | ||
|
|
02292acee1 | ||
|
|
c923899898 | ||
|
|
fcdd2ad036 | ||
|
|
02d3af0ac1 | ||
|
|
0516bccece | ||
|
|
2d6389d54d | ||
|
|
60d5a117b5 | ||
|
|
9b7e2e35f5 | ||
|
|
ddfb383f23 | ||
|
|
a1707486f4 | ||
|
|
451101ec67 | ||
|
|
83c583b7e6 | ||
|
|
33cb3d3c97 | ||
|
|
3d98f345c1 | ||
|
|
de8ce5c110 | ||
|
|
fd9ed77316 | ||
|
|
d974b73cce | ||
|
|
da8a67fcad | ||
|
|
471bc60ed7 | ||
|
|
fef46be34c | ||
|
|
9a92dbdedb | ||
|
|
d6be0a4154 | ||
|
|
d3ae372903 | ||
|
|
7621ef1a13 | ||
|
|
148fdd0590 | ||
|
|
232256310a | ||
|
|
5e938791ef | ||
|
|
08405dd9b4 | ||
|
|
512c637ea3 | ||
|
|
909ebd72a1 | ||
|
|
123136e90e | ||
|
|
299d25af27 | ||
|
|
9eee2f6444 | ||
|
|
2afb10b73b | ||
|
|
1b016e5915 | ||
|
|
1c403e1748 | ||
|
|
a372a133ca | ||
|
|
08a7df504b | ||
|
|
39f9d9a86d | ||
|
|
bdd5af65ce | ||
|
|
92d7d2ab91 | ||
|
|
8d4d7ce449 | ||
|
|
d2d650cace | ||
|
|
772cefd700 | ||
|
|
e20350160b | ||
|
|
08f4e91b27 | ||
|
|
021237bc38 | ||
|
|
78c36db2f9 | ||
|
|
7fd2562cb5 | ||
|
|
15a3be2e66 | ||
|
|
9b6a540ec6 | ||
|
|
2b51085bc2 | ||
|
|
822134070b | ||
|
|
26cd874779 | ||
|
|
9f21b68541 | ||
|
|
e49d95663b | ||
|
|
2c70392ada | ||
|
|
1b2248b1e7 | ||
|
|
a322dc6353 | ||
|
|
7c78ae47c6 | ||
|
|
a14dec1b7e | ||
|
|
53b5862697 | ||
|
|
83d379c7b5 | ||
|
|
be33db8339 | ||
|
|
97e9924a0b | ||
|
|
7daab55639 | ||
|
|
9d70b7469a | ||
|
|
b5504902c4 | ||
|
|
f5e82ccd75 | ||
|
|
f4c4c21a10 | ||
|
|
661d2440f2 | ||
|
|
f4af8097f6 | ||
|
|
e1822905e7 | ||
|
|
e5154dad5b | ||
|
|
30f8932039 | ||
|
|
c4f0792c77 | ||
|
|
79c7f13ff9 | ||
|
|
dbeeb0c69b | ||
|
|
58c53ff5e2 | ||
|
|
87c441887a | ||
|
|
8ee4dab239 | ||
|
|
e01ebf8d8e | ||
|
|
e92bcd378c | ||
|
|
80156e73d1 | ||
|
|
97803cd860 | ||
|
|
9a5feee095 | ||
|
|
84410056bd | ||
|
|
acd0e41703 | ||
|
|
c7dfb9dca7 | ||
|
|
0efd82bd59 | ||
|
|
426ceff451 | ||
|
|
f2be7ed34c | ||
|
|
5dcc783b95 | ||
|
|
d1c641e934 | ||
|
|
59be63785d | ||
|
|
0bf85ec729 | ||
|
|
b54c2dc254 | ||
|
|
021fcd0641 | ||
|
|
f2dadae7a3 | ||
|
|
7ce7df2625 | ||
|
|
09fcd384ab | ||
|
|
5f8625a384 | ||
|
|
621011af7a | ||
|
|
a0b81941d1 | ||
|
|
e735335773 | ||
|
|
7b62572a56 | ||
|
|
0f921c926b | ||
|
|
4d8a4d23c0 | ||
|
|
9d7eaa46fd | ||
|
|
cc9664f7d6 | ||
|
|
573b3e9d1c | ||
|
|
9808694d89 | ||
|
|
d70d8f5b6e | ||
|
|
b75c2d80bf | ||
|
|
aa747ff651 | ||
|
|
bcbf5daf0d | ||
|
|
aee1c05a45 | ||
|
|
0bb96a8dd3 | ||
|
|
1e1d2c7b63 | ||
|
|
f12375cddc | ||
|
|
ed26e6611a | ||
|
|
98f77eca07 | ||
|
|
1b2b560f8f | ||
|
|
b49cc0c9bd | ||
|
|
4ba58ea861 | ||
|
|
3f52a20c90 | ||
|
|
580089d06e | ||
|
|
1397ab0fa6 | ||
|
|
87400793eb | ||
|
|
45f79d95b1 | ||
|
|
c8a4a61028 | ||
|
|
44091981b2 | ||
|
|
d3352643fc | ||
|
|
114c7fb38a | ||
|
|
dc7da708dc | ||
|
|
72e56aa1c7 | ||
|
|
99ceab07ad | ||
|
|
c0f6c072ce | ||
|
|
e039124f6c | ||
|
|
c96e4a4c7a | ||
|
|
622a08acf3 | ||
|
|
f44b6bf0d0 | ||
|
|
a6d75e15ea | ||
|
|
a02f03c4cb | ||
|
|
d48f5132fb | ||
|
|
ed4ac24efa | ||
|
|
9f3b8a7c2c | ||
|
|
612d4bb1f5 | ||
|
|
b58a50d246 | ||
|
|
af83811d57 | ||
|
|
66835fe6ab | ||
|
|
34cc1d33c6 | ||
|
|
a42d14e3b8 | ||
|
|
87aa165edf | ||
|
|
d217d62007 | ||
|
|
27bcc0d40a | ||
|
|
e1df075cde | ||
|
|
8358692e8d | ||
|
|
e1fae01dab | ||
|
|
d206ab140a | ||
|
|
9d8722ab17 | ||
|
|
c4fa40c403 | ||
|
|
1d0b06bfbe | ||
|
|
2cdf473dcb | ||
|
|
1af9e2c2da | ||
|
|
9a1815fa1e | ||
|
|
f601961c49 | ||
|
|
406acd34c5 | ||
|
|
31cdcbbc25 | ||
|
|
2215ce71c9 | ||
|
|
1872fbb1c8 | ||
|
|
d99f912ac2 | ||
|
|
00a76fb648 | ||
|
|
187e951a47 | ||
|
|
c0b9b27aae | ||
|
|
b76bb17396 | ||
|
|
2efa6d3623 | ||
|
|
3972ce633d | ||
|
|
0dc7901393 | ||
|
|
a25ba6eaa5 | ||
|
|
4ea48dfe57 | ||
|
|
8f7ad8b2ee | ||
|
|
3b9800df07 | ||
|
|
4c80d3234e | ||
|
|
9e4af1d66b | ||
|
|
73555df2ea | ||
|
|
3ca78604fd | ||
|
|
0138046923 | ||
|
|
2129184209 | ||
|
|
dd2116f8a6 | ||
|
|
814c2d9149 | ||
|
|
b3f7276044 | ||
|
|
ad88aa980b | ||
|
|
aca55e9203 | ||
|
|
cc3330bb27 | ||
|
|
1370909db7 | ||
|
|
08cc0c394b | ||
|
|
cb6692aea3 | ||
|
|
b3badb3a55 | ||
|
|
cbf73901d3 | ||
|
|
4822e45d58 | ||
|
|
1d930d36bf | ||
|
|
9effcc403d | ||
|
|
05dcc039bd | ||
|
|
cb08656abc | ||
|
|
69b22fc736 | ||
|
|
bf857f6ce7 | ||
|
|
7ebf2378b3 | ||
|
|
aec25dab37 | ||
|
|
e11969780d | ||
|
|
02c98b1547 | ||
|
|
c864589478 | ||
|
|
bdea1593be | ||
|
|
f6b78c07ca | ||
|
|
982a217d32 | ||
|
|
06588752ad | ||
|
|
9b057d7141 | ||
|
|
93fb3a85b5 | ||
|
|
7320f9ba66 | ||
|
|
a94f43ae0c | ||
|
|
e19a3f02e5 | ||
|
|
375c2c896c | ||
|
|
b151e79aed | ||
|
|
b45901c133 | ||
|
|
fab54ca0ae | ||
|
|
31dd32f19b | ||
|
|
f51c79d282 | ||
|
|
743c943363 | ||
|
|
91f6e266d1 | ||
|
|
8e843647bf | ||
|
|
151402dc50 | ||
|
|
057f340c9c | ||
|
|
f3f9c63156 | ||
|
|
7910a79917 | ||
|
|
cc7acfcd00 | ||
|
|
5580e208f5 | ||
|
|
56ef06d651 | ||
|
|
204dfca126 | ||
|
|
eb337a8aaf | ||
|
|
aa6fd781e8 | ||
|
|
32bcfa1d42 | ||
|
|
3b2e14d0de | ||
|
|
88a0ce38f9 | ||
|
|
110c8337aa | ||
|
|
3dc79fea6b | ||
|
|
fb036385f9 | ||
|
|
428bb2817b | ||
|
|
791caff240 | ||
|
|
d92015d071 | ||
|
|
de98bd9e0b | ||
|
|
67f5a7794a | ||
|
|
fbef94f634 | ||
|
|
0e8363f06e | ||
|
|
a1bafe0426 | ||
|
|
c51461592c | ||
|
|
ef5f996ec4 | ||
|
|
aa5998a52e | ||
|
|
37207c1cb0 | ||
|
|
d1813fdbc7 | ||
|
|
faf9d1d6f8 | ||
|
|
0360df0604 | ||
|
|
fe6487eeb4 | ||
|
|
b9eedd1cf6 | ||
|
|
26281b8f0b | ||
|
|
f0508fdf93 | ||
|
|
166d69c7ec | ||
|
|
fabf08ba55 | ||
|
|
0e5d8af0e9 | ||
|
|
3e1263ebff | ||
|
|
c0ed830241 | ||
|
|
4209158807 | ||
|
|
6d79ebf449 | ||
|
|
88ab691f07 | ||
|
|
37b1dc574c | ||
|
|
ad56e249ed | ||
|
|
f28cfe3d69 | ||
|
|
9643442281 | ||
|
|
dd44ec7ac1 | ||
|
|
801c1126cf | ||
|
|
4fd72efc46 | ||
|
|
9ec045cb21 | ||
|
|
52801ee94c | ||
|
|
2077d53964 | ||
|
|
14046e9217 | ||
|
|
2766debffc | ||
|
|
4f4688899c | ||
|
|
8151db9696 | ||
|
|
227c61b588 | ||
|
|
61224fba7b | ||
|
|
1dbf5516d8 | ||
|
|
10fe6ac32a | ||
|
|
e39ee66726 | ||
|
|
fff2db75d0 | ||
|
|
3a14db53c6 | ||
|
|
8b76b82e0f | ||
|
|
e110c55e1a | ||
|
|
85c30fbad3 | ||
|
|
14e5c74c65 | ||
|
|
b180e31b56 | ||
|
|
d172a45891 | ||
|
|
e74289116e | ||
|
|
68b932bad0 | ||
|
|
c4793e849c | ||
|
|
1c525a6d2e | ||
|
|
c8610ee16a | ||
|
|
0fb3bc1106 | ||
|
|
3cf133d750 | ||
|
|
f0be6b0bc9 | ||
|
|
e0ccb8b10d | ||
|
|
940afae1fd | ||
|
|
94ba339ef2 | ||
|
|
bfead10d87 | ||
|
|
97f9a73fc1 |
2
.github/ISSUE_TEMPLATE/feature-request.md
vendored
2
.github/ISSUE_TEMPLATE/feature-request.md
vendored
@@ -10,7 +10,7 @@ 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 Core 3.1 and .NET 5.0 have known limitations, so make sure that what you're asking for isn't already in another build.
|
||||
- .NET 6.0 has known limitations, so make sure that what you're asking for isn't already in another build.
|
||||
- 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...
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/informational.md
vendored
2
.github/ISSUE_TEMPLATE/informational.md
vendored
@@ -10,7 +10,7 @@ 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 Core 3.1 and .NET 5.0 have known limitations, so make sure that what you're giving information on isn't already in another build.
|
||||
- .NET 6.0 has known limitations, so make sure that what you're giving information on isn't already in another build.
|
||||
- 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...
|
||||
|
||||
5
.github/ISSUE_TEMPLATE/issue-report.md
vendored
5
.github/ISSUE_TEMPLATE/issue-report.md
vendored
@@ -10,7 +10,7 @@ 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 Core 3.1 and .NET 5.0 have known issues, please try using another build to reproduce the error
|
||||
- .NET 6.0 has known issues, please try using another build to reproduce the error
|
||||
- Check multiple discs to help narrow down the issue
|
||||
- Check the Options to see if changing any of those affects your issue.
|
||||
|
||||
@@ -25,9 +25,8 @@ What version are you using?
|
||||
**Build**
|
||||
What runtime version are you using?
|
||||
|
||||
- [ ] .NET Framework 4.7.2 running on (Operating System)
|
||||
- [ ] .NET Framework 4.8 running on (Operating System)
|
||||
- [ ] .NET Core 3.1 running on (Operating System)
|
||||
- [ ] .NET 6.0 running on (Operating System)
|
||||
|
||||
**Describe the issue**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "MPF.Library/Aaru/CICMMetadata"]
|
||||
path = MPF.Library/Aaru/CICMMetadata
|
||||
url = https://github.com/claunia/CICMMetadata
|
||||
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@@ -10,9 +10,9 @@
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/MPF/bin/Debug/netcoreapp3.1/MPF.dll",
|
||||
"program": "${workspaceFolder}/MPF.Check/bin/Debug/net6.0/MPF.Check.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/MPF",
|
||||
"cwd": "${workspaceFolder}/MPF.Check",
|
||||
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false
|
||||
|
||||
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"omnisharp.projectLoadTimeout": 480
|
||||
}
|
||||
15
.vscode/tasks.json
vendored
15
.vscode/tasks.json
vendored
@@ -3,25 +3,22 @@
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"command": "dotnet",
|
||||
"command": "msbuild",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/MPF/MPF.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
"${workspaceFolder}/MPF.sln",
|
||||
"-property:RuntimeIdentifiers=win7-x64"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "publish",
|
||||
"command": "dotnet",
|
||||
"command": "msbuild",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"publish",
|
||||
"${workspaceFolder}/MPF/MPF.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
"-target:Publish",
|
||||
"-property:RuntimeIdentifiers=win7-x64"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
|
||||
542
CHANGELIST.md
542
CHANGELIST.md
@@ -1,4 +1,542 @@
|
||||
### 2.6.2 (2023-07-25)
|
||||
|
||||
- Ensure custom parameters properly set
|
||||
- Universal hash only for audio discs
|
||||
- Support LibCrypt data from Redumper
|
||||
- Always show extension for Redumper
|
||||
- Normalize old universal hash text
|
||||
- Skip extra tracks during checking
|
||||
- Modify the track count on checking
|
||||
- Attempt to match universal hash
|
||||
- Fix .NET Framework 4.8 build
|
||||
- Fix universal hash URL generation
|
||||
- Add Windows publish script
|
||||
- Add *nix publish script
|
||||
- Add build instructions to README
|
||||
- Clarify build instructions
|
||||
|
||||
### 2.6.1 (2023-07-19)
|
||||
|
||||
- Simplify Redumper error value extraction
|
||||
- Don't pull comment fields that auto-populate
|
||||
- Set best compression levels for log files
|
||||
- Be more explicit about .NET 6 limitation
|
||||
- Set extensions for Redumper in UI
|
||||
- Fix comment field pulling again
|
||||
|
||||
### 2.6 (2023-07-14)
|
||||
|
||||
- Update README
|
||||
- Add warning to login tab
|
||||
- Pull hardware info from redumper log (fuzz6001)
|
||||
- Increase the version of AppVeyor (fuzz6001)
|
||||
- Add Windows 7 note to README
|
||||
- Update redumper to build 113
|
||||
- Split MMI invocation in drive listing
|
||||
- Update README
|
||||
- Add Hasbro iON
|
||||
- Get the write offset from the latest redumper (fuzz6001)
|
||||
- Update redumper to build 115
|
||||
- Update to DIC 20230401
|
||||
- Add DIC `.` notice to README
|
||||
- Resync with Redump
|
||||
- Update redumper to build 118
|
||||
- Clarify non-Redump systems
|
||||
- Add UltraCade
|
||||
- Re-enable BD33 and BD66
|
||||
- Add PIC models for BD (unused)
|
||||
- Handle PIC based on disc type
|
||||
- UMDs always have "2 layers"
|
||||
- Add dumping program selection to main UI
|
||||
- Update to DIC 20230413
|
||||
- Comment out `.` handling for DIC
|
||||
- Ensure dumping program box can enable/disable
|
||||
- Disable special SmartE handling for DIC
|
||||
- Remove path from PS1/PS2 serial
|
||||
- Make TOC file optional for CD/GD
|
||||
- Add datafile models
|
||||
- Add datafile helper method
|
||||
- Start migrating to datafile serialization
|
||||
- Prepare for future DIC changes
|
||||
- Add suppl support to Xbox
|
||||
- Support single digit subs
|
||||
- Fix info tool hash finding
|
||||
- Fix missing size for ISO data
|
||||
- Attempt to more accurately parse layerbreaks
|
||||
- Fix upcoming suppl DAT parsing
|
||||
- Ensure blank lines don't interfere
|
||||
- De-indent ringcode data
|
||||
- Be more specific with runtime identifiers
|
||||
- Fix subdump output path in AV config
|
||||
- Fix subdump mkdir path in AV config
|
||||
- Single file packing for .NET 6 again
|
||||
- Add missing BD disc type identifier string
|
||||
- Truncate PIC data for PS4/PS5
|
||||
- Add internal theme support with class
|
||||
- Add PIC identifier to SubmissionInfo
|
||||
- Fix other media type method
|
||||
- Fix non-zero offset text
|
||||
- Add executable listing for XSX
|
||||
- Update redumper to build 151
|
||||
- Add more safety to DAT generation
|
||||
- Get write offset from redumper 119 (fuzz6001)
|
||||
- Update hardware information pull from redumper (fuzz6001)
|
||||
- Add MCD/SS header support for Redumper
|
||||
- Fix MCD region(s) parsing
|
||||
- Update to DIC 20230606
|
||||
- Update redumper to build 166
|
||||
- Unblock Redumper DVD support
|
||||
- Support Redumper DVD layerbreak
|
||||
- Add placeholder and TODOs for Redumper
|
||||
- Add TODO with notes to Redumper
|
||||
- Fix 2-layer DVD support in Redumper
|
||||
- Fix VSCode build
|
||||
- Fix Redumper DAT/layer parsing
|
||||
- Update Redumper PS1 output parsing
|
||||
- Fix previous commit, clean up helpers
|
||||
- Update redumper to build 173
|
||||
- Initial support for Redumper CSS outputs
|
||||
- Hook up CSS output for testing
|
||||
- Update redumper to build 174
|
||||
- Add support for redumper CD synonyms
|
||||
- Adjust CSS title key parsing
|
||||
- Fix non-reading loop
|
||||
- Normalize Redumper CSS outputs
|
||||
- Normalize multi-instance site tags
|
||||
- Add missing Aaru error log to zip
|
||||
- Check Redumper dat section for completeness
|
||||
- Update redumper to build 176
|
||||
- UMDs are Sony discs
|
||||
- Strip colons from Redumper disc key
|
||||
- Use `HashSet` for disc or book type
|
||||
- Add ordering to disc or book type
|
||||
- Update redumper to build 183
|
||||
- Parse and format Redumper CD multisession data
|
||||
- New layerbreak takes precedence
|
||||
- Reduce pulled information for Xbox and X360
|
||||
- Ensure we found the tags we're skipping
|
||||
- Omit pulling universal hash
|
||||
- Update Nuget packages to newest stable
|
||||
|
||||
### 2.5 (2023-03-12)
|
||||
|
||||
- Add _drive file to zip for UIC
|
||||
- Add Xbox Series X and PS5 to list, fix Acorn
|
||||
- Add Xbox Series X short name to list
|
||||
- Remove windows from test target
|
||||
- Remove .NET 6.0 from tests, add TODO
|
||||
- Add .NET 6.0 to tests, remove msbuild args
|
||||
- Add HD-DVD to speed definitions
|
||||
- Add PS3 internal serial and version parsing (tjanas)
|
||||
- Update Nuget packages to newest stable
|
||||
- Simplify path selection in UI
|
||||
- Fix broken normalization test
|
||||
- Update drive info before dumping
|
||||
- Update redumper strings
|
||||
- Add new parameter and mode validation
|
||||
- Add redumper to the UI
|
||||
- Update redumper to build 81
|
||||
- Fix incorrect naming in Options window
|
||||
- Initial attempt at parsing redumper outputs
|
||||
- Update README
|
||||
- Reenable write offset for all CDs
|
||||
- Add missing redumper output file
|
||||
- Force a filename for redumper
|
||||
- Fix incorrect SetParameters
|
||||
- Fix a couple redumper things
|
||||
- Update AppVeyor version
|
||||
- Output security sectors to info
|
||||
- Remove x86 requirement for build
|
||||
- Fix XGD media type outputs
|
||||
- Fix typo in ToInternalProgram
|
||||
- Fix redumper error count parsing
|
||||
- Update to Aaru v5.3.2 LTS
|
||||
- Update options loader with sane defaults
|
||||
- Fix AppVeyor pathing
|
||||
- Skip during detection
|
||||
- Address some UI concerns
|
||||
- Tweak AppVeyor, show Check 6.0 builds
|
||||
- More strict when custom parameters editing
|
||||
- Use msbuild for .NET Framework 4.8
|
||||
- Update nuget packages
|
||||
- ReadAllText not ReadAllLines
|
||||
- Add drive format (fs) to log
|
||||
- Go back to pre .NET 7 Aaru
|
||||
- Be smarter about old paths
|
||||
- Fix relative paths for DIC
|
||||
- Add nicer failure message
|
||||
- Update to DIC 20230201
|
||||
- Use relative path output for DIC
|
||||
- Remove usage of Aaru
|
||||
- Remove Aaru as submodule
|
||||
- Fix Aaru removal
|
||||
- Enable .NET 6 Windows builds
|
||||
- Update Redumper to build_106
|
||||
- Reformat CICM for old .NET versions
|
||||
- Attempt to handle no drives
|
||||
- Handle no drives better
|
||||
- Handle no drives betterer
|
||||
- Packaging requires `-windows` for framework
|
||||
- Fix other `-windows` places for .NET 6
|
||||
- Fix typo in DICMultiSectorReadValue
|
||||
- Semi-unify drive finding
|
||||
- Introduce cross-platform MMI
|
||||
- Remove System.Management
|
||||
- Add Redumper Universal Hash support
|
||||
- Fix Redumper write offset support
|
||||
- Add Redumper non-zero data start
|
||||
- Use media size for type detection on .NET 6
|
||||
- Trim PIC for PS3
|
||||
- Get the version of redumper (fuzz6001)
|
||||
- Update VSCode config files
|
||||
- Can't publish single file for UI
|
||||
- Handle missing extension gracefully
|
||||
- Fix incorrect option slider display
|
||||
- Handle undetected discs on refresh
|
||||
- Originally intended behaviour of the Update Label button (IcySon55)
|
||||
- Update to BurnOutSharp 2.7.0
|
||||
- Get error count from recent redumper log (fuzz6001)
|
||||
- Minor cosmetic changes
|
||||
- Set saner defaults for dumping speeds
|
||||
- Attempt to support Windows 7
|
||||
- Add `win7-x64` to identifier list
|
||||
- Remove unsupported identifiers
|
||||
- Add identifiers in more places
|
||||
- Move drive finding inside of the try/catch
|
||||
- Update to DIC 20230309
|
||||
- Fix errant forward slashes
|
||||
- Add TOC back as optional file
|
||||
- Fix Redumper path generation
|
||||
- Use and trim quotes for Redumper
|
||||
- Fix incorrect image name setting
|
||||
- Ensure Redumper parameters are set
|
||||
- Ensure min values are taken care of
|
||||
- Update parameters with `=` handling
|
||||
- Ensure drive and speed are set
|
||||
- Handle quotes embedded
|
||||
- Return list of missing files for Redumper
|
||||
- Readd accidentally deleted line
|
||||
- Detect EOF during the search for error counts (fuzz6001)
|
||||
|
||||
### 2.4 (2022-10-26)
|
||||
|
||||
- Update to DIC 20211001
|
||||
- Fix Redump disc title pulling
|
||||
- Add /mr default flag options
|
||||
- Make FillFromRedump private again
|
||||
- Fix DVD layer finding corner case
|
||||
- Fix failing module tests
|
||||
- Add option to limit region and language selections
|
||||
- Cap X360 directory check to 500MB
|
||||
- Assign normalized path to parameters
|
||||
- Move path normalization to better place
|
||||
- Specifically include Unsafe Nuget package
|
||||
- Update Nuget packages to newest stable
|
||||
- Add Xbox One system detection
|
||||
- Update to DIC 20220301
|
||||
- Force internal drive refresh
|
||||
- Add single drive refresh button (IcySon55)
|
||||
- Fix "missing" option in window
|
||||
- Track last used drive on refresh
|
||||
- Clean up pre-dump validation
|
||||
- Update to Aaru v5.3.1 LTS
|
||||
- Add upper case `<TAB>` processing
|
||||
- Reorder event handers
|
||||
- Handle sanitized protections edge case
|
||||
- Update Aaru Nuget package
|
||||
- Return faster on empty protection sets
|
||||
- Remove redundant check around volume label
|
||||
- Fix tabs in Games and Videos boxes
|
||||
- Make fully and partially matching IDs more apparent
|
||||
- Add write offset as read-only field
|
||||
- Explicitly clear list, just in case
|
||||
- Add both fully and partially matching to info file
|
||||
- Fix submission info clone
|
||||
- Clear out fully matched IDs from the partial list
|
||||
- Refine copy protection section showing
|
||||
- Update Nuget packages
|
||||
- Normalize newlines in comments and contents
|
||||
- Increase JSON accuracy for disc types
|
||||
- Further separate out protection scan outputs
|
||||
- Compress JSON for artifacts alone
|
||||
- Even stricter output for copy protection section
|
||||
- Report dictionary to InfoTool
|
||||
- Even even stricter copy protection output
|
||||
- Disable PVD creation for Aaru
|
||||
- Explicitly sanitize '?' from path
|
||||
- Combine cases in protection scan
|
||||
- Convert status label to TextBlock
|
||||
- Add option for copy protection file output
|
||||
- Make protection field user-editable
|
||||
- Add warning to tooltip
|
||||
- Create core UI library
|
||||
- Rename MPF.GUI to MPF.UI
|
||||
- Add multisession pseudo-tag
|
||||
- Add multisession helper method skeleton
|
||||
- Move and update options loader; clean up Check
|
||||
- Move helper methods around
|
||||
- Consolidate Redump login testing
|
||||
- Separate common arguments to new helper
|
||||
- Parse and format CD multisession data
|
||||
- Convert triple space to tab
|
||||
- Fix clone issue with copy protection
|
||||
- Be more picky about multisession
|
||||
- Sanitize whitespace around tabs
|
||||
- Convert internal libraries to .NET Standard 2.0
|
||||
- Update AppVeyor to VS2022
|
||||
- Update Nuget packages
|
||||
- Remove needless csproj constants
|
||||
- Update copyright date to 2022
|
||||
- Revert AppVeyor to VS2019 for now
|
||||
- Add size-based media type detection for non-Framework
|
||||
- Gate ManagmentObject use further
|
||||
- Use built-in NETFRAMEWORK directive
|
||||
- Update to BurnOutSharp 2.1.0
|
||||
- .NET 6.0 and Cleanup
|
||||
- Remove .NET Core 3.1 from test project for now
|
||||
- Remove .NET Core 3.1 entirely
|
||||
- Add filesystem logging for .NET 6
|
||||
- Avoid whitespace changes for PVD, Header, and Cuesheet
|
||||
- Sync to newest CICM
|
||||
- Update solution file for VS2022
|
||||
- Add Aaru as a submodule for .NET 6
|
||||
- Multisession is multi-line
|
||||
- Use Aaru for media type retrival (.NET 6)
|
||||
- Fix CD-R multisession info
|
||||
- Better get drive list (.NET 6)
|
||||
- Add optical media support method (.NET 6)
|
||||
- Simplify IsOptical (.NET 6)
|
||||
- Reorganize GetMediaType
|
||||
- Possibly fix tab regex replacement
|
||||
- Add PIC.bin to log zip
|
||||
- Organize projects in solution
|
||||
- Implement Drive.Create for safety
|
||||
- Fix incomplete system name detection
|
||||
- Add Sharp X68k detection
|
||||
- Add Bandai Playdia QIS detection
|
||||
- Framework for XBONE filenames
|
||||
- Add files for XBONE
|
||||
- Update to DIC 20220707
|
||||
- Fix .bin file paths; update internal filename generation
|
||||
- Disable nonstandard BD-ROM sizes
|
||||
- Trim leading file paths for XBONE
|
||||
- Give .NET 6 priority for web calls
|
||||
- Update to BurnOutSharp 2.3.0 (nw)
|
||||
- Add Mattel Fisher-Price iXL detection
|
||||
- Update to BurnOutSharp 2.3.1 (nw)
|
||||
- Fix serial parsing for Dreamcast
|
||||
- Fix missing parenthesis
|
||||
- Add internal name for Cleanrip outputs
|
||||
- Fix psxt001z namespace
|
||||
- Fix missing assignment
|
||||
- Update to new constructor
|
||||
- Update PSX content check
|
||||
- Update Aaru submodule to latest devel
|
||||
- Add Sony Electronic Book system
|
||||
- Verify GD-ROM outputs, finally
|
||||
- Electronic not Electric
|
||||
- Fix ringcode guide images
|
||||
- Add skeleton for Redumper
|
||||
- Download Redumper with AppVeyor
|
||||
- Add Redumper constants
|
||||
- Add Redumper parameter values
|
||||
- Add Redumper command support and reset
|
||||
- Add Redumper dumping command
|
||||
- Add Redumper command validation
|
||||
- Add Redumper command generation
|
||||
- Create Redumper extensions class
|
||||
- Minor Redumper cleanup
|
||||
- Add important Redumper note
|
||||
- Update to DIC 20220909
|
||||
- Possibly fix PIC parsing
|
||||
- Add PS3 folder/file checks for detection
|
||||
- Use default directory for folder browsing, if possible
|
||||
- Add unused command filename parser
|
||||
- Add initial framework for reporting dumping program
|
||||
- Report specific DIC version, if possible
|
||||
- Add dumping info section skeleton
|
||||
- Update Aaru submodules
|
||||
- Fix missing info reference change
|
||||
- Enable separated protection info output by default
|
||||
- Try adding MPF logs to zip
|
||||
- Create MPF log helper and filter for deletion
|
||||
- Fix missing info in Aaru
|
||||
- Add hardware info to DIC and Aaru
|
||||
- Fix hardware info
|
||||
- Add specialized CDS/SafeDisc filter
|
||||
- Add unused article formatter
|
||||
- Add language filtering to formatter
|
||||
- Add multi-language helper for filter
|
||||
- Update Nuget packages
|
||||
- Remove deprecated protection setting
|
||||
- Update BurnOutSharp to 2.3.4
|
||||
- Add compression result reason to log
|
||||
- Add System.Memory package to MPF.Library
|
||||
- Add CodePages package to MPF.Library
|
||||
- Remove extraneous packages
|
||||
- Change location of dumping info
|
||||
- Add MS ZipFile package to MPF.Library
|
||||
- Add + to positive offsets
|
||||
- Disable layerbreak generation for BD
|
||||
- Disable XGD version reporting
|
||||
- Disable XGD layerbreak reporting
|
||||
- Disable XGD1 PVD reporting
|
||||
- Put Redump limitations behind existing flag
|
||||
- Add framework for reported disc type
|
||||
- Add disc type parsing for Aaru and DIC
|
||||
- Fix multiple DiscType for DIC
|
||||
- Fix multiple DiscType* for DIC
|
||||
- Add logging to !submissionInfo writing failure
|
||||
- Add logging to !submissionInfo formatting failure
|
||||
- Update issue templates to be more accurate
|
||||
- Fix NRE with offsets
|
||||
- Fix readonly Filename info display
|
||||
- Fix layerbreak-based checks
|
||||
- Add PS4 serial finding (tjanas)
|
||||
- Add unused notification method
|
||||
- Move to unused Chime class
|
||||
- Add PS5 serial finding (tjanas)
|
||||
- Fix offset formatting (fuzz6001)
|
||||
|
||||
### 2.3 (2022-02-05)
|
||||
|
||||
- Start overhauling Redump information pulling, again
|
||||
- Add internal structure for special site codes
|
||||
- Add new tabs for special site information
|
||||
- Clean up default handling of fields
|
||||
- Try to handle multi-line fields during parsing
|
||||
- Fix CSSKey log handling
|
||||
- Show most read-only fields in new tab
|
||||
- Add horizontal scroll to user input
|
||||
- Tweak new disc information fields and tabs
|
||||
- Allow internal serial and volume label to be hidden
|
||||
- Be smarter about showing update checks
|
||||
- Ensure all fields are read-only on read-only tab
|
||||
- Add model for 2-layer ringcode guide
|
||||
- Add first attempt 2-layer ringcode guide
|
||||
- Add even more safety to clone
|
||||
- Sanitize filename after check
|
||||
- Handle pulled linebreaks better
|
||||
- Skip anti-modchip string in some cases
|
||||
- Handle pulled linebreaks better, again
|
||||
- Tweak more Disc Info window formatting
|
||||
- Skip unnecessary newlines in parsing
|
||||
- Force scroll visibility, tweak text sizes again
|
||||
- Fix newline skipping
|
||||
- Add missing continue statement
|
||||
- Add newlines for mutliline special fields
|
||||
- Omit volume label for "Audio CD"
|
||||
- Remove Enter/Escape registration on disc info window
|
||||
- Logically group more things in disc info window
|
||||
- Remove tab key from disc info window
|
||||
- Add `<tab>` processing
|
||||
- Unban newly opened consoles
|
||||
- Tweak minimalized layout a bit more
|
||||
- Add tab setting
|
||||
- Further disc info window tweaks
|
||||
- Changed IsEnabled to IsReadOnly
|
||||
- Fix scrolling issues in disc info window
|
||||
- Convert postgap and VCD fields to checkboxes
|
||||
- Adjust width ratios for disc info window
|
||||
- Fix IsReadOnly
|
||||
- Only include booleans if the value is true
|
||||
- Add hidden debug option for "ShowDebugViewMenuItem"
|
||||
- Fix incorrect header check
|
||||
- Make protection read-only field multiline
|
||||
- Reformat Saturn internal date
|
||||
- Fix Sega CD internal serial reading
|
||||
- Fix crash on invalid parameters
|
||||
- Differentiate XMID and XeMID
|
||||
- Conditionally pull region from Redump
|
||||
- Be smarter about volume labels
|
||||
- Use volume label in checks, not formatted version
|
||||
- Sync with Redump region and language selection
|
||||
- Try to delete old log archive before writing
|
||||
- Add support for all ISO language codes
|
||||
- Add support for all ISO region codes
|
||||
- Ensure ordering in output site tags
|
||||
- Make site code formatting helper method
|
||||
- Better helper method organization
|
||||
- Start supporting ordered tags and non-tags
|
||||
- Add more non-tag support; rearrange info window
|
||||
- Fix incorrect language three-letter code
|
||||
- Hook up additional Xbox field to disc info window
|
||||
- Fix non-tag tag shortnames
|
||||
- Fix parsing of non-tag tags again
|
||||
- Disable unnecessary cuesheet parsing
|
||||
- Fix incorrect region two-letter code
|
||||
- Adjust long names for some languages
|
||||
- Add Sierra ID to list of pseudo-tags
|
||||
- Add another hand-formatted version of SS tag
|
||||
- Move internal serial before volume label
|
||||
- Check for $SystemUpdate folder for X360 discs
|
||||
- Slightly rename UK and USA regions for UI
|
||||
- Add another hand-formatted version of SS tag
|
||||
- Add verification reminders for pulled tags
|
||||
- Read longer string for Saturn internal serial
|
||||
- Ensure version only pulled if one doesn't exist
|
||||
- Ensure Games pseudo-tag is multi-line
|
||||
- Add alternate pseudo-tag for Playable Demos
|
||||
- Make error clearer if something is unsupported in Check
|
||||
- Ensure drive is not null for volume labels
|
||||
- Check explicitly for no matches on Redump pull
|
||||
- Normalize PS1/PS2 executable names
|
||||
- Adjust paths for DIC just before dumping
|
||||
|
||||
### 2.2 (2021-12-30)
|
||||
|
||||
- Fix Saturn header finding
|
||||
- Add Pocket PC support
|
||||
- Add HD-DVD-Video support
|
||||
- Convert to using separate Redump library code
|
||||
- Update to Aaru v5.3.0-rc1
|
||||
- Update to BurnOutSharp 1.8.0
|
||||
- Update support packages
|
||||
- Add on-startup "check for updates" option
|
||||
- Update to Aaru v5.3.0-rc2
|
||||
- Add .NET 5.0 as build target
|
||||
- Remove .NET Core 3.1 and .NET 5.0 from AppVeyor build artifacts
|
||||
- Null-safeguard RedumpLib conversions
|
||||
- Move cuesheet code to separate DLL
|
||||
- Move CICMMetadata to top-level
|
||||
- Separate out remaining functionality into individual DLLs
|
||||
- Update to Aaru v5.3.0 LTS
|
||||
- Update to DIC 20211001
|
||||
- HTTP encode password for Redump login, again
|
||||
- Fix NullReferenceException in anti-modchip scans
|
||||
- Update arcade metadata (Shizmob)
|
||||
- Add JSON output option for MPF.Check
|
||||
- Fix JSON output serialization
|
||||
- Ensure corrupt directories on media don't throw errors
|
||||
- Add retry to Redump external calls
|
||||
- Make anti-modchip scans even safer
|
||||
- Remove lower bound checking on LBA values for DIC
|
||||
- Remove offset for audio discs on DIC output
|
||||
- Start adding regression tests for DIC
|
||||
- Ensure parameters box is safer during options save
|
||||
- Fix protection sanitization and add regression tests
|
||||
- Update to DIC 20211101
|
||||
- Add protection sanitization for StarForce
|
||||
- Trim filenames for DVD protection from DIC
|
||||
- Fill out internal tests around Redump library
|
||||
- Refine the "missing disc" text
|
||||
- Overhaul XeMID handling
|
||||
- Fix output dialog issues in Options window
|
||||
- Fix saving path settings if set from dialog
|
||||
- Allow default system if skipping system detection enabled
|
||||
- Add internal support for all Redump site codes
|
||||
- Use the Volume Label special site code
|
||||
- Capture newlines in Redump fields
|
||||
- Invert condition for volume label
|
||||
- Fix missing ISN usages
|
||||
- Fix ISN string
|
||||
- Validate track count when matching Redump
|
||||
- Allow for better matching of multi track discs
|
||||
- Temporarily disable pulling comments from Redump pages
|
||||
- Add safety around volume labels
|
||||
|
||||
### 2.1 (2021-07-22)
|
||||
|
||||
- Enum, no more
|
||||
- Sony works backward
|
||||
- Add experimental dark mode
|
||||
@@ -28,6 +566,7 @@
|
||||
- Update to BurnOutSharp 1.7.0
|
||||
|
||||
### 2.0 (2021-04-23)
|
||||
|
||||
- Rename DICUI to Media Preservation Frontend (MPF)
|
||||
- Add handling for BEh drive _mainInfo.txt changes
|
||||
- Fix multiline regex fields during info pulling
|
||||
@@ -82,6 +621,7 @@
|
||||
- Update to BurnOutSharp 1.6.1
|
||||
|
||||
### 1.18 (2020-11-10)
|
||||
|
||||
- Add more information extraction and generation for Aaru
|
||||
- Remove instances of CD Check from copy protection (again, sorry)
|
||||
- Fix multiline submission info outputs
|
||||
@@ -106,6 +646,7 @@
|
||||
- Added HD-DVD-Video detection
|
||||
|
||||
### 1.17.1 (2020-09-14)
|
||||
|
||||
- Shuffled some shared, internal UI variables
|
||||
- Synced WPF and Avalonia UI internals
|
||||
- Made the disc information window less prone to bugs
|
||||
@@ -113,6 +654,7 @@
|
||||
- Added support for old(?) DIC flags: `/fix` and `/re`
|
||||
|
||||
### 1.17 (2020-09-12)
|
||||
|
||||
- Updated to Aaru version 5.1
|
||||
- Updated to BurnOutSharp version 1.4.0
|
||||
- Updated to DIC version 20200716
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net48;netcoreapp3.1</TargetFrameworks>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<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-2021</Copyright>
|
||||
<Copyright>Copyright (c)2019-2023</Copyright>
|
||||
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
|
||||
<Version>2.1</Version>
|
||||
<Version>2.6.2</Version>
|
||||
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||
<FileVersion>$(Version)</FileVersion>
|
||||
<IncludeSource>true</IncludeSource>
|
||||
@@ -28,10 +28,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="1.7.0" GeneratePathProperty="true">
|
||||
<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.1">
|
||||
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
@@ -42,10 +42,9 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj">
|
||||
<Project>{51ab0928-13f9-44bf-a407-b6957a43a056}</Project>
|
||||
<Name>MPF.Library</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
|
||||
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj" />
|
||||
<ProjectReference Include="..\RedumpLib\RedumpLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp;
|
||||
using MPF.Data;
|
||||
using MPF.Redump;
|
||||
using MPF.Utilities;
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.Utilities;
|
||||
using MPF.Library;
|
||||
using RedumpLib.Data;
|
||||
using RedumpLib.Web;
|
||||
|
||||
namespace MPF.Check
|
||||
{
|
||||
@@ -11,120 +14,17 @@ namespace MPF.Check
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// Help options
|
||||
if (args.Length == 0 || args[0] == "-h" || args[0] == "-?")
|
||||
{
|
||||
DisplayHelp();
|
||||
// Try processing the standalone arguments
|
||||
if (ProcessStandaloneArguments(args))
|
||||
return;
|
||||
}
|
||||
|
||||
// List options
|
||||
if (args[0] == "-lm" || args[0] == "--listmedia")
|
||||
{
|
||||
ListMediaTypes();
|
||||
Console.ReadLine();
|
||||
// Try processing the common arguments
|
||||
(bool success, MediaType mediaType, RedumpSystem? knownSystem) = ProcessCommonArguments(args);
|
||||
if (!success)
|
||||
return;
|
||||
}
|
||||
else if (args[0] == "-lp" || args[0] == "--listprograms")
|
||||
{
|
||||
ListPrograms();
|
||||
Console.ReadLine();
|
||||
return;
|
||||
}
|
||||
else if (args[0] == "-ls" || args[0] == "--listsystems")
|
||||
{
|
||||
ListKnownSystems();
|
||||
Console.ReadLine();
|
||||
return;
|
||||
}
|
||||
|
||||
// Normal operation check
|
||||
if (args.Length < 3)
|
||||
{
|
||||
DisplayHelp("Invalid number of arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the MediaType
|
||||
var mediaType = Converters.ToMediaType(args[0].Trim('"'));
|
||||
if (mediaType == MediaType.NONE)
|
||||
{
|
||||
DisplayHelp($"{args[0]} is not a recognized media type");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the KnownSystem
|
||||
var knownSystem = Converters.ToKnownSystem(args[1].Trim('"'));
|
||||
if (knownSystem == KnownSystem.NONE)
|
||||
{
|
||||
DisplayHelp($"{args[1]} is not a recognized system");
|
||||
return;
|
||||
}
|
||||
|
||||
// Default values
|
||||
string username = null, password = null;
|
||||
string internalProgram = "DiscImageCreator";
|
||||
string path = string.Empty;
|
||||
bool scan = false, compress = false;
|
||||
|
||||
// Loop through and process options
|
||||
int startIndex = 2;
|
||||
for (; startIndex < args.Length; startIndex++)
|
||||
{
|
||||
// Redump login
|
||||
if (args[startIndex].StartsWith("-c=") || args[startIndex].StartsWith("--credentials="))
|
||||
{
|
||||
string[] credentials = args[startIndex].Split('=')[1].Split(';');
|
||||
username = credentials[0];
|
||||
password = credentials[1];
|
||||
}
|
||||
else if (args[startIndex] == "-c" || args[startIndex] == "--credentials")
|
||||
{
|
||||
username = args[startIndex + 1];
|
||||
password = args[startIndex + 2];
|
||||
startIndex += 2;
|
||||
}
|
||||
|
||||
// Use specific program
|
||||
else if (args[startIndex].StartsWith("-u=") || args[startIndex].StartsWith("--use="))
|
||||
{
|
||||
internalProgram = args[startIndex].Split('=')[1];
|
||||
}
|
||||
else if (args[startIndex] == "-u" || args[startIndex] == "--use")
|
||||
{
|
||||
internalProgram = args[startIndex + 1];
|
||||
startIndex++;
|
||||
}
|
||||
|
||||
// Use a device path for physical checks
|
||||
else if (args[startIndex].StartsWith("-p=") || args[startIndex].StartsWith("--path="))
|
||||
{
|
||||
path = args[startIndex].Split('=')[1];
|
||||
}
|
||||
else if (args[startIndex] == "-p" || args[startIndex] == "--path")
|
||||
{
|
||||
path = args[startIndex + 1];
|
||||
startIndex++;
|
||||
}
|
||||
|
||||
// Scan for protection (requires device path)
|
||||
else if (args[startIndex].StartsWith("-s") || args[startIndex].StartsWith("--scan"))
|
||||
{
|
||||
scan = true;
|
||||
}
|
||||
|
||||
// Compress log and extraneous files
|
||||
else if (args[startIndex].StartsWith("-z") || args[startIndex].StartsWith("--zip"))
|
||||
{
|
||||
compress = true;
|
||||
}
|
||||
|
||||
// Default, we fall out
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
(Core.Data.Options options, string path, int startIndex) = OptionsLoader.LoadFromArguments(args, startIndex: 2);
|
||||
|
||||
// Make new Progress objects
|
||||
var resultProgress = new Progress<Result>();
|
||||
@@ -132,20 +32,14 @@ namespace MPF.Check
|
||||
var protectionProgress = new Progress<ProtectionProgress>();
|
||||
protectionProgress.ProgressChanged += ProgressUpdated;
|
||||
|
||||
// If credentials are invalid, alert the user
|
||||
if (!string.IsNullOrWhiteSpace(username) && !string.IsNullOrWhiteSpace(password))
|
||||
{
|
||||
using (RedumpWebClient wc = new RedumpWebClient())
|
||||
{
|
||||
bool? loggedIn = wc.Login(username, password);
|
||||
if (loggedIn == true)
|
||||
Console.WriteLine("Redump username and password accepted!");
|
||||
else if (loggedIn == false)
|
||||
Console.WriteLine("Redump username and password denied!");
|
||||
else
|
||||
Console.WriteLine("An error occurred validating your crendentials!");
|
||||
}
|
||||
}
|
||||
// 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++)
|
||||
@@ -161,22 +55,11 @@ namespace MPF.Check
|
||||
string filepath = Path.GetFullPath(args[i].Trim('"'));
|
||||
|
||||
// Now populate an environment
|
||||
var options = new Options
|
||||
{
|
||||
InternalProgram = Converters.ToInternalProgram(internalProgram),
|
||||
ScanForProtection = scan && !string.IsNullOrWhiteSpace(path),
|
||||
PromptForDiscInformation = false,
|
||||
CompressLogFiles = compress,
|
||||
|
||||
RedumpUsername = username,
|
||||
RedumpPassword = password,
|
||||
};
|
||||
|
||||
Drive drive = null;
|
||||
if (!string.IsNullOrWhiteSpace(path))
|
||||
drive = new Drive(null, new DriveInfo(path));
|
||||
drive = Drive.Create(null, path);
|
||||
|
||||
var env = new DumpEnvironment(options, "", filepath, drive, knownSystem, mediaType, null);
|
||||
var env = new DumpEnvironment(options, filepath, drive, knownSystem, mediaType, internalProgram: null, parameters: null);
|
||||
|
||||
// Finally, attempt to do the output dance
|
||||
var result = env.VerifyAndSaveDumpOutput(resultProgress, protectionProgress).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
@@ -194,7 +77,7 @@ namespace MPF.Check
|
||||
Console.WriteLine(error);
|
||||
|
||||
Console.WriteLine("Usage:");
|
||||
Console.WriteLine("MPF.Check.exe <mediatype> <system> [options] </path/to/output.bin> ...");
|
||||
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");
|
||||
@@ -202,58 +85,94 @@ namespace MPF.Check
|
||||
Console.WriteLine("-ls, --listsystems List supported system types");
|
||||
Console.WriteLine("-lp, --listprograms List supported dumping program outputs");
|
||||
Console.WriteLine();
|
||||
|
||||
Console.WriteLine("Check Options:");
|
||||
Console.WriteLine("-c, --credentials <user> <pw> Redump username and password");
|
||||
Console.WriteLine("-u, --use <program> Dumping program output type");
|
||||
Console.WriteLine("-p, --path <drivepath> Physical drive path for additional checks");
|
||||
Console.WriteLine("-s, --scan Enable copy protection scan (requires --path)");
|
||||
Console.WriteLine("-z, --zip Enable log file compression");
|
||||
var supportedArguments = OptionsLoader.PrintSupportedArguments();
|
||||
foreach (string argument in supportedArguments)
|
||||
{
|
||||
Console.WriteLine(argument);
|
||||
}
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List all media types with their short usable names
|
||||
/// Process common arguments for all functionality
|
||||
/// </summary>
|
||||
private static void ListMediaTypes()
|
||||
/// <returns>True if all arguments pass, false otherwise</returns>
|
||||
private static (bool, MediaType, RedumpSystem?) ProcessCommonArguments(string[] args)
|
||||
{
|
||||
Console.WriteLine("Supported Media Types:");
|
||||
foreach (var val in Enum.GetValues(typeof(MediaType)))
|
||||
// All other use requires at least 3 arguments
|
||||
if (args.Length < 3)
|
||||
{
|
||||
if (((MediaType)val) == MediaType.NONE)
|
||||
continue;
|
||||
|
||||
Console.WriteLine($"{((MediaType?)val).ShortName()} - {((MediaType?)val).LongName()}");
|
||||
DisplayHelp("Invalid number of arguments");
|
||||
return (false, MediaType.NONE, null);
|
||||
}
|
||||
|
||||
// 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 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>
|
||||
/// List all programs with their short usable names
|
||||
/// Process any standalone arguments for the program
|
||||
/// </summary>
|
||||
private static void ListPrograms()
|
||||
/// <returns>True if one of the arguments was processed, false otherwise</returns>
|
||||
private static bool ProcessStandaloneArguments(string[] args)
|
||||
{
|
||||
Console.WriteLine("Supported Programs:");
|
||||
foreach (var val in Enum.GetValues(typeof(InternalProgram)))
|
||||
// Help options
|
||||
if (args.Length == 0 || args[0] == "-h" || args[0] == "-?")
|
||||
{
|
||||
if (((InternalProgram)val) == InternalProgram.NONE)
|
||||
continue;
|
||||
|
||||
Console.WriteLine($"{((InternalProgram?)val).LongName()}");
|
||||
DisplayHelp();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List all known systems with their short usable names
|
||||
/// </summary>
|
||||
private static void ListKnownSystems()
|
||||
{
|
||||
Console.WriteLine("Supported Known Systems:");
|
||||
foreach (var val in Enum.GetValues(typeof(KnownSystem)))
|
||||
// List options
|
||||
if (args[0] == "-lm" || args[0] == "--listmedia")
|
||||
{
|
||||
if (((KnownSystem)val) == KnownSystem.NONE)
|
||||
continue;
|
||||
|
||||
Console.WriteLine($"{((KnownSystem?)val).ShortName()} - {((KnownSystem?)val).LongName()}");
|
||||
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>
|
||||
|
||||
4
MPF.Core/AssemblyInfo.cs
Normal file
4
MPF.Core/AssemblyInfo.cs
Normal file
@@ -0,0 +1,4 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Anything marked as internal can be used by the test methods
|
||||
[assembly: InternalsVisibleTo("MPF.Test")]
|
||||
385
MPF.Core/Converters/EnumConverter.cs
Normal file
385
MPF.Core/Converters/EnumConverter.cs
Normal file
@@ -0,0 +1,385 @@
|
||||
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,7 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.Data
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Constant values for UI
|
||||
@@ -16,10 +17,11 @@ namespace MPF.Data
|
||||
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> bd { get; } = cd.Where(s => s <= 16).ToList();
|
||||
private static IReadOnlyList<int> unknown { get; } = new List<int> { 1 };
|
||||
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
|
||||
@@ -32,16 +34,17 @@ namespace MPF.Data
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
case MediaType.GDROM:
|
||||
return cd;
|
||||
return CD;
|
||||
case MediaType.DVD:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return dvd;
|
||||
return DVD;
|
||||
case MediaType.HDDVD:
|
||||
return HDDVD;
|
||||
case MediaType.BluRay:
|
||||
return bd;
|
||||
return BD;
|
||||
default:
|
||||
return unknown;
|
||||
return Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,13 +84,19 @@ namespace MPF.Data
|
||||
|
||||
// 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 MatchingIDsField = "Matching IDs";
|
||||
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)";
|
||||
@@ -99,11 +108,7 @@ namespace MPF.Data
|
||||
public const string PlayStationEDCField = "EDC";
|
||||
public const string PlayStationAntiModchipField = "Anti-modchip";
|
||||
public const string PlayStationLibCryptField = "LibCrypt";
|
||||
public const string XBOXDMIHash = "DMI.bin Hashes";
|
||||
public const string XBOXPFIHash = "PFI.bin Hashes";
|
||||
public const string XBOXSSHash = "SS.bin Hashes";
|
||||
public const string XBOXSSRanges = "Security Sector Ranges";
|
||||
public const string XBOXSSVersion = "Security Sector Version";
|
||||
|
||||
// Default values
|
||||
|
||||
650
MPF.Core/Data/Drive.cs
Normal file
650
MPF.Core/Data/Drive.cs
Normal file
@@ -0,0 +1,650 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
32
MPF.Core/Data/Enumerations.cs
Normal file
32
MPF.Core/Data/Enumerations.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
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,
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace MPF.Data
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
public class IniFile : IDictionary<string, string>
|
||||
{
|
||||
@@ -1,14 +1,14 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MPF.Utilities;
|
||||
using MPF.Core.Converters;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.Data
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
public class Options : IDictionary<string, string>, ICloneable
|
||||
{
|
||||
private Dictionary<string, string> _settings;
|
||||
private readonly Dictionary<string, string> _settings;
|
||||
|
||||
#region Internal Program
|
||||
|
||||
@@ -39,6 +39,15 @@ namespace MPF.Data
|
||||
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>
|
||||
@@ -47,7 +56,7 @@ namespace MPF.Data
|
||||
get
|
||||
{
|
||||
string valueString = GetStringSetting(_settings, "InternalProgram", InternalProgram.DiscImageCreator.ToString());
|
||||
var valueEnum = Converters.ToInternalProgram(valueString);
|
||||
var valueEnum = EnumConverter.ToInternalProgram(valueString);
|
||||
return valueEnum == InternalProgram.NONE ? InternalProgram.DiscImageCreator : valueEnum;
|
||||
}
|
||||
set
|
||||
@@ -69,6 +78,24 @@ namespace MPF.Data
|
||||
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>
|
||||
@@ -81,20 +108,30 @@ namespace MPF.Data
|
||||
/// <summary>
|
||||
/// Default system if none can be detected
|
||||
/// </summary>
|
||||
public KnownSystem DefaultSystem
|
||||
public RedumpSystem? DefaultSystem
|
||||
{
|
||||
get
|
||||
{
|
||||
string valueString = GetStringSetting(_settings, "DefaultSystem", KnownSystem.NONE.ToString());
|
||||
var valueEnum = Converters.ToKnownSystem(valueString);
|
||||
return valueEnum ?? KnownSystem.NONE;
|
||||
string valueString = GetStringSetting(_settings, "DefaultSystem", null);
|
||||
var valueEnum = Extensions.ToRedumpSystem(valueString);
|
||||
return valueEnum;
|
||||
}
|
||||
set
|
||||
{
|
||||
_settings["DefaultSystem"] = Converters.GetLongName(value);
|
||||
_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
|
||||
@@ -104,7 +141,7 @@ namespace MPF.Data
|
||||
/// </summary>
|
||||
public int PreferredDumpSpeedCD
|
||||
{
|
||||
get { return GetInt32Setting(_settings, "PreferredDumpSpeedCD", 72); }
|
||||
get { return GetInt32Setting(_settings, "PreferredDumpSpeedCD", 24); }
|
||||
set { _settings["PreferredDumpSpeedCD"] = value.ToString(); }
|
||||
}
|
||||
|
||||
@@ -113,16 +150,25 @@ namespace MPF.Data
|
||||
/// </summary>
|
||||
public int PreferredDumpSpeedDVD
|
||||
{
|
||||
get { return GetInt32Setting(_settings, "PreferredDumpSpeedDVD", 24); }
|
||||
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", 16); }
|
||||
get { return GetInt32Setting(_settings, "PreferredDumpSpeedBD", 8); }
|
||||
set { _settings["PreferredDumpSpeedBD"] = value.ToString(); }
|
||||
}
|
||||
|
||||
@@ -179,6 +225,24 @@ namespace MPF.Data
|
||||
|
||||
#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>
|
||||
@@ -211,6 +275,15 @@ namespace MPF.Data
|
||||
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>
|
||||
@@ -231,6 +304,37 @@ namespace MPF.Data
|
||||
|
||||
#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>
|
||||
@@ -242,6 +346,15 @@ namespace MPF.Data
|
||||
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>
|
||||
@@ -260,6 +373,33 @@ namespace MPF.Data
|
||||
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>
|
||||
@@ -358,15 +498,6 @@ namespace MPF.Data
|
||||
set { _settings["ScanPackersForProtection"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Force scanning all files for protection
|
||||
/// </summary>
|
||||
public bool ForceScanningForProtection
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "ForceScanningForProtection", false); }
|
||||
set { _settings["ForceScanningForProtection"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Include debug information with scan results
|
||||
/// </summary>
|
||||
38
MPF.Core/Data/PICDiscInformation.cs
Normal file
38
MPF.Core/Data/PICDiscInformation.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
114
MPF.Core/Data/PICDiscInformationUnit.cs
Normal file
114
MPF.Core/Data/PICDiscInformationUnit.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MPF.Data
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
public class ProcessingQueue<T> : IDisposable
|
||||
{
|
||||
@@ -33,10 +33,7 @@ namespace MPF.Data
|
||||
/// <summary>
|
||||
/// Dispose the current instance
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.TokenSource.Cancel();
|
||||
}
|
||||
public void Dispose() => this.TokenSource.Cancel();
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue a new item for processing
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace MPF.Data
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Generic success/failure result object, with optional message
|
||||
423
MPF.Core/Data/XgdInfo.cs
Normal file
423
MPF.Core/Data/XgdInfo.cs
Normal file
@@ -0,0 +1,423 @@
|
||||
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,11 +1,27 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using MPF.Data;
|
||||
using OptimizedCRC;
|
||||
|
||||
namespace MPF.Hashing
|
||||
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>
|
||||
@@ -28,7 +44,7 @@ namespace MPF.Hashing
|
||||
switch (HashType)
|
||||
{
|
||||
case Hash.CRC:
|
||||
_hasher = new OptimizedCRC.OptimizedCRC();
|
||||
_hasher = new OptimizedCRC();
|
||||
break;
|
||||
|
||||
case Hash.MD5:
|
||||
@@ -66,7 +82,7 @@ namespace MPF.Hashing
|
||||
switch (HashType)
|
||||
{
|
||||
case Hash.CRC:
|
||||
(_hasher as OptimizedCRC.OptimizedCRC).Update(buffer, 0, size);
|
||||
(_hasher as OptimizedCRC).Update(buffer, 0, size);
|
||||
break;
|
||||
|
||||
case Hash.MD5:
|
||||
@@ -88,7 +104,7 @@ namespace MPF.Hashing
|
||||
switch (HashType)
|
||||
{
|
||||
case Hash.CRC:
|
||||
(_hasher as OptimizedCRC.OptimizedCRC).Update(emptyBuffer, 0, 0);
|
||||
(_hasher as OptimizedCRC).Update(emptyBuffer, 0, 0);
|
||||
break;
|
||||
|
||||
case Hash.MD5:
|
||||
@@ -109,7 +125,7 @@ namespace MPF.Hashing
|
||||
switch (HashType)
|
||||
{
|
||||
case Hash.CRC:
|
||||
return BitConverter.GetBytes((_hasher as OptimizedCRC.OptimizedCRC).Value).Reverse().ToArray();
|
||||
return BitConverter.GetBytes((_hasher as OptimizedCRC).Value).Reverse().ToArray();
|
||||
|
||||
case Hash.MD5:
|
||||
case Hash.SHA1:
|
||||
@@ -24,7 +24,8 @@
|
||||
|
||||
using System;
|
||||
|
||||
namespace OptimizedCRC
|
||||
//namespace OptimizedCRC
|
||||
namespace MPF.Core.Hashing
|
||||
{
|
||||
internal class OptimizedCRC : IDisposable
|
||||
{
|
||||
@@ -2,7 +2,8 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace Compress.ThreadReaders
|
||||
//namespace Compress.ThreadReaders
|
||||
namespace MPF.Core.Hashing
|
||||
{
|
||||
public class ThreadLoadBuffer : IDisposable
|
||||
{
|
||||
55
MPF.Core/MPF.Core.csproj
Normal file
55
MPF.Core/MPF.Core.csproj
Normal file
@@ -0,0 +1,55 @@
|
||||
<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.2</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,12 +1,12 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace MPF.Utilities
|
||||
namespace MPF.Core.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Big endian reading overloads for BinaryReader
|
||||
/// </summary>
|
||||
internal static class BinaryReaderExtensions
|
||||
public static class BinaryReaderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads the specified number of bytes from the stream, starting from a specified point in the byte array.
|
||||
396
MPF.Core/Utilities/Chime.cs
Normal file
396
MPF.Core/Utilities/Chime.cs
Normal file
@@ -0,0 +1,396 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
149
MPF.Core/Utilities/EnumExtensions.cs
Normal file
149
MPF.Core/Utilities/EnumExtensions.cs
Normal file
@@ -0,0 +1,149 @@
|
||||
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.PlayStationGameSharkUpdates:
|
||||
case RedumpSystem.SuperAudioCD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if a system is considered XGD
|
||||
/// </summary>
|
||||
/// <param name="system">RedumpSystem value to check</param>
|
||||
/// <returns>True if the system is XGD, false otherwise</returns>
|
||||
public static bool IsXGD(this RedumpSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case RedumpSystem.MicrosoftXbox:
|
||||
case RedumpSystem.MicrosoftXbox360:
|
||||
case RedumpSystem.MicrosoftXboxOne:
|
||||
case RedumpSystem.MicrosoftXboxSeriesXS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List all programs with their short usable names
|
||||
/// </summary>
|
||||
public static List<string> ListPrograms()
|
||||
{
|
||||
var programs = new List<string>();
|
||||
|
||||
foreach (var val in Enum.GetValues(typeof(InternalProgram)))
|
||||
{
|
||||
if (((InternalProgram)val) == InternalProgram.NONE)
|
||||
continue;
|
||||
|
||||
programs.Add($"{((InternalProgram?)val).LongName()}");
|
||||
}
|
||||
|
||||
return programs;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MPF.Utilities
|
||||
namespace MPF.Core.Utilities
|
||||
{
|
||||
internal static class Logging
|
||||
public static class Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Process a chunk of text and send it to a handler
|
||||
@@ -38,15 +37,15 @@ namespace MPF.Utilities
|
||||
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'))
|
||||
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"))
|
||||
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'))
|
||||
else if (line.Contains("\r"))
|
||||
ProcessCarriageReturns(sb, line, baseClass, handler);
|
||||
}
|
||||
}
|
||||
@@ -71,7 +70,7 @@ namespace MPF.Utilities
|
||||
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'))
|
||||
if (split[i].Contains("\r"))
|
||||
{
|
||||
ProcessCarriageReturns(sb, split[i], baseClass, handler);
|
||||
continue;
|
||||
182
MPF.Core/Utilities/OptionsLoader.cs
Normal file
182
MPF.Core/Utilities/OptionsLoader.cs
Normal file
@@ -0,0 +1,182 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
213
MPF.Core/Utilities/Tools.cs
Normal file
213
MPF.Core/Utilities/Tools.cs
Normal file
@@ -0,0 +1,213 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
31
MPF.CueSheets/MPF.CueSheets.csproj
Normal file
31
MPF.CueSheets/MPF.CueSheets.csproj
Normal file
@@ -0,0 +1,31 @@
|
||||
<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.2</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>
|
||||
Submodule MPF.Library/Aaru/CICMMetadata deleted from 7944bca8e6
@@ -1,106 +0,0 @@
|
||||
using System.IO;
|
||||
|
||||
namespace MPF.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents information for a single drive
|
||||
/// </summary>
|
||||
public class Drive
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents drive type
|
||||
/// </summary>
|
||||
public InternalDriveType? InternalDriveType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Drive partition format
|
||||
/// </summary>
|
||||
public string DriveFormat { get { return driveInfo.DriveFormat; } }
|
||||
|
||||
/// <summary>
|
||||
/// Windows drive letter
|
||||
/// </summary>
|
||||
public char Letter { get { return driveInfo?.Name[0] ?? '\0'; } }
|
||||
|
||||
/// <summary>
|
||||
/// Represents if Windows has marked the drive as active
|
||||
/// </summary>
|
||||
public bool MarkedActive { get { return driveInfo.IsReady; } }
|
||||
|
||||
/// <summary>
|
||||
/// Media label as read by Windows
|
||||
/// </summary>
|
||||
public string VolumeLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
string volumeLabel = Template.DiscNotDetected;
|
||||
if (driveInfo.IsReady)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(driveInfo.VolumeLabel))
|
||||
volumeLabel = "track";
|
||||
else
|
||||
volumeLabel = driveInfo.VolumeLabel;
|
||||
}
|
||||
|
||||
foreach (char c in Path.GetInvalidFileNameChars())
|
||||
volumeLabel = volumeLabel.Replace(c, '_');
|
||||
|
||||
return volumeLabel;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DriveInfo object representing the drive, if possible
|
||||
/// </summary>
|
||||
private readonly DriveInfo driveInfo;
|
||||
|
||||
public Drive(InternalDriveType? driveType, DriveInfo driveInfo)
|
||||
{
|
||||
this.InternalDriveType = driveType;
|
||||
this.driveInfo = driveInfo;
|
||||
}
|
||||
|
||||
/// <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.driveInfo?.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,777 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace MPF.Data
|
||||
{
|
||||
/// <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>
|
||||
/// 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,
|
||||
|
||||
// Verification support only
|
||||
CleanRip,
|
||||
DCDumper,
|
||||
UmdImageCreator,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Known systems
|
||||
/// </summary>
|
||||
public enum KnownSystem
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
#region Disc-Based Consoles
|
||||
|
||||
AtariJaguarCD,
|
||||
BandaiPlaydiaQuickInteractiveSystem,
|
||||
BandaiApplePippin,
|
||||
CommodoreAmigaCD32,
|
||||
CommodoreAmigaCDTV,
|
||||
EnvizionsEVOSmartConsole,
|
||||
FujitsuFMTownsMarty,
|
||||
HasbroVideoNow,
|
||||
HasbroVideoNowColor,
|
||||
HasbroVideoNowJr,
|
||||
HasbroVideoNowXP,
|
||||
MattelFisherPriceiXL,
|
||||
MattelHyperscan,
|
||||
MicrosoftXBOX,
|
||||
MicrosoftXBOX360,
|
||||
MicrosoftXBOXOne,
|
||||
MicrosoftXboxSeriesXS,
|
||||
NECPCEngineTurboGrafxCD,
|
||||
NECPCFX,
|
||||
NintendoGameCube,
|
||||
NintendoSonySuperNESCDROMSystem,
|
||||
NintendoWii,
|
||||
NintendoWiiU,
|
||||
Panasonic3DOInteractiveMultiplayer, // The 3DO Company 3DO Interactive Multiplayer
|
||||
PhilipsCDi,
|
||||
PioneerLaserActive,
|
||||
SegaCDMegaCD,
|
||||
SegaDreamcast,
|
||||
SegaSaturn,
|
||||
SNKNeoGeoCD,
|
||||
SonyPlayStation,
|
||||
SonyPlayStation2,
|
||||
SonyPlayStation3,
|
||||
SonyPlayStation4,
|
||||
SonyPlayStation5,
|
||||
SonyPlayStationPortable,
|
||||
TandyMemorexVisualInformationSystem,
|
||||
VMLabsNuon,
|
||||
VTechVFlashVSmilePro,
|
||||
ZAPiTGamesGameWaveFamilyEntertainmentSystem,
|
||||
|
||||
MarkerDiscBasedConsoleEnd,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cartridge-Based and Other Consoles
|
||||
|
||||
/*
|
||||
AmstradGX4000,
|
||||
APFMicrocomputerSystem,
|
||||
Atari2600VCS,
|
||||
Atari5200,
|
||||
Atari7800,
|
||||
AtariJaguar,
|
||||
AtariXEVideoGameSystem,
|
||||
Audiosonic1292AdvancedProgrammableVideoSystem,
|
||||
BallyAstrocade,
|
||||
BitCorporationDina,
|
||||
CasioLoopy,
|
||||
CasioPV1000,
|
||||
Commodore64GamesSystem,
|
||||
DaewooElectronicsZemmix,
|
||||
EmersonArcadia2001,
|
||||
EpochCassetteVision,
|
||||
EpochSuperCassetteVision,
|
||||
FairchildChannelF,
|
||||
FuntechSuperACan,
|
||||
GeneralConsumerElectricVectrex,
|
||||
HeberBBCBridgeCompanion,
|
||||
IntertonVC4000,
|
||||
JungleTacVii,
|
||||
LeapFrogClickStart,
|
||||
LJNVideoArt,
|
||||
MagnavoxOdyssey2,
|
||||
MattelIntellivision,
|
||||
NECPCEngineTurboGrafx16,
|
||||
NichibutsuMyVision,
|
||||
Nintendo64,
|
||||
Nintendo64DD,
|
||||
NintendoFamilyComputerNintendoEntertainmentSystem,
|
||||
NintendoFamilyComputerDiskSystem,
|
||||
NintendoSuperFamicomSuperNintendoEntertainmentSystem,
|
||||
NintendoSwitch,
|
||||
PhilipsVideopacPlusG7400,
|
||||
RCAStudioII,
|
||||
Sega32X,
|
||||
SegaMarkIIIMasterSystem,
|
||||
SegaMegaDriveGenesis,
|
||||
SegaSG1000,
|
||||
SNKNeoGeo,
|
||||
SSDCOMPANYLIMITEDXaviXPORT,
|
||||
ViewMasterInteractiveVision,
|
||||
VTechCreatiVision,
|
||||
VTechVSmile,
|
||||
VTechSocrates,
|
||||
WorldsOfWonderActionMax,
|
||||
|
||||
MarkerOtherConsoleEnd,
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region Computers
|
||||
|
||||
AcornArchimedes,
|
||||
AppleMacintosh,
|
||||
CommodoreAmiga,
|
||||
FujitsuFMTowns,
|
||||
IBMPCCompatible,
|
||||
NECPC88,
|
||||
NECPC98,
|
||||
SharpX68000,
|
||||
|
||||
MarkerComputerEnd,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Arcade
|
||||
|
||||
AmigaCUBOCD32,
|
||||
AmericanLaserGames3DO,
|
||||
Atari3DO,
|
||||
Atronic,
|
||||
AUSCOMSystem1,
|
||||
BallyGameMagic,
|
||||
CapcomCPSystemIII,
|
||||
funworldPhotoPlay,
|
||||
GlobalVRVarious,
|
||||
GlobalVRVortek,
|
||||
GlobalVRVortekV3,
|
||||
ICEPCHardware,
|
||||
IncredibleTechnologiesEagle,
|
||||
IncredibleTechnologiesVarious,
|
||||
KonamieAmusement,
|
||||
KonamiFirebeat,
|
||||
KonamiGVSystem,
|
||||
KonamiM2,
|
||||
KonamiPython,
|
||||
KonamiPython2,
|
||||
KonamiSystem573,
|
||||
KonamiTwinkle,
|
||||
KonamiVarious,
|
||||
MeritIndustriesBoardwalk,
|
||||
MeritIndustriesMegaTouchForce,
|
||||
MeritIndustriesMegaTouchION,
|
||||
MeritIndustriesMegaTouchMaxx,
|
||||
MeritIndustriesMegaTouchXL,
|
||||
NamcoCapcomSystem256,
|
||||
NamcoCapcomTaitoSystem246,
|
||||
NamcoSegaNintendoTriforce,
|
||||
NamcoSystem12,
|
||||
NamcoSystem357,
|
||||
NewJatreCDi,
|
||||
NichibutsuHighRateSystem,
|
||||
NichibutsuSuperCD,
|
||||
NichibutsuXRateSystem,
|
||||
PanasonicM2,
|
||||
PhotoPlayVarious,
|
||||
RawThrillsVarious,
|
||||
SegaChihiro,
|
||||
SegaEuropaR,
|
||||
SegaLindbergh,
|
||||
SegaNaomi,
|
||||
SegaNaomi2,
|
||||
SegaNu,
|
||||
SegaRingEdge,
|
||||
SegaRingEdge2,
|
||||
SegaRingWide,
|
||||
SegaTitanVideo,
|
||||
SegaSystem32,
|
||||
SeibuCATSSystem,
|
||||
TABAustriaQuizard,
|
||||
TsunamiTsuMoMultiGameMotionSystem,
|
||||
|
||||
MarkerArcadeEnd,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Other
|
||||
|
||||
AudioCD,
|
||||
BDVideo,
|
||||
DVDAudio,
|
||||
DVDVideo,
|
||||
EnhancedCD,
|
||||
HDDVDVideo,
|
||||
NavisoftNaviken21,
|
||||
PalmOS,
|
||||
PhotoCD,
|
||||
PlayStationGameSharkUpdates,
|
||||
RainbowDisc,
|
||||
SegaPrologue21,
|
||||
SuperAudioCD,
|
||||
TaoiKTV,
|
||||
TomyKissSite,
|
||||
VideoCD,
|
||||
|
||||
MarkerOtherEnd,
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Known system category
|
||||
/// </summary>
|
||||
public enum KnownSystemCategory
|
||||
{
|
||||
DiscBasedConsole = 0,
|
||||
OtherConsole,
|
||||
Computer,
|
||||
Arcade,
|
||||
Other,
|
||||
Custom
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Known media types
|
||||
/// </summary>
|
||||
public enum MediaType
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
#region Punched Media
|
||||
|
||||
ApertureCard,
|
||||
JacquardLoomCard,
|
||||
MagneticStripeCard,
|
||||
OpticalPhonecard,
|
||||
PunchedCard,
|
||||
PunchedTape,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tape
|
||||
|
||||
Cassette,
|
||||
DataCartridge,
|
||||
OpenReel,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Disc / Disc
|
||||
|
||||
BluRay,
|
||||
CDROM,
|
||||
DVD,
|
||||
FloppyDisk,
|
||||
Floptical,
|
||||
GDROM,
|
||||
HDDVD,
|
||||
HardDisk,
|
||||
IomegaBernoulliDisk,
|
||||
IomegaJaz,
|
||||
IomegaZip,
|
||||
LaserDisc, // LD-ROM and LV-ROM variants
|
||||
Nintendo64DD,
|
||||
NintendoFamicomDiskSystem,
|
||||
NintendoGameCubeGameDisc,
|
||||
NintendoWiiOpticalDisc,
|
||||
NintendoWiiUOpticalDisc,
|
||||
UMD,
|
||||
|
||||
#endregion
|
||||
|
||||
// Unsorted Formats
|
||||
Cartridge,
|
||||
CED,
|
||||
CompactFlash,
|
||||
MMC,
|
||||
SDCard,
|
||||
FlashDrive,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Physical media types
|
||||
/// </summary>
|
||||
/// <see cref="https://docs.microsoft.com/en-us/previous-versions/windows/desktop/cimwin32a/win32-physicalmedia"/>
|
||||
public enum PhysicalMediaType : ushort
|
||||
{
|
||||
Unknown = 0,
|
||||
Other = 1,
|
||||
TapeCartridge = 2,
|
||||
QICCartridge = 3,
|
||||
AITCartridge = 4,
|
||||
DTFCartridge = 5,
|
||||
DATCartridge = 6,
|
||||
EightMillimeterTapeCartridge = 7,
|
||||
NineteenMillimeterTapeCartridge = 8,
|
||||
DLTCartridge = 9,
|
||||
HalfInchMagneticTapeCartridge = 10,
|
||||
CartridgeDisk = 11,
|
||||
JAZDisk = 12,
|
||||
ZIPDisk = 13,
|
||||
SyQuestDisk = 14,
|
||||
WinchesterRemovableDisk = 15,
|
||||
CDROM = 16,
|
||||
CDROMXA = 17,
|
||||
CDI = 18,
|
||||
CDRecordable = 19,
|
||||
WORM = 20,
|
||||
MagnetoOptical = 21,
|
||||
DVD = 22,
|
||||
DVDPlusRW = 23,
|
||||
DVDRAM = 24,
|
||||
DVDROM = 25,
|
||||
DVDVideo = 26,
|
||||
Divx = 27,
|
||||
FloppyDiskette = 28,
|
||||
HardDisk = 29,
|
||||
MemoryCard = 30,
|
||||
HardCopy = 31,
|
||||
ClikDisk = 32,
|
||||
CDRW = 33,
|
||||
CDDA = 34,
|
||||
CDPlus = 35,
|
||||
DVDRecordable = 36,
|
||||
DVDMinusRW = 37,
|
||||
DVDAudio = 38,
|
||||
DVD5 = 39,
|
||||
DVD9 = 40,
|
||||
DVD10 = 41,
|
||||
DVD18 = 42,
|
||||
MagnetoOpticalRewriteable = 43,
|
||||
MagnetoOpticalWriteOnce = 44,
|
||||
MagnetoOpticalRewriteableLIMDOW = 45,
|
||||
PhaseChangeWriteOnce = 46,
|
||||
PhaseChangeRewriteable = 47,
|
||||
PhaseChangeDualRewriteable = 48,
|
||||
AblativeWriteOnce = 49,
|
||||
NearFieldRecording = 50,
|
||||
MiniQic = 51,
|
||||
Travan = 52,
|
||||
EightMillimeterMetalParticle = 53,
|
||||
EightMillimeterAdvancedMetalEvaporate = 54,
|
||||
NCTP = 55,
|
||||
LTOUltrium = 56,
|
||||
LTOAccelis = 57,
|
||||
NineTrackTape = 58,
|
||||
EighteenTrackTape = 59,
|
||||
ThirtySixTrackTape = 60,
|
||||
Magstar3590 = 61,
|
||||
MagstarMP = 62,
|
||||
D2Tape = 63,
|
||||
TapeDSTSmall = 64,
|
||||
TapeDSTMedium = 65,
|
||||
TapeDSTLarge = 66,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Redump disc category
|
||||
/// </summary>
|
||||
public enum RedumpDiscCategory
|
||||
{
|
||||
Games = 1,
|
||||
Demos = 2,
|
||||
Video = 3,
|
||||
Audio = 4,
|
||||
Multimedia = 5,
|
||||
Applications = 6,
|
||||
Coverdiscs = 7,
|
||||
Educational = 8,
|
||||
BonusDiscs = 9,
|
||||
Preproduction = 10,
|
||||
AddOns = 11,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Redump dump status
|
||||
/// </summary>
|
||||
public enum RedumpDumpStatus
|
||||
{
|
||||
BadDumpRed = 2,
|
||||
PossibleBadDumpYellow = 3,
|
||||
OriginalMediaBlue = 4,
|
||||
TwoOrMoreDumpsGreen = 5,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Redump supported langauge
|
||||
/// </summary>
|
||||
public enum RedumpLanguage
|
||||
{
|
||||
Afrikaans,
|
||||
Albanian,
|
||||
Arabic,
|
||||
Basque,
|
||||
Bulgarian,
|
||||
Catalan,
|
||||
Chinese,
|
||||
Croatian,
|
||||
Czech,
|
||||
Danish,
|
||||
Dutch,
|
||||
English,
|
||||
Estonian,
|
||||
Finnish,
|
||||
French,
|
||||
Gaelic,
|
||||
German,
|
||||
Greek,
|
||||
Hebrew,
|
||||
Hindi,
|
||||
Hungarian,
|
||||
Indonesian,
|
||||
Icelandic,
|
||||
Italian,
|
||||
Japanese,
|
||||
Korean,
|
||||
Latin,
|
||||
Latvian,
|
||||
Lithuanian,
|
||||
Macedonian,
|
||||
Norwegian,
|
||||
Polish,
|
||||
Portuguese,
|
||||
Punjabi,
|
||||
Romanian,
|
||||
Russian,
|
||||
Serbian,
|
||||
Slovak,
|
||||
Slovenian,
|
||||
Spanish,
|
||||
Swedish,
|
||||
Tamil,
|
||||
Thai,
|
||||
Turkish,
|
||||
Ukrainian,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Redump PS2 language selection via
|
||||
/// </summary>
|
||||
public enum RedumpLanguageSelection
|
||||
{
|
||||
BiosSettings,
|
||||
LanguageSelector,
|
||||
OptionsMenu,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supported Redump region
|
||||
/// </summary>
|
||||
public enum RedumpRegion
|
||||
{
|
||||
Argentina,
|
||||
Asia,
|
||||
AsiaEurope,
|
||||
AsiaUSA,
|
||||
Australia,
|
||||
AustraliaGermany,
|
||||
AustraliaNewZealand,
|
||||
Austria,
|
||||
AustriaSwitzerland,
|
||||
Belgium,
|
||||
BelgiumNetherlands,
|
||||
Brazil,
|
||||
Bulgaria,
|
||||
Canada,
|
||||
China,
|
||||
Croatia,
|
||||
Czech,
|
||||
Denmark,
|
||||
Estonia,
|
||||
Europe,
|
||||
EuropeAsia,
|
||||
EuropeAustralia,
|
||||
EuropeCanada,
|
||||
EuropeGermany,
|
||||
Export,
|
||||
Finland,
|
||||
France,
|
||||
FranceSpain,
|
||||
Germany,
|
||||
GreaterChina,
|
||||
Greece,
|
||||
Hungary,
|
||||
Iceland,
|
||||
India,
|
||||
Ireland,
|
||||
Israel,
|
||||
Italy,
|
||||
Japan,
|
||||
JapanAsia,
|
||||
JapanEurope,
|
||||
JapanKorea,
|
||||
JapanUSA,
|
||||
Korea,
|
||||
LatinAmerica,
|
||||
Lithuania,
|
||||
Netherlands,
|
||||
NewZealand,
|
||||
Norway,
|
||||
Poland,
|
||||
Portugal,
|
||||
Romania,
|
||||
Russia,
|
||||
Scandinavia,
|
||||
Serbia,
|
||||
Singapore,
|
||||
Slovakia,
|
||||
SouthAfrica,
|
||||
Spain,
|
||||
SpainPortugal,
|
||||
Sweden,
|
||||
Switzerland,
|
||||
Taiwan,
|
||||
Thailand,
|
||||
Turkey,
|
||||
UnitedArabEmirates,
|
||||
UK,
|
||||
UKAustralia,
|
||||
Ukraine,
|
||||
USA,
|
||||
USAAsia,
|
||||
USAAustralia,
|
||||
USABrazil,
|
||||
USACanada,
|
||||
USAEurope,
|
||||
USAGermany,
|
||||
USAJapan,
|
||||
USAKorea,
|
||||
World,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of all known Redump systems
|
||||
/// </summary>
|
||||
public enum RedumpSystem
|
||||
{
|
||||
// Special BIOS sets
|
||||
MicrosoftXboxBIOS,
|
||||
NintendoGameCubeBIOS,
|
||||
SonyPlayStationBIOS,
|
||||
SonyPlayStation2BIOS,
|
||||
|
||||
// Regular systems
|
||||
AcornArchimedes,
|
||||
AppleMacintosh,
|
||||
AtariJaguarCDInteractiveMultimediaSystem,
|
||||
AudioCD,
|
||||
BandaiPippin,
|
||||
BandaiPlaydiaQuickInteractiveSystem,
|
||||
BDVideo,
|
||||
CommodoreAmigaCD,
|
||||
CommodoreAmigaCD32,
|
||||
CommodoreAmigaCDTV,
|
||||
DVDVideo,
|
||||
EnhancedCD,
|
||||
FujitsuFMTownsseries,
|
||||
funworldPhotoPlay,
|
||||
HasbroVideoNow,
|
||||
HasbroVideoNowColor,
|
||||
HasbroVideoNowJr,
|
||||
HasbroVideoNowXP,
|
||||
IBMPCcompatible,
|
||||
IncredibleTechnologiesEagle,
|
||||
KonamieAmusement,
|
||||
KonamiFireBeat,
|
||||
KonamiM2,
|
||||
KonamiSystem573,
|
||||
KonamiSystemGV,
|
||||
KonamiTwinkle,
|
||||
MattelFisherPriceiXL,
|
||||
MattelHyperScan,
|
||||
MemorexVisualInformationSystem,
|
||||
MicrosoftXbox,
|
||||
MicrosoftXbox360,
|
||||
MicrosoftXboxOne,
|
||||
MicrosoftXboxSeriesXS,
|
||||
NamcoSegaNintendoTriforce,
|
||||
NamcoSystem12,
|
||||
NamcoSystem246,
|
||||
NavisoftNaviken21,
|
||||
NECPCEngineCDTurboGrafxCD,
|
||||
NECPC88series,
|
||||
NECPC98series,
|
||||
NECPCFXPCFXGA,
|
||||
NintendoGameCube,
|
||||
NintendoWii,
|
||||
NintendoWiiU,
|
||||
PalmOS,
|
||||
Panasonic3DOInteractiveMultiplayer,
|
||||
PanasonicM2,
|
||||
PhilipsCDi,
|
||||
PhotoCD,
|
||||
PlayStationGameSharkUpdates,
|
||||
SegaChihiro,
|
||||
SegaDreamcast,
|
||||
SegaLindbergh,
|
||||
SegaMegaCDSegaCD,
|
||||
SegaNaomi,
|
||||
SegaNaomi2,
|
||||
SegaPrologue21,
|
||||
SegaRingEdge,
|
||||
SegaRingEdge2,
|
||||
SegaSaturn,
|
||||
SegaTitanVideo,
|
||||
SharpX68000,
|
||||
SNKNeoGeoCD,
|
||||
SonyPlayStation,
|
||||
SonyPlayStation2,
|
||||
SonyPlayStation3,
|
||||
SonyPlayStation4,
|
||||
SonyPlayStation5,
|
||||
SonyPlayStationPortable,
|
||||
TABAustriaQuizard,
|
||||
TaoiKTV,
|
||||
TomyKissSite,
|
||||
VideoCD,
|
||||
VMLabsNUON,
|
||||
VTechVFlashVSmilePro,
|
||||
ZAPiTGamesGameWaveFamilyEntertainmentSystem,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generic yes/no values for Redump
|
||||
/// </summary>
|
||||
public enum YesNo
|
||||
{
|
||||
NULL = 0,
|
||||
No = 1,
|
||||
Yes = 2,
|
||||
}
|
||||
|
||||
#region Win32_CDROMDrive
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-cdromdrive
|
||||
|
||||
/// <summary>
|
||||
/// Availability and status of the device
|
||||
/// </summary>
|
||||
public enum Availability : ushort
|
||||
{
|
||||
Other = 1,
|
||||
Unknown = 2,
|
||||
RunningFullPower = 3,
|
||||
Warning = 4,
|
||||
InTest = 5,
|
||||
NotApplicable = 6,
|
||||
PowerOff = 7,
|
||||
OffLine = 8,
|
||||
OffDuty = 9,
|
||||
Degraded = 10,
|
||||
NotInstalled = 11,
|
||||
InstallError = 12,
|
||||
PowerSaveUnknown = 13,
|
||||
PowerSaveLowPowerMode = 14,
|
||||
PowerSaveStandby = 15,
|
||||
PowerCycle = 16,
|
||||
PowerSaveWarning = 17,
|
||||
Paused = 18,
|
||||
NotReady = 19,
|
||||
NotConfigured = 20,
|
||||
Quiesced = 21,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Optical drive capabilities
|
||||
/// </summary>
|
||||
public enum Capabilities : ushort
|
||||
{
|
||||
Unknown = 0,
|
||||
Other = 1,
|
||||
SequentialAccess = 2,
|
||||
RandomAccess = 3,
|
||||
SupportsWriting = 4,
|
||||
Encryption = 5,
|
||||
Compression = 6,
|
||||
SupportsRemoveableMedia = 7,
|
||||
ManualCleaning = 8,
|
||||
AutomaticCleaning = 9,
|
||||
SMARTNotification = 10,
|
||||
SupportsDualSidedMedia = 11,
|
||||
PredismountEjectNotRequired = 12,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// File system flags
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum FileSystemFlags : uint
|
||||
{
|
||||
None = 0,
|
||||
CaseSensitiveSearch = 1,
|
||||
CasePreservedNames = 2,
|
||||
UnicodeOnDisk = 4,
|
||||
PersistentACLs = 8,
|
||||
FileCompression = 16,
|
||||
VolumeQuotas = 32,
|
||||
SupportsSparseFiles = 64,
|
||||
SupportsReparsePoints = 128,
|
||||
SupportsRemoteStorage = 256,
|
||||
SupportsLongNames = 16384,
|
||||
VolumeIsCompressed = 32768,
|
||||
ReadOnlyVolume = 524288,
|
||||
SupportsObjectIDS = 65536,
|
||||
SupportsEncryption = 131072,
|
||||
SupportsNamedStreams = 262144,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specific power-related capabilities of a logical device
|
||||
/// </summary>
|
||||
public enum PowerManagementCapabilities : ushort
|
||||
{
|
||||
Unknown = 0,
|
||||
NotSupported = 1,
|
||||
Disabled = 2,
|
||||
Enabled = 3,
|
||||
PowerSavingModesEnteredAutomatically = 4,
|
||||
PowerStateSettable = 5,
|
||||
PowerCyclingSupported = 6,
|
||||
TimedPowerOnSupported = 7,
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
574
MPF.Library/DumpEnvironment.cs
Normal file
574
MPF.Library/DumpEnvironment.cs
Normal file
@@ -0,0 +1,574 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using BurnOutSharp;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.Utilities;
|
||||
using MPF.Modules;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.Library
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the state of all settings to be used during dumping
|
||||
/// </summary>
|
||||
public class DumpEnvironment
|
||||
{
|
||||
#region Output paths
|
||||
|
||||
/// <summary>
|
||||
/// Base output file path to write files to
|
||||
/// </summary>
|
||||
public string OutputPath { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI information
|
||||
|
||||
/// <summary>
|
||||
/// Drive object representing the current drive
|
||||
/// </summary>
|
||||
public Drive Drive { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected system
|
||||
/// </summary>
|
||||
public RedumpSystem? System { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected media type
|
||||
/// </summary>
|
||||
public MediaType? Type { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected dumping program
|
||||
/// </summary>
|
||||
public InternalProgram InternalProgram { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Options object representing user-defined options
|
||||
/// </summary>
|
||||
public Core.Data.Options Options { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Parameters object representing what to send to the internal program
|
||||
/// </summary>
|
||||
public BaseParameters Parameters { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Generic way of reporting a message
|
||||
/// </summary>
|
||||
public EventHandler<string> ReportStatus;
|
||||
|
||||
/// <summary>
|
||||
/// Queue of items that need to be logged
|
||||
/// </summary>
|
||||
private ProcessingQueue<string> outputQueue;
|
||||
|
||||
/// <summary>
|
||||
/// Event handler for data returned from a process
|
||||
/// </summary>
|
||||
private void OutputToLog(object proc, string args) => outputQueue.Enqueue(args);
|
||||
|
||||
/// <summary>
|
||||
/// Process the outputs in the queue
|
||||
/// </summary>
|
||||
private void ProcessOutputs(string nextOutput) => ReportStatus.Invoke(this, nextOutput);
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for a full DumpEnvironment object from user information
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="outputPath"></param>
|
||||
/// <param name="drive"></param>
|
||||
/// <param name="system"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="internalProgram"></param>
|
||||
/// <param name="parameters"></param>
|
||||
public DumpEnvironment(Core.Data.Options options,
|
||||
string outputPath,
|
||||
Drive drive,
|
||||
RedumpSystem? system,
|
||||
MediaType? type,
|
||||
InternalProgram? internalProgram,
|
||||
string parameters)
|
||||
{
|
||||
// Set options object
|
||||
this.Options = options;
|
||||
|
||||
// Output paths
|
||||
this.OutputPath = InfoTool.NormalizeOutputPaths(outputPath);
|
||||
|
||||
// UI information
|
||||
this.Drive = drive;
|
||||
this.System = system ?? options.DefaultSystem;
|
||||
this.Type = type ?? MediaType.NONE;
|
||||
this.InternalProgram = internalProgram ?? options.InternalProgram;
|
||||
|
||||
// Dumping program
|
||||
SetParameters(parameters);
|
||||
}
|
||||
|
||||
#region Public Functionality
|
||||
|
||||
/// <summary>
|
||||
/// Adjust output paths if we're using DiscImageCreator
|
||||
/// </summary>
|
||||
public void AdjustPathsForDiscImageCreator()
|
||||
{
|
||||
// Only DiscImageCreator has issues with paths
|
||||
if (this.Parameters.InternalProgram != InternalProgram.DiscImageCreator)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// Normalize the output path
|
||||
string outputPath = InfoTool.NormalizeOutputPaths(this.OutputPath);
|
||||
|
||||
// Replace all instances in the output directory
|
||||
string outputDirectory = Path.GetDirectoryName(outputPath);
|
||||
outputDirectory = outputDirectory.Replace(".", "_");
|
||||
|
||||
// Replace all instances in the output filename
|
||||
string outputFilename = Path.GetFileNameWithoutExtension(outputPath);
|
||||
outputFilename = outputFilename.Replace(".", "_");
|
||||
|
||||
// Get the extension for recreating the path
|
||||
string outputExtension = Path.GetExtension(outputPath).TrimStart('.');
|
||||
|
||||
// Rebuild the output path
|
||||
if (!string.IsNullOrWhiteSpace(outputExtension))
|
||||
this.OutputPath = Path.Combine(outputDirectory, $"{outputFilename}.{outputExtension}");
|
||||
else
|
||||
this.OutputPath = Path.Combine(outputDirectory, outputFilename);
|
||||
|
||||
// Assign the path to the filename as well for dumping
|
||||
((Modules.DiscImageCreator.Parameters)this.Parameters).Filename = this.OutputPath;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the parameters object based on the internal program and parameters string
|
||||
/// </summary>
|
||||
/// <param name="parameters">String representation of the parameters</param>
|
||||
public void SetParameters(string parameters)
|
||||
{
|
||||
switch (this.InternalProgram)
|
||||
{
|
||||
// Dumping support
|
||||
case InternalProgram.Aaru:
|
||||
this.Parameters = new Modules.Aaru.Parameters(parameters) { ExecutablePath = Options.AaruPath };
|
||||
break;
|
||||
|
||||
case InternalProgram.DD:
|
||||
this.Parameters = new Modules.DD.Parameters(parameters) { ExecutablePath = Options.DDPath };
|
||||
break;
|
||||
|
||||
case InternalProgram.DiscImageCreator:
|
||||
this.Parameters = new Modules.DiscImageCreator.Parameters(parameters) { ExecutablePath = Options.DiscImageCreatorPath };
|
||||
break;
|
||||
|
||||
case InternalProgram.Redumper:
|
||||
this.Parameters = new Modules.Redumper.Parameters(parameters) { ExecutablePath = Options.RedumperPath };
|
||||
break;
|
||||
|
||||
// Verification support only
|
||||
case InternalProgram.CleanRip:
|
||||
this.Parameters = new Modules.CleanRip.Parameters(parameters) { ExecutablePath = null };
|
||||
break;
|
||||
|
||||
case InternalProgram.DCDumper:
|
||||
this.Parameters = null; // TODO: Create correct parameter type when supported
|
||||
break;
|
||||
|
||||
case InternalProgram.UmdImageCreator:
|
||||
this.Parameters = new Modules.UmdImageCreator.Parameters(parameters) { ExecutablePath = null };
|
||||
break;
|
||||
|
||||
// This should never happen, but it needs a fallback
|
||||
default:
|
||||
this.Parameters = new Modules.DiscImageCreator.Parameters(parameters) { ExecutablePath = Options.DiscImageCreatorPath };
|
||||
break;
|
||||
}
|
||||
|
||||
// Set system and type
|
||||
this.Parameters.System = this.System;
|
||||
this.Parameters.Type = this.Type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the full parameter string for either DiscImageCreator or Aaru
|
||||
/// </summary>
|
||||
/// <param name="driveSpeed">Nullable int representing the drive speed</param>
|
||||
/// <returns>String representing the params, null on error</returns>
|
||||
public string GetFullParameters(int? driveSpeed)
|
||||
{
|
||||
// Populate with the correct params for inputs (if we're not on the default option)
|
||||
if (System != null && Type != MediaType.NONE)
|
||||
{
|
||||
// If drive letter is invalid, skip this
|
||||
if (Drive == null)
|
||||
return null;
|
||||
|
||||
// Set the proper parameters
|
||||
switch (this.InternalProgram)
|
||||
{
|
||||
case InternalProgram.Aaru:
|
||||
Parameters = new Modules.Aaru.Parameters(System, Type, Drive.Letter, this.OutputPath, driveSpeed, Options);
|
||||
break;
|
||||
|
||||
case InternalProgram.DD:
|
||||
Parameters = new Modules.DD.Parameters(System, Type, Drive.Letter, this.OutputPath, driveSpeed, Options);
|
||||
break;
|
||||
|
||||
case InternalProgram.DiscImageCreator:
|
||||
Parameters = new Modules.DiscImageCreator.Parameters(System, Type, Drive.Letter, this.OutputPath, driveSpeed, Options);
|
||||
break;
|
||||
|
||||
case InternalProgram.Redumper:
|
||||
Parameters = new Modules.Redumper.Parameters(System, Type, Drive.Letter, this.OutputPath, driveSpeed, Options);
|
||||
break;
|
||||
|
||||
// This should never happen, but it needs a fallback
|
||||
default:
|
||||
Parameters = new Modules.DiscImageCreator.Parameters(System, Type, Drive.Letter, this.OutputPath, driveSpeed, Options);
|
||||
break;
|
||||
}
|
||||
|
||||
// Generate and return the param string
|
||||
return Parameters.GenerateParameters();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dumping
|
||||
|
||||
/// <summary>
|
||||
/// Cancel an in-progress dumping process
|
||||
/// </summary>
|
||||
public void CancelDumping() => Parameters.KillInternalProgram();
|
||||
|
||||
/// <summary>
|
||||
/// Eject the disc using DiscImageCreator
|
||||
/// </summary>
|
||||
public async Task<string> EjectDisc() =>
|
||||
await RunStandaloneDiscImageCreatorCommand(Modules.DiscImageCreator.CommandStrings.Eject);
|
||||
|
||||
/// <summary>
|
||||
/// Reset the current drive using DiscImageCreator
|
||||
/// </summary>
|
||||
public async Task<string> ResetDrive() =>
|
||||
await RunStandaloneDiscImageCreatorCommand(Modules.DiscImageCreator.CommandStrings.Reset);
|
||||
|
||||
/// <summary>
|
||||
/// Execute the initial invocation of the dumping programs
|
||||
/// </summary>
|
||||
/// <param name="progress">Optional result progress callback</param>
|
||||
public async Task<Result> Run(IProgress<Result> progress = null)
|
||||
{
|
||||
// Check that we have the basics for dumping
|
||||
Result result = IsValidForDump();
|
||||
if (!result)
|
||||
return result;
|
||||
|
||||
// Invoke output processing, if needed
|
||||
if (!Options.ToolsInSeparateWindow)
|
||||
{
|
||||
outputQueue = new ProcessingQueue<string>(ProcessOutputs);
|
||||
Parameters.ReportStatus += OutputToLog;
|
||||
}
|
||||
|
||||
// Execute internal tool
|
||||
progress?.Report(Result.Success($"Executing {this.InternalProgram}... {(Options.ToolsInSeparateWindow ? "please wait!" : "see log for output!")}"));
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(this.OutputPath));
|
||||
await Task.Run(() => Parameters.ExecuteInternalProgram(Options.ToolsInSeparateWindow));
|
||||
progress?.Report(Result.Success($"{this.InternalProgram} has finished!"));
|
||||
|
||||
// Execute additional tools
|
||||
progress?.Report(Result.Success("Running any additional tools... see log for output!"));
|
||||
result = await Task.Run(() => ExecuteAdditionalTools());
|
||||
progress?.Report(result);
|
||||
|
||||
// Remove event handler if needed
|
||||
if (!Options.ToolsInSeparateWindow)
|
||||
{
|
||||
outputQueue.Dispose();
|
||||
Parameters.ReportStatus -= OutputToLog;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that the current environment has a complete dump and create submission info is possible
|
||||
/// </summary>
|
||||
/// <param name="resultProgress">Optional result progress callback</param>
|
||||
/// <param name="protectionProgress">Optional protection progress callback</param>
|
||||
/// <param name="processUserInfo">Optional user prompt to deal with submission information</param>
|
||||
/// <returns>Result instance with the outcome</returns>
|
||||
public async Task<Result> VerifyAndSaveDumpOutput(
|
||||
IProgress<Result> resultProgress = null,
|
||||
IProgress<ProtectionProgress> protectionProgress = null,
|
||||
Func<SubmissionInfo, (bool?, SubmissionInfo)> processUserInfo = null)
|
||||
{
|
||||
resultProgress?.Report(Result.Success("Gathering submission information... please wait!"));
|
||||
|
||||
// Get the output directory and filename separately
|
||||
string outputDirectory = Path.GetDirectoryName(this.OutputPath);
|
||||
string outputFilename = Path.GetFileName(this.OutputPath);
|
||||
|
||||
// Check to make sure that the output had all the correct files
|
||||
(bool foundFiles, List<string> missingFiles) = InfoTool.FoundAllFiles(outputDirectory, outputFilename, this.Parameters, false);
|
||||
if (!foundFiles)
|
||||
{
|
||||
resultProgress?.Report(Result.Failure($"There were files missing from the output:\n{string.Join("\n", missingFiles)}"));
|
||||
return Result.Failure("Error! Please check output directory as dump may be incomplete!");
|
||||
}
|
||||
|
||||
// Extract the information from the output files
|
||||
resultProgress?.Report(Result.Success("Extracting output information from output files..."));
|
||||
SubmissionInfo submissionInfo = await InfoTool.ExtractOutputInformation(
|
||||
this.OutputPath,
|
||||
this.Drive,
|
||||
this.System,
|
||||
this.Type,
|
||||
this.Options,
|
||||
this.Parameters,
|
||||
resultProgress,
|
||||
protectionProgress);
|
||||
resultProgress?.Report(Result.Success("Extracting information complete!"));
|
||||
|
||||
// Eject the disc automatically if configured to
|
||||
if (Options.EjectAfterDump == true)
|
||||
{
|
||||
resultProgress?.Report(Result.Success($"Ejecting disc in drive {Drive.Letter}"));
|
||||
await EjectDisc();
|
||||
}
|
||||
|
||||
// Reset the drive automatically if configured to
|
||||
if (this.InternalProgram == InternalProgram.DiscImageCreator && Options.DICResetDriveAfterDump)
|
||||
{
|
||||
resultProgress?.Report(Result.Success($"Resetting drive {Drive.Letter}"));
|
||||
await ResetDrive();
|
||||
}
|
||||
|
||||
// Get user-modifiable information if confugured to
|
||||
if (Options.PromptForDiscInformation && processUserInfo != null)
|
||||
{
|
||||
resultProgress?.Report(Result.Success("Waiting for additional disc information..."));
|
||||
|
||||
bool? filledInfo;
|
||||
(filledInfo, submissionInfo) = processUserInfo(submissionInfo);
|
||||
|
||||
if (filledInfo == true)
|
||||
resultProgress?.Report(Result.Success("Additional disc information added!"));
|
||||
else
|
||||
resultProgress?.Report(Result.Success("Disc information skipped!"));
|
||||
}
|
||||
|
||||
// Process special fields for site codes
|
||||
resultProgress?.Report(Result.Success("Processing site codes..."));
|
||||
InfoTool.ProcessSpecialFields(submissionInfo);
|
||||
resultProgress?.Report(Result.Success("Processing complete!"));
|
||||
|
||||
// Format the information for the text output
|
||||
resultProgress?.Report(Result.Success("Formatting information..."));
|
||||
(List<string> formattedValues, string formatResult) = InfoTool.FormatOutputData(submissionInfo, this.Options);
|
||||
if (formattedValues == null)
|
||||
resultProgress?.Report(Result.Success(formatResult));
|
||||
else
|
||||
resultProgress?.Report(Result.Failure(formatResult));
|
||||
|
||||
// Write the text output
|
||||
resultProgress?.Report(Result.Success("Writing information to !submissionInfo.txt..."));
|
||||
(bool txtSuccess, string txtResult) = InfoTool.WriteOutputData(outputDirectory, formattedValues);
|
||||
if (txtSuccess)
|
||||
resultProgress?.Report(Result.Success(txtResult));
|
||||
else
|
||||
resultProgress?.Report(Result.Failure(txtResult));
|
||||
|
||||
// Write the copy protection output
|
||||
if (Options.ScanForProtection && Options.OutputSeparateProtectionFile)
|
||||
{
|
||||
resultProgress?.Report(Result.Success("Writing protection to !protectionInfo.txt..."));
|
||||
bool scanSuccess = InfoTool.WriteProtectionData(outputDirectory, submissionInfo);
|
||||
if (scanSuccess)
|
||||
resultProgress?.Report(Result.Success("Writing complete!"));
|
||||
else
|
||||
resultProgress?.Report(Result.Failure("Writing could not complete!"));
|
||||
}
|
||||
|
||||
// Write the JSON output, if required
|
||||
if (Options.OutputSubmissionJSON)
|
||||
{
|
||||
resultProgress?.Report(Result.Success($"Writing information to !submissionInfo.json{(Options.IncludeArtifacts ? ".gz" : string.Empty)}..."));
|
||||
bool jsonSuccess = InfoTool.WriteOutputData(outputDirectory, submissionInfo, Options.IncludeArtifacts);
|
||||
if (jsonSuccess)
|
||||
resultProgress?.Report(Result.Success("Writing complete!"));
|
||||
else
|
||||
resultProgress?.Report(Result.Failure("Writing could not complete!"));
|
||||
}
|
||||
|
||||
// Compress the logs, if required
|
||||
if (Options.CompressLogFiles)
|
||||
{
|
||||
resultProgress?.Report(Result.Success("Compressing log files..."));
|
||||
(bool compressSuccess, string compressResult) = InfoTool.CompressLogFiles(outputDirectory, outputFilename, this.Parameters);
|
||||
if (compressSuccess)
|
||||
resultProgress?.Report(Result.Success(compressResult));
|
||||
else
|
||||
resultProgress?.Report(Result.Failure(compressResult));
|
||||
}
|
||||
|
||||
resultProgress?.Report(Result.Success("Submission information process complete!"));
|
||||
return Result.Success();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the parameters are valid
|
||||
/// </summary>
|
||||
/// <returns>True if the configuration is valid, false otherwise</returns>
|
||||
internal bool ParametersValid()
|
||||
{
|
||||
bool parametersValid = Parameters.IsValid();
|
||||
bool floppyValid = !(Drive.InternalDriveType == InternalDriveType.Floppy ^ Type == MediaType.FloppyDisk);
|
||||
|
||||
// TODO: HardDisk being in the Removable category is a hack, fix this later
|
||||
bool removableDiskValid = !((Drive.InternalDriveType == InternalDriveType.Removable || Drive.InternalDriveType == InternalDriveType.HardDisk)
|
||||
^ (Type == MediaType.CompactFlash || Type == MediaType.SDCard || Type == MediaType.FlashDrive || Type == MediaType.HardDisk));
|
||||
|
||||
return parametersValid && floppyValid && removableDiskValid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run any additional tools given a DumpEnvironment
|
||||
/// </summary>
|
||||
/// <returns>Result instance with the outcome</returns>
|
||||
private Result ExecuteAdditionalTools() => Result.Success("No external tools needed!");
|
||||
|
||||
/// <summary>
|
||||
/// Run internal program async with an input set of parameters
|
||||
/// </summary>
|
||||
/// <param name="parameters"></param>
|
||||
/// <returns>Standard output from commandline window</returns>
|
||||
private async Task<string> ExecuteInternalProgram(BaseParameters parameters)
|
||||
{
|
||||
Process childProcess;
|
||||
string output = await Task.Run(() =>
|
||||
{
|
||||
childProcess = new Process()
|
||||
{
|
||||
StartInfo = new ProcessStartInfo()
|
||||
{
|
||||
FileName = parameters.ExecutablePath,
|
||||
Arguments = parameters.GenerateParameters(),
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true,
|
||||
},
|
||||
};
|
||||
childProcess.Start();
|
||||
childProcess.WaitForExit(1000);
|
||||
|
||||
// Just in case, we want to push a button 5 times to clear any errors
|
||||
for (int i = 0; i < 5; i++)
|
||||
childProcess.StandardInput.WriteLine("Y");
|
||||
|
||||
string stdout = childProcess.StandardOutput.ReadToEnd();
|
||||
childProcess.Dispose();
|
||||
return stdout;
|
||||
});
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate the current environment is ready for a dump
|
||||
/// </summary>
|
||||
/// <returns>Result instance with the outcome</returns>
|
||||
private Result IsValidForDump()
|
||||
{
|
||||
// Validate that everything is good
|
||||
if (!ParametersValid())
|
||||
return Result.Failure("Error! Current configuration is not supported!");
|
||||
|
||||
// Fix the output paths, just in case
|
||||
this.OutputPath = InfoTool.NormalizeOutputPaths(this.OutputPath);
|
||||
|
||||
// Validate that the output path isn't on the dumping drive
|
||||
if (this.OutputPath[0] == Drive.Letter)
|
||||
return Result.Failure("Error! Cannot output to same drive that is being dumped!");
|
||||
|
||||
// Validate that the required program exists
|
||||
if (!File.Exists(Parameters.ExecutablePath))
|
||||
return Result.Failure($"Error! {Parameters.ExecutablePath} does not exist!");
|
||||
|
||||
// Validate that the dumping drive doesn't contain the executable
|
||||
string fullExecutablePath = Path.GetFullPath(Parameters.ExecutablePath);
|
||||
if (fullExecutablePath[0] == Drive.Letter)
|
||||
return Result.Failure("Error! Cannot dump same drive that executable resides on!");
|
||||
|
||||
// Validate that the current configuration is supported
|
||||
return Tools.GetSupportStatus(System, Type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate that DIscImageCreator is able to be found
|
||||
/// </summary>
|
||||
/// <returns>True if DiscImageCreator is found properly, false otherwise</returns>
|
||||
private bool RequiredProgramsExist()
|
||||
{
|
||||
// Validate that the path is configured
|
||||
if (string.IsNullOrWhiteSpace(Options.DiscImageCreatorPath))
|
||||
return false;
|
||||
|
||||
// Validate that the required program exists
|
||||
if (!File.Exists(Options.DiscImageCreatorPath))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run a standalone DiscImageCreator command
|
||||
/// </summary>
|
||||
/// <param name="command">Command string to run</param>
|
||||
/// <returns>The output of the command on success, null on error</returns>
|
||||
private async Task<string> RunStandaloneDiscImageCreatorCommand(string command)
|
||||
{
|
||||
// Validate that DiscImageCreator is all set
|
||||
if (!RequiredProgramsExist())
|
||||
return null;
|
||||
|
||||
// Validate we're not trying to eject a non-optical
|
||||
if (Drive.InternalDriveType != InternalDriveType.Optical)
|
||||
return null;
|
||||
|
||||
CancelDumping();
|
||||
|
||||
var parameters = new Modules.DiscImageCreator.Parameters(string.Empty)
|
||||
{
|
||||
BaseCommand = command,
|
||||
DriveLetter = Drive.Letter.ToString(),
|
||||
ExecutablePath = Options.DiscImageCreatorPath,
|
||||
};
|
||||
|
||||
return await ExecuteInternalProgram(parameters);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
2861
MPF.Library/InfoTool.cs
Normal file
2861
MPF.Library/InfoTool.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net48;netcoreapp3.1</TargetFrameworks>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<Title>MPF Library</Title>
|
||||
<TargetFrameworks>net48;net6.0</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win7-x64;win8-x64;win81-x64;win10-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<AssemblyName>MPF.Library</AssemblyName>
|
||||
<Description>Library code for MPF and MPF.Check</Description>
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
<Copyright>Copyright (c)2019-2021</Copyright>
|
||||
<Copyright>Copyright (c)2019-2023</Copyright>
|
||||
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
|
||||
<Version>2.1</Version>
|
||||
<Version>2.6.2</Version>
|
||||
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||
<FileVersion>$(Version)</FileVersion>
|
||||
<IncludeSource>true</IncludeSource>
|
||||
@@ -23,64 +21,21 @@
|
||||
<NrtShowRevision>false</NrtShowRevision>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)'!='netcoreapp3.1'">
|
||||
<DefineConstants>NET_FRAMEWORK</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'!='netcoreapp3.1'">
|
||||
<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>
|
||||
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
|
||||
<ProjectReference Include="..\MPF.Modules\MPF.Modules.csproj" />
|
||||
<ProjectReference Include="..\RedumpLib\RedumpLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Aaru\CICMMetadata\CICMMetadataEditor\**" />
|
||||
<Compile Remove="Aaru\CICMMetadata\java\**" />
|
||||
<Compile Remove="Aaru\CICMMetadata\samples\**" />
|
||||
<EmbeddedResource Remove="Aaru\CICMMetadata\CICMMetadataEditor\**" />
|
||||
<EmbeddedResource Remove="Aaru\CICMMetadata\java\**" />
|
||||
<EmbeddedResource Remove="Aaru\CICMMetadata\samples\**" />
|
||||
<None Remove="Aaru\CICMMetadata\CICMMetadataEditor\**" />
|
||||
<None Remove="Aaru\CICMMetadata\java\**" />
|
||||
<None Remove="Aaru\CICMMetadata\samples\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Aaru\CICMMetadata\.editorconfig" />
|
||||
<None Remove="Aaru\CICMMetadata\.git" />
|
||||
<None Remove="Aaru\CICMMetadata\.gitignore" />
|
||||
<None Remove="Aaru\CICMMetadata\.project" />
|
||||
<None Remove="Aaru\CICMMetadata\build.sh" />
|
||||
<None Remove="Aaru\CICMMetadata\cicm.xml" />
|
||||
<None Remove="Aaru\CICMMetadata\cicm.xsd" />
|
||||
<None Remove="Aaru\CICMMetadata\CICMMetadata.iml" />
|
||||
<None Remove="Aaru\CICMMetadata\dotnet\cicm.vb" />
|
||||
<None Remove="Aaru\CICMMetadata\README.md" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="1.7.0" GeneratePathProperty="true">
|
||||
<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="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
|
||||
<PackageReference Include="System.Management" Version="6.0.0-preview.6.21352.12" />
|
||||
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.1">
|
||||
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
|
||||
<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>
|
||||
@@ -90,8 +45,4 @@
|
||||
<Content Include="$(PkgBurnOutSharp)\content\**" PackagePath="contentFiles\any\any;content" CopyToOutputDirectory="Always" PackageCopyToOutput="true" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Management" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
341
MPF.Library/Protection.cs
Normal file
341
MPF.Library/Protection.cs
Normal file
@@ -0,0 +1,341 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using BinaryObjectScanner.Protection;
|
||||
using BurnOutSharp;
|
||||
using psxt001z;
|
||||
|
||||
namespace MPF.Library
|
||||
{
|
||||
public static class Protection
|
||||
{
|
||||
/// <summary>
|
||||
/// Run protection scan on a given path
|
||||
/// </summary>
|
||||
/// <param name="path">Path to scan for protection</param>
|
||||
/// <param name="options">Options object that determines what to scan</param>
|
||||
/// <param name="progress">Optional progress callback</param>
|
||||
/// <returns>Set of all detected copy protections with an optional error string</returns>
|
||||
public static async Task<(Dictionary<string, List<string>>, string)> RunProtectionScanOnPath(string path, Core.Data.Options options, IProgress<ProtectionProgress> progress = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var found = await Task.Run(() =>
|
||||
{
|
||||
var scanner = new Scanner(
|
||||
options.ScanArchivesForProtection,
|
||||
scanContents: true, // Hardcoded value to avoid issues
|
||||
scanGameEngines: false, // Hardcoded value to avoid issues
|
||||
options.ScanPackersForProtection,
|
||||
scanPaths: true, // Hardcoded value to avoid issues
|
||||
options.IncludeDebugProtectionInformation,
|
||||
progress);
|
||||
|
||||
return scanner.GetProtections(path);
|
||||
});
|
||||
|
||||
// If nothing was returned, return
|
||||
if (found == null || !found.Any())
|
||||
return (null, null);
|
||||
|
||||
// Filter out any empty protections
|
||||
var filteredProtections = found
|
||||
.Where(kvp => kvp.Value != null && kvp.Value.Any())
|
||||
.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value.OrderBy(s => s).ToList());
|
||||
|
||||
// Return the filtered set of protections
|
||||
return (filteredProtections, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (null, ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Format found protections to a deduplicated, ordered string
|
||||
/// </summary>
|
||||
/// <param name="protections">Dictionary of file to list of protection mappings</param>
|
||||
/// <returns>Detected protections, if any</returns>
|
||||
public static string FormatProtections(Dictionary<string, List<string>> protections)
|
||||
{
|
||||
// If the filtered list is empty in some way, return
|
||||
if (protections == null || !protections.Any())
|
||||
return "None found";
|
||||
|
||||
// Get an ordered list of distinct found protections
|
||||
var orderedDistinctProtections = protections
|
||||
.SelectMany(kvp => kvp.Value)
|
||||
.Distinct()
|
||||
.OrderBy(p => p);
|
||||
|
||||
// Sanitize and join protections for writing
|
||||
string protectionString = SanitizeFoundProtections(orderedDistinctProtections);
|
||||
if (string.IsNullOrWhiteSpace(protectionString))
|
||||
return "None found";
|
||||
|
||||
return protectionString;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the existence of an anti-modchip string from a PlayStation disc, if possible
|
||||
/// </summary>
|
||||
/// <param name="path">Path to scan for anti-modchip strings</param>
|
||||
/// <returns>Anti-modchip existence if possible, false on error</returns>
|
||||
public static async Task<bool> GetPlayStationAntiModchipDetected(string path)
|
||||
{
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var antiModchip = new PSXAntiModchip();
|
||||
foreach (string file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] fileContent = File.ReadAllBytes(file);
|
||||
string protection = antiModchip.CheckContents(file, fileContent, false);
|
||||
if (!string.IsNullOrWhiteSpace(protection))
|
||||
return true;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get if LibCrypt data is detected in the subchannel file, if possible
|
||||
/// </summary>
|
||||
/// <param name="sub">.sub file location</param>
|
||||
/// <returns>Status of the LibCrypt data, if possible</returns>
|
||||
public static bool? GetLibCryptDetected(string sub)
|
||||
{
|
||||
// If the file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(sub))
|
||||
return null;
|
||||
|
||||
return LibCrypt.CheckSubfile(sub);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sanitize unnecessary protection duplication from output
|
||||
/// </summary>
|
||||
/// <param name="foundProtections">Enumerable of found protections</param>
|
||||
public static string SanitizeFoundProtections(IEnumerable<string> foundProtections)
|
||||
{
|
||||
// ActiveMARK
|
||||
if (foundProtections.Any(p => p == "ActiveMARK 5") && foundProtections.Any(p => p == "ActiveMARK"))
|
||||
foundProtections = foundProtections.Where(p => p != "ActiveMARK");
|
||||
|
||||
// Cactus Data Shield
|
||||
if (foundProtections.Any(p => Regex.IsMatch(p, @"Cactus Data Shield [0-9]{3} .+")) && foundProtections.Any(p => p == "Cactus Data Shield 200"))
|
||||
foundProtections = foundProtections.Where(p => p != "Cactus Data Shield 200");
|
||||
|
||||
// CD-Check
|
||||
foundProtections = foundProtections.Where(p => p != "Executable-Based CD Check");
|
||||
|
||||
// CD-Cops
|
||||
if (foundProtections.Any(p => p == "CD-Cops") && foundProtections.Any(p => p.StartsWith("CD-Cops") && p.Length > "CD-Cops".Length))
|
||||
foundProtections = foundProtections.Where(p => p != "CD-Cops");
|
||||
|
||||
// CD-Key / Serial
|
||||
foundProtections = foundProtections.Where(p => p != "CD-Key / Serial");
|
||||
|
||||
// Electronic Arts
|
||||
if (foundProtections.Any(p => p == "EA CdKey Registration Module") && foundProtections.Any(p => p.StartsWith("EA CdKey Registration Module") && p.Length > "EA CdKey Registration Module".Length))
|
||||
foundProtections = foundProtections.Where(p => p != "EA CdKey Registration Module");
|
||||
if (foundProtections.Any(p => p == "EA DRM Protection") && foundProtections.Any(p => p.StartsWith("EA DRM Protection") && p.Length > "EA DRM Protection".Length))
|
||||
foundProtections = foundProtections.Where(p => p != "EA DRM Protection");
|
||||
|
||||
// Games for Windows LIVE
|
||||
if (foundProtections.Any(p => p == "Games for Windows LIVE") && foundProtections.Any(p => p.StartsWith("Games for Windows LIVE") && !p.Contains("Zero Day Piracy Protection") && p.Length > "Games for Windows LIVE".Length))
|
||||
foundProtections = foundProtections.Where(p => p != "Games for Windows LIVE");
|
||||
|
||||
// Impulse Reactor
|
||||
if (foundProtections.Any(p => p.StartsWith("Impulse Reactor Core Module")) && foundProtections.Any(p => p == "Impulse Reactor"))
|
||||
foundProtections = foundProtections.Where(p => p != "Impulse Reactor");
|
||||
|
||||
// JoWood X-Prot
|
||||
if (foundProtections.Any(p => p.StartsWith("JoWood X-Prot")))
|
||||
{
|
||||
if (foundProtections.Any(p => Regex.IsMatch(p, @"JoWood X-Prot [0-9]\.[0-9]\.[0-9]\.[0-9]{2}")))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "JoWood X-Prot")
|
||||
.Where(p => p != "JoWood X-Prot v1.0-v1.3")
|
||||
.Where(p => p != "JoWood X-Prot v1.4+")
|
||||
.Where(p => p != "JoWood X-Prot v2");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "JoWood X-Prot v2"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "JoWood X-Prot")
|
||||
.Where(p => p != "JoWood X-Prot v1.0-v1.3")
|
||||
.Where(p => p != "JoWood X-Prot v1.4+");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "JoWood X-Prot v1.4+"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "JoWood X-Prot")
|
||||
.Where(p => p != "JoWood X-Prot v1.0-v1.3");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "JoWood X-Prot v1.0-v1.3"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "JoWood X-Prot");
|
||||
}
|
||||
}
|
||||
|
||||
// LaserLok
|
||||
// TODO: Figure this one out
|
||||
|
||||
// Online Registration
|
||||
foundProtections = foundProtections.Where(p => !p.StartsWith("Executable-Based Online Registration"));
|
||||
|
||||
// ProtectDISC / VOB ProtectCD/DVD
|
||||
// TODO: Figure this one out
|
||||
|
||||
// SafeCast
|
||||
// TODO: Figure this one out
|
||||
|
||||
// Cactus Data Shield / SafeDisc
|
||||
if (foundProtections.Any(p => p == "Cactus Data Shield 300 (Confirm presence of other CDS-300 files)"))
|
||||
{
|
||||
foundProtections = foundProtections
|
||||
.Where(p => p != "Cactus Data Shield 300 (Confirm presence of other CDS-300 files)");
|
||||
|
||||
if (foundProtections.Any(p => !p.StartsWith("SafeDisc")))
|
||||
foundProtections = foundProtections.Append("Cactus Data Shield 300");
|
||||
}
|
||||
|
||||
// SafeDisc
|
||||
// TODO: Update based on new internal naming schemes
|
||||
if (foundProtections.Any(p => p.StartsWith("SafeDisc")))
|
||||
{
|
||||
if (foundProtections.Any(p => Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}")))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "SafeDisc")
|
||||
.Where(p => p != "SafeDisc 1/Lite")
|
||||
.Where(p => p != "SafeDisc 1-3")
|
||||
.Where(p => p != "SafeDisc 2")
|
||||
.Where(p => p != "SafeDisc 3.20-4.xx (version removed)")
|
||||
.Where(p => !p.StartsWith("SafeDisc (dplayerx.dll)"))
|
||||
.Where(p => !p.StartsWith("SafeDisc (drvmgt.dll)"))
|
||||
.Where(p => !p.StartsWith("SafeDisc (secdrv.sys)"))
|
||||
.Where(p => p != "SafeDisc Lite");
|
||||
}
|
||||
else if (foundProtections.Any(p => p.StartsWith("SafeDisc (drvmgt.dll)")))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "SafeDisc")
|
||||
.Where(p => p != "SafeDisc 1/Lite")
|
||||
.Where(p => p != "SafeDisc 1-3")
|
||||
.Where(p => p != "SafeDisc 2")
|
||||
.Where(p => p != "SafeDisc 3.20-4.xx (version removed)")
|
||||
.Where(p => !p.StartsWith("SafeDisc (dplayerx.dll)"))
|
||||
.Where(p => !p.StartsWith("SafeDisc (secdrv.sys)"))
|
||||
.Where(p => p != "SafeDisc Lite");
|
||||
}
|
||||
else if (foundProtections.Any(p => p.StartsWith("SafeDisc (secdrv.sys)")))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "SafeDisc")
|
||||
.Where(p => p != "SafeDisc 1/Lite")
|
||||
.Where(p => p != "SafeDisc 1-3")
|
||||
.Where(p => p != "SafeDisc 2")
|
||||
.Where(p => p != "SafeDisc 3.20-4.xx (version removed)")
|
||||
.Where(p => !p.StartsWith("SafeDisc (dplayerx.dll)"))
|
||||
.Where(p => p != "SafeDisc Lite");
|
||||
}
|
||||
else if (foundProtections.Any(p => p.StartsWith("SafeDisc (dplayerx.dll)")))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "SafeDisc")
|
||||
.Where(p => p != "SafeDisc 1/Lite")
|
||||
.Where(p => p != "SafeDisc 1-3")
|
||||
.Where(p => p != "SafeDisc 2")
|
||||
.Where(p => p != "SafeDisc 3.20-4.xx (version removed)")
|
||||
.Where(p => p != "SafeDisc Lite");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "SafeDisc 3.20-4.xx (version removed)"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "SafeDisc")
|
||||
.Where(p => p != "SafeDisc 1/Lite")
|
||||
.Where(p => p != "SafeDisc 1-3")
|
||||
.Where(p => p != "SafeDisc 2")
|
||||
.Where(p => p != "SafeDisc Lite");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "SafeDisc 2"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "SafeDisc")
|
||||
.Where(p => p != "SafeDisc 1/Lite")
|
||||
.Where(p => p != "SafeDisc 1-3")
|
||||
.Where(p => p != "SafeDisc Lite");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "SafeDisc 1/Lite"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "SafeDisc")
|
||||
.Where(p => p != "SafeDisc 1-3")
|
||||
.Where(p => p != "SafeDisc Lite");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "SafeDisc Lite"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "SafeDisc")
|
||||
.Where(p => p != "SafeDisc 1-3");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "SafeDisc 1-3"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "SafeDisc");
|
||||
}
|
||||
}
|
||||
|
||||
// SecuROM
|
||||
// TODO: Figure this one out
|
||||
|
||||
// SolidShield
|
||||
// TODO: Figure this one out
|
||||
|
||||
// StarForce
|
||||
if (foundProtections.Any(p => p.StartsWith("StarForce")))
|
||||
{
|
||||
if (foundProtections.Any(p => Regex.IsMatch(p, @"StarForce [0-9]+\..+")))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "StarForce")
|
||||
.Where(p => p != "StarForce 3-5")
|
||||
.Where(p => p != "StarForce 5")
|
||||
.Where(p => p != "StarForce 5 [Protected Module]");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "StarForce 5 [Protected Module]"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "StarForce")
|
||||
.Where(p => p != "StarForce 3-5")
|
||||
.Where(p => p != "StarForce 5");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "StarForce 5"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "StarForce")
|
||||
.Where(p => p != "StarForce 3-5");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "StarForce 3-5"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "StarForce");
|
||||
}
|
||||
}
|
||||
|
||||
// Sysiphus
|
||||
if (foundProtections.Any(p => p == "Sysiphus") && foundProtections.Any(p => p.StartsWith("Sysiphus") && p.Length > "Sysiphus".Length))
|
||||
foundProtections = foundProtections.Where(p => p != "Sysiphus");
|
||||
|
||||
// TAGES
|
||||
// TODO: Figure this one out
|
||||
|
||||
// XCP
|
||||
if (foundProtections.Any(p => p == "XCP") && foundProtections.Any(p => p.StartsWith("XCP") && p.Length > "XCP".Length))
|
||||
foundProtections = foundProtections.Where(p => p != "XCP");
|
||||
|
||||
return string.Join(", ", foundProtections);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
using MPF.Data;
|
||||
|
||||
namespace MPF.Redump
|
||||
{
|
||||
/// <summary>
|
||||
/// Information pertaining to Redump systems
|
||||
/// </summary>
|
||||
public static class Extras
|
||||
{
|
||||
#region Special lists
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that are not publically accessible
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem?[] BannedSystems = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.AudioCD,
|
||||
RedumpSystem.BDVideo,
|
||||
RedumpSystem.DVDVideo,
|
||||
RedumpSystem.HasbroVideoNow,
|
||||
RedumpSystem.HasbroVideoNowColor,
|
||||
RedumpSystem.HasbroVideoNowJr,
|
||||
RedumpSystem.HasbroVideoNowXP,
|
||||
RedumpSystem.KonamiM2,
|
||||
RedumpSystem.MicrosoftXbox360,
|
||||
RedumpSystem.MicrosoftXboxOne,
|
||||
//RedumpSystem.MicrosoftXboxSeriesXS,
|
||||
RedumpSystem.NavisoftNaviken21,
|
||||
RedumpSystem.NintendoWii,
|
||||
RedumpSystem.NintendoWiiU,
|
||||
RedumpSystem.PanasonicM2,
|
||||
RedumpSystem.SegaPrologue21,
|
||||
RedumpSystem.SegaRingEdge,
|
||||
RedumpSystem.SegaRingEdge2,
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
RedumpSystem.SonyPlayStation4,
|
||||
//RedumpSystem.SonyPlayStation5,
|
||||
RedumpSystem.VideoCD,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that have a Cues pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem?[] HasCues = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.AppleMacintosh,
|
||||
RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem,
|
||||
RedumpSystem.AudioCD,
|
||||
RedumpSystem.BandaiPippin,
|
||||
RedumpSystem.BandaiPlaydiaQuickInteractiveSystem,
|
||||
RedumpSystem.CommodoreAmigaCD,
|
||||
RedumpSystem.CommodoreAmigaCD32,
|
||||
RedumpSystem.CommodoreAmigaCDTV,
|
||||
RedumpSystem.FujitsuFMTownsseries,
|
||||
RedumpSystem.funworldPhotoPlay,
|
||||
RedumpSystem.HasbroVideoNow,
|
||||
RedumpSystem.HasbroVideoNowColor,
|
||||
RedumpSystem.HasbroVideoNowJr,
|
||||
RedumpSystem.HasbroVideoNowXP,
|
||||
RedumpSystem.IBMPCcompatible,
|
||||
RedumpSystem.IncredibleTechnologiesEagle,
|
||||
RedumpSystem.KonamieAmusement,
|
||||
RedumpSystem.KonamiFireBeat,
|
||||
RedumpSystem.KonamiM2,
|
||||
RedumpSystem.KonamiSystemGV,
|
||||
RedumpSystem.MattelFisherPriceiXL,
|
||||
RedumpSystem.MattelHyperScan,
|
||||
RedumpSystem.MemorexVisualInformationSystem,
|
||||
RedumpSystem.MicrosoftXbox,
|
||||
RedumpSystem.MicrosoftXbox360,
|
||||
RedumpSystem.NamcoSegaNintendoTriforce,
|
||||
RedumpSystem.NamcoSystem246,
|
||||
RedumpSystem.NavisoftNaviken21,
|
||||
RedumpSystem.NECPCEngineCDTurboGrafxCD,
|
||||
RedumpSystem.NECPC88series,
|
||||
RedumpSystem.NECPC98series,
|
||||
RedumpSystem.NECPCFXPCFXGA,
|
||||
RedumpSystem.PalmOS,
|
||||
RedumpSystem.Panasonic3DOInteractiveMultiplayer,
|
||||
RedumpSystem.PanasonicM2,
|
||||
RedumpSystem.PhilipsCDi,
|
||||
RedumpSystem.PhotoCD,
|
||||
RedumpSystem.PlayStationGameSharkUpdates,
|
||||
RedumpSystem.SegaChihiro,
|
||||
RedumpSystem.SegaDreamcast,
|
||||
RedumpSystem.SegaMegaCDSegaCD,
|
||||
RedumpSystem.SegaNaomi,
|
||||
RedumpSystem.SegaNaomi2,
|
||||
RedumpSystem.SegaPrologue21,
|
||||
RedumpSystem.SegaSaturn,
|
||||
RedumpSystem.SNKNeoGeoCD,
|
||||
RedumpSystem.SonyPlayStation,
|
||||
RedumpSystem.SonyPlayStation2,
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
RedumpSystem.TABAustriaQuizard,
|
||||
RedumpSystem.TomyKissSite,
|
||||
RedumpSystem.VideoCD,
|
||||
RedumpSystem.VTechVFlashVSmilePro,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that has a Dat pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem?[] HasDat = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.MicrosoftXboxBIOS,
|
||||
RedumpSystem.NintendoGameCubeBIOS,
|
||||
RedumpSystem.SonyPlayStationBIOS,
|
||||
RedumpSystem.SonyPlayStation2BIOS,
|
||||
|
||||
RedumpSystem.AppleMacintosh,
|
||||
RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem,
|
||||
RedumpSystem.AudioCD,
|
||||
RedumpSystem.BandaiPippin,
|
||||
RedumpSystem.BandaiPlaydiaQuickInteractiveSystem,
|
||||
RedumpSystem.BDVideo,
|
||||
RedumpSystem.CommodoreAmigaCD,
|
||||
RedumpSystem.CommodoreAmigaCD32,
|
||||
RedumpSystem.CommodoreAmigaCDTV,
|
||||
RedumpSystem.DVDVideo,
|
||||
RedumpSystem.FujitsuFMTownsseries,
|
||||
RedumpSystem.funworldPhotoPlay,
|
||||
RedumpSystem.HasbroVideoNow,
|
||||
RedumpSystem.HasbroVideoNowColor,
|
||||
RedumpSystem.HasbroVideoNowJr,
|
||||
RedumpSystem.HasbroVideoNowXP,
|
||||
RedumpSystem.IBMPCcompatible,
|
||||
RedumpSystem.IncredibleTechnologiesEagle,
|
||||
RedumpSystem.KonamieAmusement,
|
||||
RedumpSystem.KonamiFireBeat,
|
||||
RedumpSystem.KonamiM2,
|
||||
RedumpSystem.KonamiSystemGV,
|
||||
RedumpSystem.MattelFisherPriceiXL,
|
||||
RedumpSystem.MattelHyperScan,
|
||||
RedumpSystem.MemorexVisualInformationSystem,
|
||||
RedumpSystem.MicrosoftXbox,
|
||||
RedumpSystem.MicrosoftXbox360,
|
||||
RedumpSystem.MicrosoftXboxOne,
|
||||
//RedumpSystem.MicrosoftXboxSeriesXS,
|
||||
RedumpSystem.NamcoSegaNintendoTriforce,
|
||||
RedumpSystem.NamcoSystem246,
|
||||
RedumpSystem.NavisoftNaviken21,
|
||||
RedumpSystem.NECPCEngineCDTurboGrafxCD,
|
||||
RedumpSystem.NECPC88series,
|
||||
RedumpSystem.NECPC98series,
|
||||
RedumpSystem.NECPCFXPCFXGA,
|
||||
RedumpSystem.NintendoGameCube,
|
||||
RedumpSystem.NintendoWii,
|
||||
RedumpSystem.NintendoWiiU,
|
||||
RedumpSystem.PalmOS,
|
||||
RedumpSystem.Panasonic3DOInteractiveMultiplayer,
|
||||
RedumpSystem.PanasonicM2,
|
||||
RedumpSystem.PhilipsCDi,
|
||||
RedumpSystem.PhotoCD,
|
||||
RedumpSystem.PlayStationGameSharkUpdates,
|
||||
RedumpSystem.SegaChihiro,
|
||||
RedumpSystem.SegaDreamcast,
|
||||
RedumpSystem.SegaLindbergh,
|
||||
RedumpSystem.SegaMegaCDSegaCD,
|
||||
RedumpSystem.SegaNaomi,
|
||||
RedumpSystem.SegaNaomi2,
|
||||
RedumpSystem.SegaRingEdge,
|
||||
RedumpSystem.SegaRingEdge2,
|
||||
RedumpSystem.SegaSaturn,
|
||||
RedumpSystem.SNKNeoGeoCD,
|
||||
RedumpSystem.SonyPlayStation,
|
||||
RedumpSystem.SonyPlayStation2,
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
RedumpSystem.SonyPlayStation4,
|
||||
//RedumpSystem.SonyPlayStation5,
|
||||
RedumpSystem.SonyPlayStationPortable,
|
||||
RedumpSystem.TABAustriaQuizard,
|
||||
RedumpSystem.TomyKissSite,
|
||||
RedumpSystem.VideoCD,
|
||||
RedumpSystem.VMLabsNUON,
|
||||
RedumpSystem.VTechVFlashVSmilePro,
|
||||
RedumpSystem.ZAPiTGamesGameWaveFamilyEntertainmentSystem,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that has a Decrypted Keys pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem?[] HasDkeys = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that has a GDI pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem?[] HasGdi = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.NamcoSegaNintendoTriforce,
|
||||
RedumpSystem.SegaChihiro,
|
||||
RedumpSystem.SegaDreamcast,
|
||||
RedumpSystem.SegaNaomi,
|
||||
RedumpSystem.SegaNaomi2,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that has a Keys pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem?[] HasKeys = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.NintendoWiiU,
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that has an LSD pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem?[] HasLsd = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.IBMPCcompatible,
|
||||
RedumpSystem.SonyPlayStation,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that has an SBI pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem?[] HasSbi = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.IBMPCcompatible,
|
||||
RedumpSystem.SonyPlayStation,
|
||||
};
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,119 +0,0 @@
|
||||
using MPF.Data;
|
||||
|
||||
namespace MPF.Utilities
|
||||
{
|
||||
public static class EnumExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Determine the category based on the system
|
||||
/// </summary>
|
||||
/// <param name="system">KnownSystem value to check</param>
|
||||
/// <returns>KnownSystemCategory related to the system</returns>
|
||||
public static KnownSystemCategory Category(this KnownSystem? system)
|
||||
{
|
||||
if (system < KnownSystem.MarkerDiscBasedConsoleEnd)
|
||||
return KnownSystemCategory.DiscBasedConsole;
|
||||
/*
|
||||
else if (system < KnownSystem.MarkerOtherConsoleEnd)
|
||||
return KnownSystemCategory.OtherConsole;
|
||||
*/
|
||||
else if (system < KnownSystem.MarkerComputerEnd)
|
||||
return KnownSystemCategory.Computer;
|
||||
else if (system < KnownSystem.MarkerArcadeEnd)
|
||||
return KnownSystemCategory.Arcade;
|
||||
else if (system < KnownSystem.MarkerOtherEnd)
|
||||
return KnownSystemCategory.Other;
|
||||
else
|
||||
return KnownSystemCategory.Custom;
|
||||
}
|
||||
|
||||
/// <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 is considered audio-only
|
||||
/// </summary>
|
||||
/// <param name="system">KnownSystem 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 KnownSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case KnownSystem.AtariJaguarCD:
|
||||
case KnownSystem.AudioCD:
|
||||
case KnownSystem.DVDAudio:
|
||||
case KnownSystem.HasbroVideoNow:
|
||||
case KnownSystem.HasbroVideoNowColor:
|
||||
case KnownSystem.HasbroVideoNowJr:
|
||||
case KnownSystem.HasbroVideoNowXP:
|
||||
case KnownSystem.PhilipsCDi:
|
||||
case KnownSystem.SuperAudioCD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if a system is a marker value
|
||||
/// </summary>
|
||||
/// <param name="system">KnownSystem value to check</param>
|
||||
/// <returns>True if the system is a marker value, false otherwise</returns>
|
||||
public static bool IsMarker(this KnownSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case KnownSystem.MarkerArcadeEnd:
|
||||
case KnownSystem.MarkerComputerEnd:
|
||||
case KnownSystem.MarkerDiscBasedConsoleEnd:
|
||||
// case KnownSystem.MarkerOtherConsoleEnd:
|
||||
case KnownSystem.MarkerOtherEnd:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if a system is considered XGD
|
||||
/// </summary>
|
||||
/// <param name="system">KnownSystem value to check</param>
|
||||
/// <returns>True if the system is XGD, false otherwise</returns>
|
||||
public static bool IsXGD(this KnownSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case KnownSystem.MicrosoftXBOX:
|
||||
case KnownSystem.MicrosoftXBOX360:
|
||||
case KnownSystem.MicrosoftXBOXOne:
|
||||
case KnownSystem.MicrosoftXboxSeriesXS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using MPF.Redump;
|
||||
|
||||
namespace MPF.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 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()
|
||||
{
|
||||
// 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
|
||||
using (var client = new RedumpWebClient())
|
||||
{
|
||||
(string tag, string url) = client.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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current informational version formatted as a string
|
||||
/// </summary>
|
||||
public static string GetCurrentVersion()
|
||||
{
|
||||
var assemblyVersion = Attribute.GetCustomAttribute(Assembly.GetEntryAssembly(), typeof(AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute;
|
||||
return assemblyVersion.InformationalVersion;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
namespace MPF.Aaru
|
||||
namespace MPF.Modules.Aaru
|
||||
{
|
||||
/// <summary>
|
||||
/// Top-level commands for Aaru
|
||||
@@ -7,6 +7,11 @@ namespace MPF.Aaru
|
||||
{
|
||||
public const string NONE = "";
|
||||
|
||||
// Archive Family
|
||||
public const string ArchivePrefixShort = "arc";
|
||||
public const string ArchivePrefixLong = "archive";
|
||||
public const string ArchiveInfo = "info";
|
||||
|
||||
// Database Family
|
||||
public const string DatabasePrefixShort = "db";
|
||||
public const string DatabasePrefixLong = "database";
|
||||
@@ -25,6 +30,7 @@ namespace MPF.Aaru
|
||||
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";
|
||||
@@ -32,7 +38,6 @@ namespace MPF.Aaru
|
||||
// Image Family
|
||||
public const string ImagePrefixShort = "i";
|
||||
public const string ImagePrefixLong = "image";
|
||||
public const string ImageAnalyze = "analyze";
|
||||
public const string ImageChecksumShort = "chk";
|
||||
public const string ImageChecksumLong = "checksum";
|
||||
public const string ImageCompareShort = "cmp";
|
||||
@@ -149,6 +154,7 @@ namespace MPF.Aaru
|
||||
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";
|
||||
@@ -168,9 +174,14 @@ namespace MPF.Aaru
|
||||
public const string SpamSumLong = "--spamsum";
|
||||
public const string StopOnErrorShort = "-s";
|
||||
public const string StopOnErrorLong = "--stop-on-error";
|
||||
public const string StoreEncryptedLong = "--store-encrypted";
|
||||
public const string TapeShort = "-t";
|
||||
public const string TapeLong = "--tape";
|
||||
public const string TitleKeysLong = "--title-keys";
|
||||
public const string TrapDiscShort = "-t";
|
||||
public const string TrapDiscLong = "--trap-disc";
|
||||
public const string TrimLong = "--trim";
|
||||
public const string UseBufferedReadsLong = "--use-buffered-reads";
|
||||
public const string VerboseShort = "-v";
|
||||
public const string VerboseLong = "--verbose";
|
||||
public const string VerifyDiscShort = "-w";
|
||||
@@ -195,6 +206,7 @@ namespace MPF.Aaru
|
||||
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";
|
||||
@@ -219,6 +231,8 @@ namespace MPF.Aaru
|
||||
public const string FormatConvertLong = "--format";
|
||||
public const string FormatDumpShort = "-t";
|
||||
public const string FormatDumpLong = "--format";
|
||||
public const string GeometryShort = "-g";
|
||||
public const string GeometryLong = "--geometry";
|
||||
public const string ImgBurnLogShort = "-b";
|
||||
public const string ImgBurnLogLong = "--ibg-log";
|
||||
public const string MediaBarcodeLong = "--media-barcode";
|
||||
@@ -1,6 +1,6 @@
|
||||
using MPF.Data;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.Aaru
|
||||
namespace MPF.Modules.Aaru
|
||||
{
|
||||
public static class Converters
|
||||
{
|
||||
File diff suppressed because it is too large
Load Diff
7391
MPF.Modules/Aaru/cicm.cs
Normal file
7391
MPF.Modules/Aaru/cicm.cs
Normal file
File diff suppressed because it is too large
Load Diff
4
MPF.Modules/AssemblyInfo.cs
Normal file
4
MPF.Modules/AssemblyInfo.cs
Normal file
@@ -0,0 +1,4 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Anything marked as internal can be used by the test methods
|
||||
[assembly: InternalsVisibleTo("MPF.Test")]
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
@@ -6,12 +6,15 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using BurnOutSharp.ProtectionType;
|
||||
using Compress.ThreadReaders;
|
||||
using MPF.Hashing;
|
||||
using MPF.Utilities;
|
||||
using System.Xml.Schema;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.Hashing;
|
||||
using MPF.Core.Utilities;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.Data
|
||||
namespace MPF.Modules
|
||||
{
|
||||
public abstract class BaseParameters
|
||||
{
|
||||
@@ -103,7 +106,7 @@ namespace MPF.Data
|
||||
/// <summary>
|
||||
/// Currently represented system
|
||||
/// </summary>
|
||||
public KnownSystem? System { get; set; }
|
||||
public RedumpSystem? System { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Currently represented media type
|
||||
@@ -126,13 +129,13 @@ namespace MPF.Data
|
||||
/// <summary>
|
||||
/// Generate parameters based on a set of known inputs
|
||||
/// </summary>
|
||||
/// <param name="system">KnownSystem value to use</param>
|
||||
/// <param name="system">RedumpSystem value to use</param>
|
||||
/// <param name="type">MediaType value to use</param>
|
||||
/// <param name="driveLetter">Drive letter to use</param>
|
||||
/// <param name="filename">Filename to use</param>
|
||||
/// <param name="driveSpeed">Drive speed to use</param>
|
||||
/// <param name="options">Options object containing all settings that may be used for setting parameters</param>
|
||||
public BaseParameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
public BaseParameters(RedumpSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
{
|
||||
this.System = system;
|
||||
this.Type = type;
|
||||
@@ -153,10 +156,11 @@ namespace MPF.Data
|
||||
/// Generate a SubmissionInfo for the output files
|
||||
/// </summary>
|
||||
/// <param name="submissionInfo">Base submission info to fill in specifics for</param>
|
||||
/// <param name="options">Options object representing user-defined options</param>
|
||||
/// <param name="basePath">Base filename and path to use for checking</param>
|
||||
/// <param name="drive">Drive representing the disc to get information from</param>
|
||||
/// <param name="includeArtifacts">True to include output files as encoded artifacts, false otherwise</param>
|
||||
public abstract void GenerateSubmissionInfo(SubmissionInfo submissionInfo, string basePath, Drive drive, bool includeArtifacts);
|
||||
public abstract void GenerateSubmissionInfo(SubmissionInfo submissionInfo, Options options, string basePath, Drive drive, bool includeArtifacts);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -241,7 +245,7 @@ namespace MPF.Data
|
||||
/// </summary>
|
||||
/// <param name="parameters">String possibly representing parameters</param>
|
||||
/// <returns>True if the parameters were set correctly, false otherwise</returns>
|
||||
protected virtual bool ValidateAndSetParameters(string parameters) => true;
|
||||
protected virtual bool ValidateAndSetParameters(string parameters) => !string.IsNullOrWhiteSpace(parameters);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -308,12 +312,7 @@ namespace MPF.Data
|
||||
/// <param name="index">Current index</param>
|
||||
/// <returns>True if the next item exists, false otherwise</returns>
|
||||
protected static bool DoesExist(List<string> parameters, int index)
|
||||
{
|
||||
if (index >= parameters.Count)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
=> index < parameters.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Get the Base64 representation of a string
|
||||
@@ -348,21 +347,16 @@ namespace MPF.Data
|
||||
return BitConverter.ToString(bytes).Replace("-", string.Empty);
|
||||
}
|
||||
|
||||
return string.Join("\n", File.ReadAllLines(filename));
|
||||
return File.ReadAllText(filename);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether a string is a valid drive letter
|
||||
/// </summary>
|
||||
/// <param name="parameter">String value to check</param>
|
||||
/// <returns>True if it's a valid drive letter, false otherwise</returns>
|
||||
/// <returns>True if it's a valid drive letter, false otherwise</W>
|
||||
protected static bool IsValidDriveLetter(string parameter)
|
||||
{
|
||||
if (!Regex.IsMatch(parameter, @"^[A-Z]:?\\?$"))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
=> Regex.IsMatch(parameter, @"^[A-Z]:?\\?$");
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether a string is a valid bool
|
||||
@@ -370,9 +364,7 @@ namespace MPF.Data
|
||||
/// <param name="parameter">String value to check</param>
|
||||
/// <returns>True if it's a valid bool, false otherwise</returns>
|
||||
protected static bool IsValidBool(string parameter)
|
||||
{
|
||||
return bool.TryParse(parameter, out bool _);
|
||||
}
|
||||
=> bool.TryParse(parameter, out bool _);
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether a string is a valid byte
|
||||
@@ -462,9 +454,7 @@ namespace MPF.Data
|
||||
/// <param name="i">Reference to the position in the parts</param>
|
||||
/// <returns>True if the parameter was processed successfully or skipped, false otherwise</returns>
|
||||
protected bool ProcessFlagParameter(List<string> parts, string flagString, ref int i)
|
||||
{
|
||||
return ProcessFlagParameter(parts, null, flagString, ref i);
|
||||
}
|
||||
=> ProcessFlagParameter(parts, null, flagString, ref i);
|
||||
|
||||
/// <summary>
|
||||
/// Process a flag parameter
|
||||
@@ -499,9 +489,7 @@ namespace MPF.Data
|
||||
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
|
||||
/// <returns>True if the parameter was processed successfully or skipped, false otherwise</returns>
|
||||
protected bool ProcessBooleanParameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
|
||||
{
|
||||
return ProcessBooleanParameter(parts, null, flagString, ref i, missingAllowed);
|
||||
}
|
||||
=> ProcessBooleanParameter(parts, null, flagString, ref i, missingAllowed);
|
||||
|
||||
/// <summary>
|
||||
/// Process a boolean parameter
|
||||
@@ -576,9 +564,7 @@ namespace MPF.Data
|
||||
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
|
||||
/// <returns>SByte value if success, SByte.MinValue if skipped, null on error/returns>
|
||||
protected sbyte? ProcessInt8Parameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
|
||||
{
|
||||
return ProcessInt8Parameter(parts, null, flagString, ref i, missingAllowed);
|
||||
}
|
||||
=> ProcessInt8Parameter(parts, null, flagString, ref i, missingAllowed);
|
||||
|
||||
/// <summary>
|
||||
/// Process an sbyte parameter
|
||||
@@ -639,6 +625,7 @@ namespace MPF.Data
|
||||
|
||||
string valuePart = commandParts[1];
|
||||
|
||||
this[longFlagString] = true;
|
||||
(string value, long factor) = ExtractFactorFromValue(valuePart);
|
||||
return (sbyte)(sbyte.Parse(value) * factor);
|
||||
}
|
||||
@@ -655,9 +642,7 @@ namespace MPF.Data
|
||||
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
|
||||
/// <returns>Int16 value if success, Int16.MinValue if skipped, null on error/returns>
|
||||
protected short? ProcessInt16Parameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
|
||||
{
|
||||
return ProcessInt16Parameter(parts, null, flagString, ref i, missingAllowed);
|
||||
}
|
||||
=> ProcessInt16Parameter(parts, null, flagString, ref i, missingAllowed);
|
||||
|
||||
/// <summary>
|
||||
/// Process an Int16 parameter
|
||||
@@ -717,6 +702,7 @@ namespace MPF.Data
|
||||
|
||||
string valuePart = commandParts[1];
|
||||
|
||||
this[longFlagString] = true;
|
||||
(string value, long factor) = ExtractFactorFromValue(valuePart);
|
||||
return (short)(short.Parse(value) * factor);
|
||||
}
|
||||
@@ -733,9 +719,7 @@ namespace MPF.Data
|
||||
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
|
||||
/// <returns>Int32 value if success, Int32.MinValue if skipped, null on error/returns>
|
||||
protected int? ProcessInt32Parameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
|
||||
{
|
||||
return ProcessInt32Parameter(parts, null, flagString, ref i, missingAllowed);
|
||||
}
|
||||
=> ProcessInt32Parameter(parts, null, flagString, ref i, missingAllowed);
|
||||
|
||||
/// <summary>
|
||||
/// Process an Int32 parameter
|
||||
@@ -795,6 +779,7 @@ namespace MPF.Data
|
||||
|
||||
string valuePart = commandParts[1];
|
||||
|
||||
this[longFlagString] = true;
|
||||
(string value, long factor) = ExtractFactorFromValue(valuePart);
|
||||
return (int)(int.Parse(value) * factor);
|
||||
}
|
||||
@@ -811,9 +796,7 @@ namespace MPF.Data
|
||||
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
|
||||
/// <returns>Int64 value if success, Int64.MinValue if skipped, null on error/returns>
|
||||
protected long? ProcessInt64Parameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
|
||||
{
|
||||
return ProcessInt64Parameter(parts, null, flagString, ref i, missingAllowed);
|
||||
}
|
||||
=> ProcessInt64Parameter(parts, null, flagString, ref i, missingAllowed);
|
||||
|
||||
/// <summary>
|
||||
/// Process an Int64 parameter
|
||||
@@ -873,6 +856,7 @@ namespace MPF.Data
|
||||
|
||||
string valuePart = commandParts[1];
|
||||
|
||||
this[longFlagString] = true;
|
||||
(string value, long factor) = ExtractFactorFromValue(valuePart);
|
||||
return long.Parse(value) * factor;
|
||||
}
|
||||
@@ -881,7 +865,7 @@ namespace MPF.Data
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process an Int64 parameter
|
||||
/// Process an string parameter
|
||||
/// </summary>
|
||||
/// <param name="parts">List of parts to be referenced</param>
|
||||
/// <param name="flagString">Flag string, if available</param>
|
||||
@@ -889,9 +873,7 @@ namespace MPF.Data
|
||||
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
|
||||
/// <returns>String value if possible, string.Empty on missing, null on error</returns>
|
||||
protected string ProcessStringParameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
|
||||
{
|
||||
return ProcessStringParameter(parts, null, flagString, ref i, missingAllowed);
|
||||
}
|
||||
=> ProcessStringParameter(parts, null, flagString, ref i, missingAllowed);
|
||||
|
||||
/// <summary>
|
||||
/// Process a string parameter
|
||||
@@ -957,6 +939,84 @@ namespace MPF.Data
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process a byte parameter
|
||||
/// </summary>
|
||||
/// <param name="parts">List of parts to be referenced</param>
|
||||
/// <param name="flagString">Flag string, if available</param>
|
||||
/// <param name="i">Reference to the position in the parts</param>
|
||||
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
|
||||
/// <returns>Byte value if success, Byte.MinValue if skipped, null on error/returns>
|
||||
protected byte? ProcessUInt8Parameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
|
||||
=> ProcessUInt8Parameter(parts, null, flagString, ref i, missingAllowed);
|
||||
|
||||
/// <summary>
|
||||
/// Process a byte parameter
|
||||
/// </summary>
|
||||
/// <param name="parts">List of parts to be referenced</param>
|
||||
/// <param name="shortFlagString">Short flag string, if available</param>
|
||||
/// <param name="longFlagString">Long flag string, if available</param>
|
||||
/// <param name="i">Reference to the position in the parts</param>
|
||||
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
|
||||
/// <returns>Byte value if success, Byte.MinValue if skipped, null on error/returns>
|
||||
protected byte? ProcessUInt8Parameter(List<string> parts, string shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
|
||||
{
|
||||
if (parts == null)
|
||||
return null;
|
||||
|
||||
if (parts[i] == shortFlagString || parts[i] == longFlagString)
|
||||
{
|
||||
if (!IsFlagSupported(longFlagString))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else if (!DoesExist(parts, i + 1))
|
||||
{
|
||||
if (missingAllowed)
|
||||
this[longFlagString] = true;
|
||||
|
||||
return null;
|
||||
}
|
||||
else if (IsFlagSupported(parts[i + 1]))
|
||||
{
|
||||
if (missingAllowed)
|
||||
this[longFlagString] = true;
|
||||
|
||||
return null;
|
||||
}
|
||||
else if (!IsValidInt8(parts[i + 1]))
|
||||
{
|
||||
if (missingAllowed)
|
||||
this[longFlagString] = true;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
this[longFlagString] = true;
|
||||
i++;
|
||||
|
||||
(string value, long factor) = ExtractFactorFromValue(parts[i]);
|
||||
return (byte)(byte.Parse(value) * factor);
|
||||
}
|
||||
else if (parts[i].StartsWith(shortFlagString + "=") || parts[i].StartsWith(longFlagString + "="))
|
||||
{
|
||||
if (!IsFlagSupported(longFlagString))
|
||||
return null;
|
||||
|
||||
string[] commandParts = parts[i].Split('=');
|
||||
if (commandParts.Length != 2)
|
||||
return null;
|
||||
|
||||
string valuePart = commandParts[1];
|
||||
|
||||
this[longFlagString] = true;
|
||||
(string value, long factor) = ExtractFactorFromValue(valuePart);
|
||||
return (byte)(byte.Parse(value) * factor);
|
||||
}
|
||||
|
||||
return Byte.MinValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get yhe trimmed value and multiplication factor from a value
|
||||
/// </summary>
|
||||
@@ -1023,6 +1083,155 @@ namespace MPF.Data
|
||||
|
||||
#region Common Information Extraction
|
||||
|
||||
/// <summary>
|
||||
/// Generate the proper datfile from the input Datafile, if possible
|
||||
/// </summary>
|
||||
/// <param name="datafile">.dat file location</param>
|
||||
/// <returns>Relevant pieces of the datfile, null on error</returns>
|
||||
protected static string GenerateDatfile(Datafile datafile)
|
||||
{
|
||||
// If we don't have a valid datafile, we can't do anything
|
||||
if (datafile?.Games == null || datafile.Games.Length == 0 || datafile.Games[0]?.Roms == null || datafile.Games[0].Roms.Length == 0)
|
||||
return null;
|
||||
|
||||
// Otherwise, reconstruct the hash data with only the required info
|
||||
try
|
||||
{
|
||||
var roms = datafile.Games[0].Roms;
|
||||
|
||||
string datString = string.Empty;
|
||||
for (int i = 0; i < roms.Length; i++)
|
||||
{
|
||||
var rom = roms[i];
|
||||
datString += $"<rom name=\"{rom.Name}\" size=\"{rom.Size}\" crc=\"{rom.Crc}\" md5=\"{rom.Md5}\" sha1=\"{rom.Sha1}\" />\n";
|
||||
}
|
||||
|
||||
datString.TrimEnd('\n');
|
||||
return datString;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the exception is right now
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Datafile from a standard DAT
|
||||
/// </summary>
|
||||
/// <param name="dat">Path to the DAT file to parse</param>
|
||||
/// <returns>Filled Datafile on success, null on error</returns>
|
||||
protected static Datafile GetDatafile(string dat)
|
||||
{
|
||||
// If there's no path, we can't read the file
|
||||
if (string.IsNullOrWhiteSpace(dat))
|
||||
return null;
|
||||
|
||||
// If the file doesn't exist, we can't read it
|
||||
if (!File.Exists(dat))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
// Open and read in the XML file
|
||||
XmlReader xtr = XmlReader.Create(dat, new XmlReaderSettings
|
||||
{
|
||||
CheckCharacters = false,
|
||||
DtdProcessing = DtdProcessing.Ignore,
|
||||
IgnoreComments = true,
|
||||
IgnoreWhitespace = true,
|
||||
ValidationFlags = XmlSchemaValidationFlags.None,
|
||||
ValidationType = ValidationType.None,
|
||||
});
|
||||
|
||||
// If the reader is null for some reason, we can't do anything
|
||||
if (xtr == null)
|
||||
return null;
|
||||
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(Datafile));
|
||||
Datafile obj = serializer.Deserialize(xtr) as Datafile;
|
||||
|
||||
return obj;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the exception is right now
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets disc information from a PIC file
|
||||
/// </summary>
|
||||
/// <param name="pic">Path to a PIC.bin file</param>
|
||||
/// <returns>Filled PICDiscInformation on success, null on error</returns>
|
||||
/// <remarks>This omits the emergency brake information, if it exists</remarks>
|
||||
protected static PICDiscInformation GetDiscInformation(string pic)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(File.OpenRead(pic)))
|
||||
{
|
||||
var di = new PICDiscInformation();
|
||||
|
||||
// Read the initial disc information
|
||||
di.DataStructureLength = br.ReadUInt16BigEndian();
|
||||
di.Reserved0 = br.ReadByte();
|
||||
di.Reserved1 = br.ReadByte();
|
||||
|
||||
// Create a list for the units
|
||||
var diUnits = new List<PICDiscInformationUnit>();
|
||||
|
||||
// Loop and read all available units
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
var unit = new PICDiscInformationUnit();
|
||||
|
||||
// We only accept Disc Information units, not Emergency Brake or other
|
||||
unit.DiscInformationIdentifier = Encoding.ASCII.GetString(br.ReadBytes(2));
|
||||
if (unit.DiscInformationIdentifier != "DI")
|
||||
break;
|
||||
|
||||
unit.DiscInformationFormat = br.ReadByte();
|
||||
unit.NumberOfUnitsInBlock = br.ReadByte();
|
||||
unit.Reserved0 = br.ReadByte();
|
||||
unit.SequenceNumber = br.ReadByte();
|
||||
unit.BytesInUse = br.ReadByte();
|
||||
unit.Reserved1 = br.ReadByte();
|
||||
|
||||
unit.DiscTypeIdentifier = Encoding.ASCII.GetString(br.ReadBytes(3));
|
||||
unit.DiscSizeClassVersion = br.ReadByte();
|
||||
switch (unit.DiscTypeIdentifier)
|
||||
{
|
||||
case PICDiscInformationUnit.DiscTypeIdentifierROM:
|
||||
case PICDiscInformationUnit.DiscTypeIdentifierROMUltra:
|
||||
unit.FormatDependentContents = br.ReadBytes(52);
|
||||
break;
|
||||
case PICDiscInformationUnit.DiscTypeIdentifierReWritable:
|
||||
case PICDiscInformationUnit.DiscTypeIdentifierRecordable:
|
||||
unit.FormatDependentContents = br.ReadBytes(100);
|
||||
unit.DiscManufacturerID = br.ReadBytes(6);
|
||||
unit.MediaTypeID = br.ReadBytes(3);
|
||||
unit.TimeStamp = br.ReadUInt16();
|
||||
unit.ProductRevisionNumber = br.ReadByte();
|
||||
break;
|
||||
}
|
||||
|
||||
diUnits.Add(unit);
|
||||
}
|
||||
|
||||
// Assign the units and return
|
||||
di.Units = diUnits.ToArray();
|
||||
return di;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error was
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input file path
|
||||
/// </summary>
|
||||
@@ -1142,6 +1351,8 @@ namespace MPF.Data
|
||||
if (string.IsNullOrWhiteSpace(hashData))
|
||||
return false;
|
||||
|
||||
// TODO: Use deserialization to Rom instead of Regex
|
||||
|
||||
Regex hashreg = new Regex(@"<rom name="".*?"" size=""(.*?)"" crc=""(.*?)"" md5=""(.*?)"" sha1=""(.*?)""");
|
||||
Match m = hashreg.Match(hashData);
|
||||
if (m.Success)
|
||||
@@ -1159,39 +1370,89 @@ namespace MPF.Data
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the existance of an anti-modchip string from a PlayStation disc, if possible
|
||||
/// Get the split values for ISO-based media
|
||||
/// </summary>
|
||||
/// <param name="driveLetter">Drive letter to use to check</param>
|
||||
/// <returns>Anti-modchip existance if possible, false on error</returns>
|
||||
protected static bool GetPlayStationAntiModchipDetected(char? driveLetter)
|
||||
/// <param name="datafile">Datafile represenging the hash data</param>
|
||||
/// <returns>True if extraction was successful, false otherwise</returns>
|
||||
protected static bool GetISOHashValues(Datafile datafile, out long size, out string crc32, out string md5, out string sha1)
|
||||
{
|
||||
// If there's no drive letter, we can't do this part
|
||||
if (driveLetter == null)
|
||||
size = -1; crc32 = null; md5 = null; sha1 = null;
|
||||
|
||||
if (datafile?.Games == null || datafile.Games.Length == 0 || datafile.Games[0].Roms.Length == 0)
|
||||
return false;
|
||||
|
||||
// If the folder no longer exists, we can't do this part
|
||||
string drivePath = driveLetter + ":\\";
|
||||
if (!Directory.Exists(drivePath))
|
||||
var rom = datafile.Games[0].Roms[0];
|
||||
|
||||
Int64.TryParse(rom.Size, out size);
|
||||
crc32 = rom.Crc;
|
||||
md5 = rom.Md5;
|
||||
sha1 = rom.Sha1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the layerbreak info associated from the disc information
|
||||
/// </summary>
|
||||
/// <param name="di">Disc information containing unformatted data</param>
|
||||
/// <returns>True if layerbreak info was set, false otherwise</returns>
|
||||
protected static bool GetLayerbreaks(PICDiscInformation di, out long? layerbreak1, out long? layerbreak2, out long? layerbreak3)
|
||||
{
|
||||
// Set the default values
|
||||
layerbreak1 = null; layerbreak2 = null; layerbreak3 = null;
|
||||
|
||||
// If we don't have valid disc information, we can't do anything
|
||||
if (di?.Units == null || di.Units.Length <= 1)
|
||||
return false;
|
||||
|
||||
// Scan through each file to check for the anti-modchip strings
|
||||
var antiModchip = new PSXAntiModchip();
|
||||
foreach (string path in Directory.EnumerateFiles(drivePath, "*", SearchOption.AllDirectories))
|
||||
int ReadFromArrayBigEndian(byte[] bytes, int offset)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] fileContent = File.ReadAllBytes(path);
|
||||
string protection = antiModchip.CheckContents(path, fileContent, includePosition: false);
|
||||
if (!string.IsNullOrWhiteSpace(protection))
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// No-op, we don't care what the error was
|
||||
}
|
||||
var span = new ReadOnlySpan<byte>(bytes, offset, 0x04);
|
||||
byte[] rev = span.ToArray();
|
||||
Array.Reverse(rev);
|
||||
return BitConverter.ToInt32(rev, 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
// Layerbreak 1 (2+ layers)
|
||||
if (di.Units.Length >= 2)
|
||||
{
|
||||
long offset = ReadFromArrayBigEndian(di.Units[0].FormatDependentContents, 0x0C);
|
||||
long value = ReadFromArrayBigEndian(di.Units[0].FormatDependentContents, 0x10);
|
||||
layerbreak1 = value - offset + 2;
|
||||
}
|
||||
|
||||
// Layerbreak 2 (3+ layers)
|
||||
if (di.Units.Length >= 3)
|
||||
{
|
||||
long offset = ReadFromArrayBigEndian(di.Units[1].FormatDependentContents, 0x0C);
|
||||
long value = ReadFromArrayBigEndian(di.Units[1].FormatDependentContents, 0x10);
|
||||
layerbreak2 = layerbreak1 + value - offset + 2;
|
||||
}
|
||||
|
||||
// Layerbreak 3 (4 layers)
|
||||
if (di.Units.Length >= 4)
|
||||
{
|
||||
long offset = ReadFromArrayBigEndian(di.Units[2].FormatDependentContents, 0x0C);
|
||||
long value = ReadFromArrayBigEndian(di.Units[2].FormatDependentContents, 0x10);
|
||||
layerbreak3 = layerbreak2 + value - offset + 2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the PIC identifier from the first disc information unit, if possible
|
||||
/// </summary>
|
||||
/// <param name="di">Disc information containing the data</param>
|
||||
/// <returns>String representing the PIC identifier, null on error</returns>
|
||||
protected static string GetPICIdentifier(PICDiscInformation di)
|
||||
{
|
||||
// If we don't have valid disc information, we can't do anything
|
||||
if (di?.Units == null || di.Units.Length <= 1)
|
||||
return null;
|
||||
|
||||
// We assume the identifier is consistent across all units
|
||||
return di.Units[0].DiscTypeIdentifier;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1202,7 +1463,7 @@ namespace MPF.Data
|
||||
/// <param name="region">Output region, if possible</param>
|
||||
/// <param name="date">Output EXE date in "yyyy-mm-dd" format if possible, null on error</param>
|
||||
/// <returns></returns>
|
||||
protected static bool GetPlayStationExecutableInfo(char? driveLetter, out string serial, out RedumpRegion? region, out string date)
|
||||
protected static bool GetPlayStationExecutableInfo(char? driveLetter, out string serial, out Region? region, out string date)
|
||||
{
|
||||
serial = null; region = null; date = null;
|
||||
|
||||
@@ -1238,11 +1499,21 @@ namespace MPF.Data
|
||||
if (!string.IsNullOrEmpty(bootValue))
|
||||
{
|
||||
var match = Regex.Match(bootValue, @"cdrom.?:\\?(.*)");
|
||||
if (match != null && match.Groups.Count > 1)
|
||||
if (match.Groups.Count > 1)
|
||||
{
|
||||
exeName = match.Groups[1].Value;
|
||||
exeName = exeName.Split(';')[0];
|
||||
serial = exeName.Replace('_', '-').Replace(".", string.Empty);
|
||||
// EXE name may have a trailing `;` after
|
||||
// EXE name should always be in all caps
|
||||
exeName = match.Groups[1].Value
|
||||
.Split(';')[0]
|
||||
.ToUpperInvariant();
|
||||
|
||||
// Serial is most of the EXE name normalized
|
||||
serial = exeName
|
||||
.Replace('_', '-')
|
||||
.Replace(".", string.Empty);
|
||||
|
||||
// Some games may have the EXE in a subfolder
|
||||
serial = Path.GetFileName(serial);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1299,6 +1570,117 @@ namespace MPF.Data
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the internal serial from a PlayStation 3 disc, if possible
|
||||
/// </summary>
|
||||
/// <param name="driveLetter">Drive letter to use to check</param>
|
||||
/// <returns>Internal disc serial if possible, null on error</returns>
|
||||
protected static string GetPlayStation3Serial(char? driveLetter)
|
||||
{
|
||||
// If there's no drive letter, we can't do this part
|
||||
if (driveLetter == null)
|
||||
return null;
|
||||
|
||||
// If the folder no longer exists, we can't do this part
|
||||
string drivePath = driveLetter + ":\\";
|
||||
if (!Directory.Exists(drivePath))
|
||||
return null;
|
||||
|
||||
// If we can't find PARAM.SFO, we don't have a PlayStation 3 disc
|
||||
string paramSfoPath = Path.Combine(drivePath, "PS3_GAME", "PARAM.SFO");
|
||||
if (!File.Exists(paramSfoPath))
|
||||
return null;
|
||||
|
||||
// Let's try reading PARAM.SFO to find the serial at the end of the file
|
||||
try
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(File.OpenRead(paramSfoPath)))
|
||||
{
|
||||
br.BaseStream.Seek(-0x18, SeekOrigin.End);
|
||||
return new string(br.ReadChars(9));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error was
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the version from a PlayStation 3 disc, if possible
|
||||
/// </summary>
|
||||
/// <param name="driveLetter">Drive letter to use to check</param>
|
||||
/// <returns>Game version if possible, null on error</returns>
|
||||
protected static string GetPlayStation3Version(char? driveLetter)
|
||||
{
|
||||
// If there's no drive letter, we can't do this part
|
||||
if (driveLetter == null)
|
||||
return null;
|
||||
|
||||
// If the folder no longer exists, we can't do this part
|
||||
string drivePath = driveLetter + ":\\";
|
||||
if (!Directory.Exists(drivePath))
|
||||
return null;
|
||||
|
||||
// If we can't find PARAM.SFO, we don't have a PlayStation 3 disc
|
||||
string paramSfoPath = Path.Combine(drivePath, "PS3_GAME", "PARAM.SFO");
|
||||
if (!File.Exists(paramSfoPath))
|
||||
return null;
|
||||
|
||||
// Let's try reading PARAM.SFO to find the version at the end of the file
|
||||
try
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(File.OpenRead(paramSfoPath)))
|
||||
{
|
||||
br.BaseStream.Seek(-0x08, SeekOrigin.End);
|
||||
return new string(br.ReadChars(5));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error was
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the internal serial from a PlayStation 4 disc, if possible
|
||||
/// </summary>
|
||||
/// <param name="driveLetter">Drive letter to use to check</param>
|
||||
/// <returns>Internal disc serial if possible, null on error</returns>
|
||||
protected static string GetPlayStation4Serial(char? driveLetter)
|
||||
{
|
||||
// If there's no drive letter, we can't do this part
|
||||
if (driveLetter == null)
|
||||
return null;
|
||||
|
||||
// If the folder no longer exists, we can't do this part
|
||||
string drivePath = driveLetter + ":\\";
|
||||
if (!Directory.Exists(drivePath))
|
||||
return null;
|
||||
|
||||
// If we can't find param.sfo, we don't have a PlayStation 4 disc
|
||||
string paramSfoPath = Path.Combine(drivePath, "bd", "param.sfo");
|
||||
if (!File.Exists(paramSfoPath))
|
||||
return null;
|
||||
|
||||
// Let's try reading param.sfo to find the serial at the end of the file
|
||||
try
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(File.OpenRead(paramSfoPath)))
|
||||
{
|
||||
br.BaseStream.Seek(-0x14, SeekOrigin.End);
|
||||
return new string(br.ReadChars(9));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error was
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the version from a PlayStation 4 disc, if possible
|
||||
/// </summary>
|
||||
@@ -1336,6 +1718,43 @@ namespace MPF.Data
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the internal serial from a PlayStation 5 disc, if possible
|
||||
/// </summary>
|
||||
/// <param name="driveLetter">Drive letter to use to check</param>
|
||||
/// <returns>Internal disc serial if possible, null on error</returns>
|
||||
protected static string GetPlayStation5Serial(char? driveLetter)
|
||||
{
|
||||
// If there's no drive letter, we can't do this part
|
||||
if (driveLetter == null)
|
||||
return null;
|
||||
|
||||
// If the folder no longer exists, we can't do this part
|
||||
string drivePath = driveLetter + ":\\";
|
||||
if (!Directory.Exists(drivePath))
|
||||
return null;
|
||||
|
||||
// If we can't find param.json, we don't have a PlayStation 5 disc
|
||||
string paramJsonPath = Path.Combine(drivePath, "bd", "param.json");
|
||||
if (!File.Exists(paramJsonPath))
|
||||
return null;
|
||||
|
||||
// Let's try reading param.json to find the serial in the unencrypted JSON
|
||||
try
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(File.OpenRead(paramJsonPath)))
|
||||
{
|
||||
br.BaseStream.Seek(0x82E, SeekOrigin.Begin);
|
||||
return new string(br.ReadChars(9));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error was
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the version from a PlayStation 5 disc, if possible
|
||||
/// </summary>
|
||||
@@ -1382,18 +1801,14 @@ namespace MPF.Data
|
||||
/// </summary>
|
||||
/// <param name="region">String representing the category</param>
|
||||
/// <returns>Category, if possible</returns>
|
||||
protected static RedumpDiscCategory? GetUMDCategory(string category)
|
||||
protected static DiscCategory? GetUMDCategory(string category)
|
||||
{
|
||||
switch (category)
|
||||
{
|
||||
case "GAME":
|
||||
return RedumpDiscCategory.Games;
|
||||
case "VIDEO":
|
||||
return RedumpDiscCategory.Video;
|
||||
case "AUDIO":
|
||||
return RedumpDiscCategory.Audio;
|
||||
default:
|
||||
return null;
|
||||
case "GAME": return DiscCategory.Games;
|
||||
case "VIDEO": return DiscCategory.Video;
|
||||
case "AUDIO": return DiscCategory.Audio;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1406,7 +1821,7 @@ namespace MPF.Data
|
||||
/// </summary>
|
||||
/// <param name="serial">PlayStation serial code</param>
|
||||
/// <returns>Region mapped from name, if possible</returns>
|
||||
protected static RedumpRegion? GetPlayStationRegion(string serial)
|
||||
protected static Region? GetPlayStationRegion(string serial)
|
||||
{
|
||||
// Standardized "S" serials
|
||||
if (serial.StartsWith("S"))
|
||||
@@ -1415,26 +1830,19 @@ namespace MPF.Data
|
||||
// char secondRegion = serial[3];
|
||||
switch (serial[2])
|
||||
{
|
||||
case 'A':
|
||||
return RedumpRegion.Asia;
|
||||
case 'C':
|
||||
return RedumpRegion.China;
|
||||
case 'E':
|
||||
return RedumpRegion.Europe;
|
||||
case 'J':
|
||||
return RedumpRegion.JapanKorea;
|
||||
case 'K':
|
||||
return RedumpRegion.Korea;
|
||||
case 'P':
|
||||
return RedumpRegion.Japan;
|
||||
case 'U':
|
||||
return RedumpRegion.USA;
|
||||
case 'A': return Region.Asia;
|
||||
case 'C': return Region.China;
|
||||
case 'E': return Region.Europe;
|
||||
case 'J': return Region.JapanKorea;
|
||||
case 'K': return Region.SouthKorea;
|
||||
case 'P': return Region.Japan;
|
||||
case 'U': return Region.UnitedStatesOfAmerica;
|
||||
}
|
||||
}
|
||||
|
||||
// Japan-only special serial
|
||||
else if (serial.StartsWith("PAPX"))
|
||||
return RedumpRegion.Japan;
|
||||
return Region.Japan;
|
||||
|
||||
// Region appears entirely random
|
||||
else if (serial.StartsWith("PABX"))
|
||||
@@ -1442,47 +1850,19 @@ namespace MPF.Data
|
||||
|
||||
// Japan-only special serial
|
||||
else if (serial.StartsWith("PCBX"))
|
||||
return RedumpRegion.Japan;
|
||||
return Region.Japan;
|
||||
|
||||
// Single disc known, Japan
|
||||
else if (serial.StartsWith("PDBX"))
|
||||
return RedumpRegion.Japan;
|
||||
return Region.Japan;
|
||||
|
||||
// Single disc known, Europe
|
||||
else if (serial.StartsWith("PEBX"))
|
||||
return RedumpRegion.Europe;
|
||||
return Region.Europe;
|
||||
|
||||
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>
|
||||
protected static RedumpRegion? GetXgdRegion(char region)
|
||||
{
|
||||
switch (region)
|
||||
{
|
||||
case 'W':
|
||||
return RedumpRegion.World;
|
||||
case 'A':
|
||||
return RedumpRegion.USA;
|
||||
case 'J':
|
||||
return RedumpRegion.JapanAsia;
|
||||
case 'E':
|
||||
return RedumpRegion.Europe;
|
||||
case 'K':
|
||||
return RedumpRegion.USAJapan;
|
||||
case 'L':
|
||||
return RedumpRegion.USAEurope;
|
||||
case 'H':
|
||||
return RedumpRegion.JapanEurope;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,11 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using MPF.Data;
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Data;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.CleanRip
|
||||
namespace MPF.Modules.CleanRip
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic set of CleanRip parameters
|
||||
@@ -22,7 +24,7 @@ namespace MPF.CleanRip
|
||||
public Parameters(string parameters) : base(parameters) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
public Parameters(RedumpSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
: base(system, type, driveLetter, filename, driveSpeed, options)
|
||||
{
|
||||
}
|
||||
@@ -49,19 +51,22 @@ namespace MPF.CleanRip
|
||||
break;
|
||||
|
||||
default:
|
||||
return (false, missingFiles);
|
||||
missingFiles.Add("Media and system combination not supported for CleanRip");
|
||||
break;
|
||||
}
|
||||
|
||||
return (!missingFiles.Any(), missingFiles);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive, bool includeArtifacts)
|
||||
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive drive, bool includeArtifacts)
|
||||
{
|
||||
info.TracksAndWriteOffsets.ClrMameProData = GetCleanripDatfile(basePath + ".iso", basePath + "-dumpinfo.txt");
|
||||
// TODO: Determine if there's a CleanRip version anywhere
|
||||
info.DumpingInfo.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
|
||||
Datafile datafile = GenerateCleanripDatafile(basePath + ".iso", basePath + "-dumpinfo.txt");
|
||||
|
||||
// Get the individual hash data, as per internal
|
||||
if (GetISOHashValues(info.TracksAndWriteOffsets.ClrMameProData, out long size, out string crc32, out string md5, out string sha1))
|
||||
if (GetISOHashValues(datafile, out long size, out string crc32, out string md5, out string sha1))
|
||||
{
|
||||
info.SizeAndChecksums.Size = size;
|
||||
info.SizeAndChecksums.CRC32 = crc32;
|
||||
@@ -82,10 +87,11 @@ namespace MPF.CleanRip
|
||||
if (File.Exists(basePath + ".bca"))
|
||||
info.Extras.BCA = GetBCA(basePath + ".bca");
|
||||
|
||||
if (GetGameCubeWiiInformation(basePath + "-dumpinfo.txt", out RedumpRegion? gcRegion, out string gcVersion))
|
||||
if (GetGameCubeWiiInformation(basePath + "-dumpinfo.txt", out Region? gcRegion, out string gcVersion, out string gcName))
|
||||
{
|
||||
info.CommonDiscInfo.Region = gcRegion ?? info.CommonDiscInfo.Region;
|
||||
info.VersionAndEditions.Version = gcVersion ?? info.VersionAndEditions.Version;
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalName] = gcName ?? string.Empty;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -125,6 +131,65 @@ namespace MPF.CleanRip
|
||||
|
||||
#region Information Extraction Methods
|
||||
|
||||
/// <summary>
|
||||
/// Get a formatted datfile from the cleanrip output, if possible
|
||||
/// </summary>
|
||||
/// <param name="iso">Path to ISO file</param>
|
||||
/// <param name="dumpinfo">Path to discinfo file</param>
|
||||
/// <returns></returns>
|
||||
private static Datafile GenerateCleanripDatafile(string iso, string dumpinfo)
|
||||
{
|
||||
// If the file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(dumpinfo))
|
||||
return null;
|
||||
|
||||
using (StreamReader sr = File.OpenText(dumpinfo))
|
||||
{
|
||||
long size = new FileInfo(iso).Length;
|
||||
string crc = string.Empty;
|
||||
string md5 = string.Empty;
|
||||
string sha1 = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
// Make sure this file is a dumpinfo
|
||||
if (!sr.ReadLine().Contains("--File Generated by CleanRip"))
|
||||
return null;
|
||||
|
||||
// Read all lines and gather dat information
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
string line = sr.ReadLine().Trim();
|
||||
if (line.StartsWith("CRC32"))
|
||||
crc = line.Substring(7).ToLowerInvariant();
|
||||
else if (line.StartsWith("MD5"))
|
||||
md5 = line.Substring(5);
|
||||
else if (line.StartsWith("SHA-1"))
|
||||
sha1 = line.Substring(7);
|
||||
}
|
||||
|
||||
return new Datafile
|
||||
{
|
||||
Games = new Game[]
|
||||
{
|
||||
new Game
|
||||
{
|
||||
Roms = new Rom[]
|
||||
{
|
||||
new Rom { Name = Path.GetFileName(iso), Size = size.ToString(), Crc = crc, Md5 = md5, Sha1 = sha1 },
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the exception is right now
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the hex contents of the BCA file
|
||||
/// </summary>
|
||||
@@ -202,10 +267,11 @@ namespace MPF.CleanRip
|
||||
/// <param name="dumpinfo">Path to discinfo file</param>
|
||||
/// <param name="region">Output region, if possible</param>
|
||||
/// <param name="version">Output internal version of the game</param>
|
||||
/// <param name="name">Output internal name of the game</param>
|
||||
/// <returns></returns>
|
||||
private static bool GetGameCubeWiiInformation(string dumpinfo, out RedumpRegion? region, out string version)
|
||||
private static bool GetGameCubeWiiInformation(string dumpinfo, out Region? region, out string version, out string name)
|
||||
{
|
||||
region = null; version = null;
|
||||
region = null; version = null; name = null;
|
||||
|
||||
// If the file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(dumpinfo))
|
||||
@@ -225,11 +291,15 @@ namespace MPF.CleanRip
|
||||
string line = sr.ReadLine().Trim();
|
||||
if (line.StartsWith("Version"))
|
||||
{
|
||||
version = line.Substring(9);
|
||||
version = line.Substring("Version: ".Length);
|
||||
}
|
||||
else if (line.StartsWith("Internal Name"))
|
||||
{
|
||||
name = line.Substring("Internal Name: ".Length);
|
||||
}
|
||||
else if (line.StartsWith("Filename"))
|
||||
{
|
||||
string serial = line.Substring(10);
|
||||
string serial = line.Substring("Filename: ".Length);
|
||||
|
||||
// char gameType = serial[0];
|
||||
// string gameid = serial[1] + serial[2];
|
||||
@@ -238,49 +308,49 @@ namespace MPF.CleanRip
|
||||
switch (serial[3])
|
||||
{
|
||||
case 'A':
|
||||
region = RedumpRegion.World;
|
||||
region = Region.World;
|
||||
break;
|
||||
case 'D':
|
||||
region = RedumpRegion.Germany;
|
||||
region = Region.Germany;
|
||||
break;
|
||||
case 'E':
|
||||
region = RedumpRegion.USA;
|
||||
region = Region.UnitedStatesOfAmerica;
|
||||
break;
|
||||
case 'F':
|
||||
region = RedumpRegion.France;
|
||||
region = Region.France;
|
||||
break;
|
||||
case 'I':
|
||||
region = RedumpRegion.Italy;
|
||||
region = Region.Italy;
|
||||
break;
|
||||
case 'J':
|
||||
region = RedumpRegion.Japan;
|
||||
region = Region.Japan;
|
||||
break;
|
||||
case 'K':
|
||||
region = RedumpRegion.Korea;
|
||||
region = Region.SouthKorea;
|
||||
break;
|
||||
case 'L':
|
||||
region = RedumpRegion.Europe; // Japanese import to Europe
|
||||
region = Region.Europe; // Japanese import to Europe
|
||||
break;
|
||||
case 'M':
|
||||
region = RedumpRegion.Europe; // American import to Europe
|
||||
region = Region.Europe; // American import to Europe
|
||||
break;
|
||||
case 'N':
|
||||
region = RedumpRegion.USA; // Japanese import to USA
|
||||
region = Region.UnitedStatesOfAmerica; // Japanese import to USA
|
||||
break;
|
||||
case 'P':
|
||||
region = RedumpRegion.Europe;
|
||||
region = Region.Europe;
|
||||
break;
|
||||
case 'R':
|
||||
region = RedumpRegion.Russia;
|
||||
region = Region.RussianFederation;
|
||||
break;
|
||||
case 'S':
|
||||
region = RedumpRegion.Spain;
|
||||
region = Region.Spain;
|
||||
break;
|
||||
case 'Q':
|
||||
region = RedumpRegion.Korea; // Korea with Japanese language
|
||||
region = Region.SouthKorea; // Korea with Japanese language
|
||||
break;
|
||||
case 'T':
|
||||
region = RedumpRegion.Korea; // Korea with English language
|
||||
region = Region.SouthKorea; // Korea with English language
|
||||
break;
|
||||
case 'X':
|
||||
region = null; // Not a real region code
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace MPF.DD
|
||||
namespace MPF.Modules.DD
|
||||
{
|
||||
/// <summary>
|
||||
/// Top-level commands for DD
|
||||
@@ -1,6 +1,6 @@
|
||||
using MPF.Data;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.DD
|
||||
namespace MPF.Modules.DD
|
||||
{
|
||||
public static class Converters
|
||||
{
|
||||
@@ -2,9 +2,11 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using MPF.Data;
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Data;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.DD
|
||||
namespace MPF.Modules.DD
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic set of DD parameters
|
||||
@@ -59,7 +61,7 @@ namespace MPF.DD
|
||||
public Parameters(string parameters) : base(parameters) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
public Parameters(RedumpSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
: base(system, type, driveLetter, filename, driveSpeed, options)
|
||||
{
|
||||
}
|
||||
@@ -74,11 +76,14 @@ namespace MPF.DD
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive, bool includeArtifacts)
|
||||
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive drive, bool includeArtifacts)
|
||||
{
|
||||
// TODO: Fill in submission info specifics for DD
|
||||
string outputDirectory = Path.GetDirectoryName(basePath);
|
||||
|
||||
// TODO: Determine if there's a DD version anywhere
|
||||
info.DumpingInfo.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
|
||||
|
||||
switch (this.Type)
|
||||
{
|
||||
// Determine type-specific differences
|
||||
@@ -86,45 +91,54 @@ namespace MPF.DD
|
||||
|
||||
switch (this.System)
|
||||
{
|
||||
case KnownSystem.KonamiPython2:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string pythonTwoSerial, out RedumpRegion? pythonTwoRegion, out string pythonTwoDate))
|
||||
case RedumpSystem.KonamiPython2:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string pythonTwoSerial, out Region? pythonTwoRegion, out string pythonTwoDate))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"Internal Disc Serial: {pythonTwoSerial}\n";
|
||||
// Ensure internal serial is pulled from local data
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = pythonTwoSerial ?? string.Empty;
|
||||
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? pythonTwoRegion;
|
||||
info.CommonDiscInfo.EXEDateBuildDate = pythonTwoDate;
|
||||
}
|
||||
|
||||
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? "";
|
||||
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? string.Empty;
|
||||
break;
|
||||
|
||||
case KnownSystem.SonyPlayStation:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationSerial, out RedumpRegion? playstationRegion, out string playstationDate))
|
||||
case RedumpSystem.SonyPlayStation:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationSerial, out Region? playstationRegion, out string playstationDate))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationSerial}\n";
|
||||
// Ensure internal serial is pulled from local data
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = playstationSerial ?? string.Empty;
|
||||
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationRegion;
|
||||
info.CommonDiscInfo.EXEDateBuildDate = playstationDate;
|
||||
}
|
||||
|
||||
info.CopyProtection.AntiModchip = GetPlayStationAntiModchipDetected(drive?.Letter) ? YesNo.Yes : YesNo.No;
|
||||
break;
|
||||
|
||||
case KnownSystem.SonyPlayStation2:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationTwoSerial, out RedumpRegion? playstationTwoRegion, out string playstationTwoDate))
|
||||
case RedumpSystem.SonyPlayStation2:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationTwoSerial, out Region? playstationTwoRegion, out string playstationTwoDate))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationTwoSerial}\n";
|
||||
// Ensure internal serial is pulled from local data
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = playstationTwoSerial ?? string.Empty;
|
||||
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationTwoRegion;
|
||||
info.CommonDiscInfo.EXEDateBuildDate = playstationTwoDate;
|
||||
}
|
||||
|
||||
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? "";
|
||||
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? string.Empty;
|
||||
break;
|
||||
|
||||
case KnownSystem.SonyPlayStation4:
|
||||
info.VersionAndEditions.Version = GetPlayStation4Version(drive?.Letter) ?? "";
|
||||
case RedumpSystem.SonyPlayStation3:
|
||||
info.VersionAndEditions.Version = GetPlayStation3Version(drive?.Letter) ?? string.Empty;
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = GetPlayStation3Serial(drive?.Letter) ?? string.Empty;
|
||||
break;
|
||||
|
||||
case KnownSystem.SonyPlayStation5:
|
||||
info.VersionAndEditions.Version = GetPlayStation5Version(drive?.Letter) ?? "";
|
||||
case RedumpSystem.SonyPlayStation4:
|
||||
info.VersionAndEditions.Version = GetPlayStation4Version(drive?.Letter) ?? string.Empty;
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = GetPlayStation4Serial(drive?.Letter) ?? string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.SonyPlayStation5:
|
||||
info.VersionAndEditions.Version = GetPlayStation5Version(drive?.Letter) ?? string.Empty;
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = GetPlayStation5Serial(drive?.Letter) ?? string.Empty;
|
||||
break;
|
||||
}
|
||||
}
|
||||
73
MPF.Modules/Datafile.cs
Normal file
73
MPF.Modules/Datafile.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace MPF.Modules
|
||||
{
|
||||
[XmlRoot("datafile")]
|
||||
public class Datafile
|
||||
{
|
||||
[XmlElement("header")]
|
||||
public Header Header;
|
||||
|
||||
[XmlElement("game")]
|
||||
public Game[] Games;
|
||||
}
|
||||
|
||||
public class Header
|
||||
{
|
||||
[XmlElement("name")]
|
||||
public string Name;
|
||||
|
||||
[XmlElement("description")]
|
||||
public string Description;
|
||||
|
||||
[XmlElement("version")]
|
||||
public string Version;
|
||||
|
||||
[XmlElement("date")]
|
||||
public string Date;
|
||||
|
||||
[XmlElement("author")]
|
||||
public string Author;
|
||||
|
||||
[XmlElement("homepage")]
|
||||
public string Homepage;
|
||||
|
||||
[XmlElement("url")]
|
||||
public string Url;
|
||||
}
|
||||
|
||||
public class Game
|
||||
{
|
||||
[XmlAttribute("name")]
|
||||
public string Name;
|
||||
|
||||
[XmlElement("category")]
|
||||
public string Category;
|
||||
|
||||
[XmlElement("description")]
|
||||
public string Description;
|
||||
|
||||
[XmlElement("rom")]
|
||||
public Rom[] Roms;
|
||||
}
|
||||
|
||||
public class Rom
|
||||
{
|
||||
[XmlAttribute("name")]
|
||||
public string Name;
|
||||
|
||||
[XmlAttribute("size")]
|
||||
public string Size;
|
||||
|
||||
[XmlAttribute("crc")]
|
||||
public string Crc;
|
||||
|
||||
[XmlAttribute("md5")]
|
||||
public string Md5;
|
||||
|
||||
[XmlAttribute("sha1")]
|
||||
public string Sha1;
|
||||
|
||||
// TODO: Add extended hashes here
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace MPF.DiscImageCreator
|
||||
namespace MPF.Modules.DiscImageCreator
|
||||
{
|
||||
/// <summary>
|
||||
/// Top-level commands for DiscImageCreator
|
||||
@@ -26,6 +26,7 @@ namespace MPF.DiscImageCreator
|
||||
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";
|
||||
@@ -44,12 +45,13 @@ namespace MPF.DiscImageCreator
|
||||
public const string C2Opcode = "/c2";
|
||||
public const string CopyrightManagementInformation = "/c";
|
||||
public const string D8Opcode = "/d8";
|
||||
public const string DatExpand = "/d";
|
||||
public const string DisableBeep = "/q";
|
||||
public const string DVDReread = "/rr";
|
||||
public const string ExtractMicroSoftCabFile = "/mscf";
|
||||
public const string Fix = "/fix";
|
||||
public const string ForceUnitAccess = "/f";
|
||||
public const string MultiSectorRead = "/mr";
|
||||
public const string MultiSession = "/ms";
|
||||
public const string NoFixSubP = "/np";
|
||||
public const string NoFixSubQ = "/nq";
|
||||
public const string NoFixSubQLibCrypt = "/nl";
|
||||
@@ -57,6 +59,7 @@ namespace MPF.DiscImageCreator
|
||||
public const string NoFixSubQSecuROM = "/ns";
|
||||
public const string NoSkipSS = "/nss";
|
||||
public const string PadSector = "/ps";
|
||||
public const string Range = "/ra";
|
||||
public const string Raw = "/raw";
|
||||
public const string Resume = "/re";
|
||||
public const string Reverse = "/r";
|
||||
@@ -1,6 +1,6 @@
|
||||
using MPF.Data;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.DiscImageCreator
|
||||
namespace MPF.Modules.DiscImageCreator
|
||||
{
|
||||
public static class Converters
|
||||
{
|
||||
@@ -10,33 +10,33 @@ namespace MPF.DiscImageCreator
|
||||
/// Get the most common known system for a given MediaType
|
||||
/// </summary>
|
||||
/// <param name="baseCommand">Command value to check</param>
|
||||
/// <returns>KnownSystem if possible, null on error</returns>
|
||||
public static KnownSystem? ToKnownSystem(string baseCommand)
|
||||
/// <returns>RedumpSystem if possible, null on error</returns>
|
||||
public static RedumpSystem? ToRedumpSystem(string baseCommand)
|
||||
{
|
||||
switch (baseCommand)
|
||||
{
|
||||
case CommandStrings.Audio:
|
||||
return KnownSystem.AudioCD;
|
||||
return RedumpSystem.AudioCD;
|
||||
case CommandStrings.CompactDisc:
|
||||
case CommandStrings.Data:
|
||||
case CommandStrings.DigitalVideoDisc:
|
||||
case CommandStrings.Disk:
|
||||
case CommandStrings.Floppy:
|
||||
case CommandStrings.Tape:
|
||||
return KnownSystem.IBMPCCompatible;
|
||||
return RedumpSystem.IBMPCcompatible;
|
||||
case CommandStrings.GDROM:
|
||||
case CommandStrings.Swap:
|
||||
return KnownSystem.SegaDreamcast;
|
||||
return RedumpSystem.SegaDreamcast;
|
||||
case CommandStrings.BluRay:
|
||||
return KnownSystem.SonyPlayStation3;
|
||||
return RedumpSystem.SonyPlayStation3;
|
||||
case CommandStrings.SACD:
|
||||
return KnownSystem.SuperAudioCD;
|
||||
return RedumpSystem.SuperAudioCD;
|
||||
case CommandStrings.XBOX:
|
||||
case CommandStrings.XBOXSwap:
|
||||
return KnownSystem.MicrosoftXBOX;
|
||||
return RedumpSystem.MicrosoftXbox;
|
||||
case CommandStrings.XGD2Swap:
|
||||
case CommandStrings.XGD3Swap:
|
||||
return KnownSystem.MicrosoftXBOX360;
|
||||
return RedumpSystem.MicrosoftXbox360;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
38
MPF.Modules/MPF.Modules.csproj
Normal file
38
MPF.Modules/MPF.Modules.csproj
Normal file
@@ -0,0 +1,38 @@
|
||||
<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.2</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>
|
||||
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
|
||||
<ProjectReference Include="..\MPF.CueSheets\MPF.CueSheets.csproj" />
|
||||
<ProjectReference Include="..\RedumpLib\RedumpLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Memory" Version="4.5.5" />
|
||||
<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>
|
||||
72
MPF.Modules/Redumper/Constants.cs
Normal file
72
MPF.Modules/Redumper/Constants.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
namespace MPF.Modules.Redumper
|
||||
{
|
||||
/// <summary>
|
||||
/// Top-level commands for Redumper
|
||||
/// </summary>
|
||||
public static class CommandStrings
|
||||
{
|
||||
public const string NONE = "";
|
||||
public const string CD = "cd";
|
||||
public const string DVD = "dvd"; // Synonym for CD
|
||||
public const string BluRay = "bd"; // Synonym for CD
|
||||
public const string SACD = "sacd"; // Synonym for CD
|
||||
public const string 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
|
||||
public const string HelpLong = "--help";
|
||||
public const string HelpShort = "-h";
|
||||
public const string Verbose = "--verbose";
|
||||
public const string Debug = "--debug";
|
||||
public const string Drive = "--drive";
|
||||
public const string Speed = "--speed";
|
||||
public const string Retries = "--retries";
|
||||
public const string ImagePath = "--image-path";
|
||||
public const string ImageName = "--image-name";
|
||||
public const string Overwrite = "--overwrite";
|
||||
|
||||
// Drive Configuration
|
||||
public const string DriveType = "--drive-type";
|
||||
public const string DriveReadOffset = "--drive-read-offset";
|
||||
public const string DriveC2Shift = "--drive-c2-shift";
|
||||
public const string DrivePregapStart = "--drive-pregap-start";
|
||||
public const string DriveReadMethod = "--drive-read-method";
|
||||
public const string DriveSectorOrder = "--drive-sector-order";
|
||||
|
||||
// Drive Specific
|
||||
public const string PlextorLeadinSkip = "--plextor-leadin-skip";
|
||||
public const string PlextorLeadinRetries = "--plextor-leadin-retries";
|
||||
public const string AsusSkipLeadout = "--asus-skip-leadout";
|
||||
|
||||
// Offset
|
||||
public const string ForceOffset = "--force-offset";
|
||||
public const string AudioSilenceThreshold = "--audio-silence-threshold";
|
||||
public const string CorrectOffsetShift = "--correct-offset-shift";
|
||||
public const string OffsetShiftRelocate = "--offset-shift-relocate";
|
||||
|
||||
// Split
|
||||
public const string ForceSplit = "--force-split";
|
||||
public const string LeaveUnchanged = "--leave-unchanged";
|
||||
public const string ForceQTOC = "--force-qtoc";
|
||||
public const string SkipFill = "--skip-fill";
|
||||
public const string ISO9660Trim = "--iso9660-trim";
|
||||
|
||||
// Miscellaneous
|
||||
public const string LBAStart = "--lba-start";
|
||||
public const string LBAEnd = "--lba-end";
|
||||
public const string RefineSubchannel = "--refine-subchannel";
|
||||
public const string Skip = "--skip";
|
||||
public const string DumpReadSize = "--dump-read-size";
|
||||
}
|
||||
}
|
||||
32
MPF.Modules/Redumper/Converters.cs
Normal file
32
MPF.Modules/Redumper/Converters.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.Modules.Redumper
|
||||
{
|
||||
public static class Converters
|
||||
{
|
||||
#region Cross-enumeration conversions
|
||||
|
||||
/// <summary>
|
||||
/// Get the default extension for a given disc type
|
||||
/// </summary>
|
||||
/// <param name="type">MediaType value to check</param>
|
||||
/// <returns>Valid extension (with leading '.'), null on error</returns>
|
||||
public static string Extension(MediaType? type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
return ".bin";
|
||||
case MediaType.DVD:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.BluRay:
|
||||
return ".iso";
|
||||
case MediaType.NONE:
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
2034
MPF.Modules/Redumper/Parameters.cs
Normal file
2034
MPF.Modules/Redumper/Parameters.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,9 +2,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MPF.Data;
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Data;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.UmdImageCreator
|
||||
namespace MPF.Modules.UmdImageCreator
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic set of UmdImageCreator parameters
|
||||
@@ -22,7 +24,7 @@ namespace MPF.UmdImageCreator
|
||||
public Parameters(string parameters) : base(parameters) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
public Parameters(RedumpSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
: base(system, type, driveLetter, filename, driveSpeed, options)
|
||||
{
|
||||
}
|
||||
@@ -40,6 +42,8 @@ namespace MPF.UmdImageCreator
|
||||
{
|
||||
if (!File.Exists($"{basePath}_disc.txt"))
|
||||
missingFiles.Add($"{basePath}_disc.txt");
|
||||
if (!File.Exists($"{basePath}_drive.txt"))
|
||||
missingFiles.Add($"{basePath}_drive.txt");
|
||||
if (!File.Exists($"{basePath}_mainError.txt"))
|
||||
missingFiles.Add($"{basePath}_mainError.txt");
|
||||
if (!File.Exists($"{basePath}_mainInfo.txt"))
|
||||
@@ -51,20 +55,24 @@ namespace MPF.UmdImageCreator
|
||||
break;
|
||||
|
||||
default:
|
||||
return (false, missingFiles);
|
||||
missingFiles.Add("Media and system combination not supported for UmdImageCreator");
|
||||
break;
|
||||
}
|
||||
|
||||
return (!missingFiles.Any(), missingFiles);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive, bool includeArtifacts)
|
||||
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive drive, bool includeArtifacts)
|
||||
{
|
||||
// TODO: Determine if there's a UMDImageCreator version anywhere
|
||||
info.DumpingInfo.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
|
||||
|
||||
// Extract info based generically on MediaType
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.UMD:
|
||||
info.Extras.PVD = GetPVD(basePath + "_mainInfo.txt") ?? "";
|
||||
info.Extras.PVD = GetPVD(basePath + "_mainInfo.txt") ?? string.Empty;
|
||||
|
||||
if (GetFileHashes(basePath + ".iso", out long filesize, out string crc32, out string md5, out string sha1))
|
||||
{
|
||||
@@ -74,11 +82,11 @@ namespace MPF.UmdImageCreator
|
||||
info.SizeAndChecksums.SHA1 = sha1;
|
||||
}
|
||||
|
||||
if (GetUMDAuxInfo(basePath + "_disc.txt", out string title, out RedumpDiscCategory? umdcat, out string umdversion, out string umdlayer, out long umdsize))
|
||||
if (GetUMDAuxInfo(basePath + "_disc.txt", out string title, out DiscCategory? umdcat, out string umdversion, out string umdlayer, out long umdsize))
|
||||
{
|
||||
info.CommonDiscInfo.Title = title ?? "";
|
||||
info.CommonDiscInfo.Category = umdcat ?? RedumpDiscCategory.Games;
|
||||
info.VersionAndEditions.Version = umdversion ?? "";
|
||||
info.CommonDiscInfo.Title = title ?? string.Empty;
|
||||
info.CommonDiscInfo.Category = umdcat ?? DiscCategory.Games;
|
||||
info.VersionAndEditions.Version = umdversion ?? string.Empty;
|
||||
info.SizeAndChecksums.Size = umdsize;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(umdlayer))
|
||||
@@ -93,6 +101,8 @@ namespace MPF.UmdImageCreator
|
||||
{
|
||||
if (File.Exists(basePath + "_disc.txt"))
|
||||
info.Artifacts["disc"] = GetBase64(GetFullFile(basePath + "_disc.txt"));
|
||||
if (File.Exists(basePath + "_drive.txt"))
|
||||
info.Artifacts["drive"] = GetBase64(GetFullFile(basePath + "_drive.txt"));
|
||||
if (File.Exists(basePath + "_mainError.txt"))
|
||||
info.Artifacts["mainError"] = GetBase64(GetFullFile(basePath + "_mainError.txt"));
|
||||
if (File.Exists(basePath + "_mainInfo.txt"))
|
||||
@@ -111,6 +121,8 @@ namespace MPF.UmdImageCreator
|
||||
case MediaType.UMD:
|
||||
if (File.Exists($"{basePath}_disc.txt"))
|
||||
logFiles.Add($"{basePath}_disc.txt");
|
||||
if (File.Exists($"{basePath}_drive.txt"))
|
||||
logFiles.Add($"{basePath}_drive.txt");
|
||||
if (File.Exists($"{basePath}_mainError.txt"))
|
||||
logFiles.Add($"{basePath}_mainError.txt");
|
||||
if (File.Exists($"{basePath}_mainInfo.txt"))
|
||||
@@ -169,7 +181,7 @@ namespace MPF.UmdImageCreator
|
||||
/// </summary>
|
||||
/// <param name="disc">_disc.txt file location</param>
|
||||
/// <returns>True on successful extraction of info, false otherwise</returns>
|
||||
private static bool GetUMDAuxInfo(string disc, out string title, out RedumpDiscCategory? umdcat, out string umdversion, out string umdlayer, out long umdsize)
|
||||
private static bool GetUMDAuxInfo(string disc, out string title, out DiscCategory? umdcat, out string umdversion, out string umdlayer, out long umdsize)
|
||||
{
|
||||
title = null; umdcat = null; umdversion = null; umdlayer = null; umdsize = -1;
|
||||
|
||||
168
MPF.Test/Core/Converters/EnumConverterTests.cs
Normal file
168
MPF.Test/Core/Converters/EnumConverterTests.cs
Normal file
@@ -0,0 +1,168 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
#if NETFRAMEWORK
|
||||
using IMAPI2;
|
||||
#endif
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Core.Converters
|
||||
{
|
||||
public class EnumConverterTests
|
||||
{
|
||||
#region Cross-enumeration conversions
|
||||
|
||||
/// <summary>
|
||||
/// DiscType values that map to InternalDriveType
|
||||
/// </summary>
|
||||
private static readonly DriveType[] _mappableDriveTypes = new DriveType[]
|
||||
{
|
||||
DriveType.CDRom,
|
||||
DriveType.Fixed,
|
||||
DriveType.Removable,
|
||||
};
|
||||
|
||||
#if NETFRAMEWORK
|
||||
/// <summary>
|
||||
/// IMAPI_MEDIA_PHYSICAL_TYPE values that map to MediaType
|
||||
/// </summary>
|
||||
private static readonly IMAPI_MEDIA_PHYSICAL_TYPE[] _mappableImapiTypes = new IMAPI_MEDIA_PHYSICAL_TYPE[]
|
||||
{
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_UNKNOWN,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_CDROM,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_CDR,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_CDRW,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDROM,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDRAM,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDPLUSR,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDPLUSRW,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDPLUSR_DUALLAYER,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDDASHR,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDDASHRW,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDDASHR_DUALLAYER,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DISK,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDPLUSRW_DUALLAYER,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_HDDVDROM,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_HDDVDR,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_HDDVDRAM,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_BDROM,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_BDR,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_BDRE,
|
||||
};
|
||||
#endif
|
||||
|
||||
/// <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 = driveType.ToInternalDriveType();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
#if NETFRAMEWORK
|
||||
/// <summary>
|
||||
/// Check that every supported IMAPI_MEDIA_PHYSICAL_TYPE maps to an MediaType
|
||||
/// </summary>
|
||||
/// <param name="imapiType">IMAPI_MEDIA_PHYSICAL_TYPE value to check</param>
|
||||
/// <param name="expectNull">True to expect a null mapping, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateImapiTypeMappingTestData))]
|
||||
public void IMAPIToMediaTypeTest(IMAPI_MEDIA_PHYSICAL_TYPE imapiType, bool expectNull)
|
||||
{
|
||||
var actual = imapiType.IMAPIToMediaType();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <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(typeof(DriveType)))
|
||||
{
|
||||
if (_mappableDriveTypes.Contains(driveType))
|
||||
testData.Add(new object[] { driveType, false });
|
||||
else
|
||||
testData.Add(new object[] { driveType, true });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#if NETFRAMEWORK
|
||||
/// <summary>
|
||||
/// Generate a test set of IMAPI_MEDIA_PHYSICAL_TYPE values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of IMAPI_MEDIA_PHYSICAL_TYPE values</returns>
|
||||
public static List<object[]> GenerateImapiTypeMappingTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, false } };
|
||||
foreach (IMAPI_MEDIA_PHYSICAL_TYPE imapiType in Enum.GetValues(typeof(IMAPI_MEDIA_PHYSICAL_TYPE)))
|
||||
{
|
||||
if (_mappableImapiTypes.Contains(imapiType))
|
||||
testData.Add(new object[] { imapiType, false });
|
||||
else
|
||||
testData.Add(new object[] { imapiType, true });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region Convert to Long Name
|
||||
|
||||
// TODO: Maybe add a test for the generic "GetLongName" method
|
||||
|
||||
/// <summary>
|
||||
/// Check that every InternalProgram has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="internalProgram">InternalProgram value to check</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateInternalProgramTestData))]
|
||||
public void InternalProgramLongNameTest(InternalProgram? internalProgram)
|
||||
{
|
||||
string actual = internalProgram.LongName();
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of InternalProgram values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of InternalProgram values</returns>
|
||||
public static List<object[]> GenerateInternalProgramTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null } };
|
||||
foreach (InternalProgram? internalProgram in Enum.GetValues(typeof(InternalProgram)))
|
||||
{
|
||||
testData.Add(new object[] { internalProgram });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// TODO: Add from-string tests
|
||||
}
|
||||
}
|
||||
42
MPF.Test/Core/Data/ResultTests.cs
Normal file
42
MPF.Test/Core/Data/ResultTests.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using MPF.Core.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Core.Data
|
||||
{
|
||||
public class ResultTests
|
||||
{
|
||||
[Fact]
|
||||
public void EmptySuccessTest()
|
||||
{
|
||||
var actual = Result.Success();
|
||||
Assert.True(actual);
|
||||
Assert.Empty(actual.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CustomMessageSuccessTest()
|
||||
{
|
||||
string message = "Success!";
|
||||
var actual = Result.Success(message);
|
||||
Assert.True(actual);
|
||||
Assert.Equal(message, actual.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EmptyFailureTest()
|
||||
{
|
||||
var actual = Result.Failure();
|
||||
Assert.False(actual);
|
||||
Assert.Empty(actual.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CustomMessageFailureTest()
|
||||
{
|
||||
string message = "Failure!";
|
||||
var actual = Result.Failure(message);
|
||||
Assert.False(actual);
|
||||
Assert.Equal(message, actual.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
115
MPF.Test/Core/Data/XgdInfoTests.cs
Normal file
115
MPF.Test/Core/Data/XgdInfoTests.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using MPF.Core.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Core.Data
|
||||
{
|
||||
public class XgdInfoTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
[InlineData("1234567")]
|
||||
[InlineData("1234567\0")]
|
||||
[InlineData("123456789")]
|
||||
public void UnmatchedStringTests(string invalidString)
|
||||
{
|
||||
XgdInfo xgdInfo = new XgdInfo(invalidString);
|
||||
Assert.False(xgdInfo.Initialized);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("AV00100W", "AV", "001", "00", 'W')]
|
||||
[InlineData("AV00100W\0", "AV", "001", "00", 'W')]
|
||||
public void XGD1ValidTests(string validString, string publisher, string gameId, string version, char regionIdentifier)
|
||||
{
|
||||
XgdInfo xgdInfo = new XgdInfo(validString, validate: true);
|
||||
|
||||
Assert.True(xgdInfo.Initialized);
|
||||
Assert.Equal(publisher, xgdInfo.PublisherIdentifier);
|
||||
Assert.Equal(gameId, xgdInfo.GameID);
|
||||
Assert.Equal(version, xgdInfo.SKU);
|
||||
Assert.Equal(regionIdentifier, xgdInfo.RegionIdentifier);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
// Invalid publisher identifier
|
||||
[InlineData("ZZ000000")]
|
||||
[InlineData("ZZ000000\0")]
|
||||
// Invalid region identifier
|
||||
[InlineData("AV00000Z")]
|
||||
[InlineData("AV00000Z\0")]
|
||||
public void XGD1InvalidTests(string invalidString)
|
||||
{
|
||||
XgdInfo xgdInfo = new XgdInfo(invalidString, validate: true);
|
||||
Assert.False(xgdInfo.Initialized);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("AV200100W0F11", "AV", "001", "00", 'W', "0", 'F', "11", null)]
|
||||
[InlineData("AV200100W0F11\0", "AV", "001", "00", 'W', "0", 'F', "11", null)]
|
||||
[InlineData("AV200100W01F11", "AV", "001", "00", 'W', "01", 'F', "11", null)]
|
||||
[InlineData("AV200100W01F11\0", "AV", "001", "00", 'W', "01", 'F', "11", null)]
|
||||
[InlineData("AV200100W0F11DEADBEEF", "AV", "001", "00", 'W', "0", 'F', "11", "DEADBEEF")]
|
||||
[InlineData("AV200100W0F11DEADBEEF\0", "AV", "001", "00", 'W', "0", 'F', "11", "DEADBEEF")]
|
||||
[InlineData("AV200100W01F11DEADBEEF", "AV", "001", "00", 'W', "01", 'F', "11", "DEADBEEF")]
|
||||
[InlineData("AV200100W01F11DEADBEEF\0", "AV", "001", "00", 'W', "01", 'F', "11", "DEADBEEF")]
|
||||
public void XGD23ValidTests(string validString, string publisher, string gameId, string sku, char regionIdentifier, string baseVersion, char mediaSubtype, string discNumber, string cert)
|
||||
{
|
||||
XgdInfo xgdInfo = new XgdInfo(validString, validate: true);
|
||||
|
||||
Assert.True(xgdInfo.Initialized);
|
||||
Assert.Equal(publisher, xgdInfo.PublisherIdentifier);
|
||||
Assert.Equal('2', xgdInfo.PlatformIdentifier);
|
||||
Assert.Equal(gameId, xgdInfo.GameID);
|
||||
Assert.Equal(sku, xgdInfo.SKU);
|
||||
Assert.Equal(regionIdentifier, xgdInfo.RegionIdentifier);
|
||||
Assert.Equal(baseVersion, xgdInfo.BaseVersion);
|
||||
Assert.Equal(mediaSubtype, xgdInfo.MediaSubtypeIdentifier);
|
||||
Assert.Equal(discNumber, xgdInfo.DiscNumberIdentifier);
|
||||
Assert.Equal(cert, xgdInfo.CertificationSubmissionIdentifier);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
// Invalid publisher identifier
|
||||
[InlineData("ZZ00000000000")]
|
||||
[InlineData("ZZ00000000000\0")]
|
||||
[InlineData("ZZ000000000000")]
|
||||
[InlineData("ZZ000000000000\0")]
|
||||
[InlineData("ZZ0000000000000000000")]
|
||||
[InlineData("ZZ0000000000000000000\0")]
|
||||
[InlineData("ZZ00000000000000000000")]
|
||||
[InlineData("ZZ00000000000000000000\0")]
|
||||
// Invalid platform identifier
|
||||
[InlineData("AV90000000000")]
|
||||
[InlineData("AV90000000000\0")]
|
||||
[InlineData("AV900000000000")]
|
||||
[InlineData("AV900000000000\0")]
|
||||
[InlineData("AV9000000000000000000")]
|
||||
[InlineData("AV9000000000000000000\0")]
|
||||
[InlineData("AV90000000000000000000")]
|
||||
[InlineData("AV90000000000000000000\0")]
|
||||
// Invalid region identifier
|
||||
[InlineData("AV200000Z0000")]
|
||||
[InlineData("AV200000Z0000\0")]
|
||||
[InlineData("AV200000Z00000")]
|
||||
[InlineData("AV200000Z00000\0")]
|
||||
[InlineData("AV200000Z000000000000")]
|
||||
[InlineData("AV200000Z000000000000\0")]
|
||||
[InlineData("AV200000Z0000000000000")]
|
||||
[InlineData("AV200000Z0000000000000\0")]
|
||||
// Invalid media subtype identifier
|
||||
[InlineData("AV200000W0A00")]
|
||||
[InlineData("AV200000W0A00\0")]
|
||||
[InlineData("AV200000W00A00")]
|
||||
[InlineData("AV200000W00A00\0")]
|
||||
[InlineData("AV200000W00A000000000")]
|
||||
[InlineData("AV200000W00A000000000\0")]
|
||||
[InlineData("AV200000W00A0000000000")]
|
||||
[InlineData("AV200000W00A0000000000\0")]
|
||||
public void XGD23InvalidTests(string invalidString)
|
||||
{
|
||||
XgdInfo xgdInfo = new XgdInfo(invalidString, validate: true);
|
||||
Assert.False(xgdInfo.Initialized);
|
||||
}
|
||||
}
|
||||
}
|
||||
231
MPF.Test/Core/Utilities/EnumExtensionsTests.cs
Normal file
231
MPF.Test/Core/Utilities/EnumExtensionsTests.cs
Normal file
@@ -0,0 +1,231 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MPF.Core.Utilities;
|
||||
using RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Core.Utilities
|
||||
{
|
||||
public class EnumExtensionsTests
|
||||
{
|
||||
/// <summary>
|
||||
/// MediaType values that support drive speeds
|
||||
/// </summary>
|
||||
private static readonly MediaType?[] _supportDriveSpeeds = new MediaType?[]
|
||||
{
|
||||
MediaType.CDROM,
|
||||
MediaType.DVD,
|
||||
MediaType.GDROM,
|
||||
MediaType.HDDVD,
|
||||
MediaType.BluRay,
|
||||
MediaType.NintendoGameCubeGameDisc,
|
||||
MediaType.NintendoWiiOpticalDisc,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// RedumpSystem values that are considered Audio
|
||||
/// </summary>
|
||||
private static readonly RedumpSystem?[] _audioSystems = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem,
|
||||
RedumpSystem.AudioCD,
|
||||
RedumpSystem.DVDAudio,
|
||||
RedumpSystem.HasbroiONEducationalGamingSystem,
|
||||
RedumpSystem.HasbroVideoNow,
|
||||
RedumpSystem.HasbroVideoNowColor,
|
||||
RedumpSystem.HasbroVideoNowJr,
|
||||
RedumpSystem.HasbroVideoNowXP,
|
||||
RedumpSystem.PhilipsCDi,
|
||||
RedumpSystem.SuperAudioCD,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// RedumpSystem values that are considered markers
|
||||
/// </summary>
|
||||
private static readonly RedumpSystem?[] _markerSystems = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.MarkerArcadeEnd,
|
||||
RedumpSystem.MarkerComputerEnd,
|
||||
RedumpSystem.MarkerDiscBasedConsoleEnd,
|
||||
RedumpSystem.MarkerOtherEnd,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// RedumpSystem values that are have reversed ringcodes
|
||||
/// </summary>
|
||||
private static readonly RedumpSystem?[] _reverseRingcodeSystems = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.SonyPlayStation2,
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
RedumpSystem.SonyPlayStation4,
|
||||
RedumpSystem.SonyPlayStationPortable,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// RedumpSystem values that are considered XGD
|
||||
/// </summary>
|
||||
private static readonly RedumpSystem?[] _xgdSystems = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.MicrosoftXbox,
|
||||
RedumpSystem.MicrosoftXbox360,
|
||||
RedumpSystem.MicrosoftXboxOne,
|
||||
RedumpSystem.MicrosoftXboxSeriesXS,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Check that all optical media support drive speeds
|
||||
/// </summary>
|
||||
/// <param name="mediaType">DriveType value to check</param>
|
||||
/// <param name="expected">The expected value to come from the check</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateSupportDriveSpeedsTestData))]
|
||||
public void DoesSupportDriveSpeedTest(MediaType? mediaType, bool expected)
|
||||
{
|
||||
bool actual = mediaType.DoesSupportDriveSpeed();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that all systems with reversed ringcodes are marked properly
|
||||
/// </summary>
|
||||
/// <param name="redumpSystem">RedumpSystem value to check</param>
|
||||
/// <param name="expected">The expected value to come from the check</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateReversedRingcodeSystemsTestData))]
|
||||
public void HasReversedRingcodesTest(RedumpSystem? redumpSystem, bool expected)
|
||||
{
|
||||
bool actual = redumpSystem.HasReversedRingcodes();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that all audio systems are marked properly
|
||||
/// </summary>
|
||||
/// <param name="redumpSystem">RedumpSystem value to check</param>
|
||||
/// <param name="expected">The expected value to come from the check</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateAudioSystemsTestData))]
|
||||
public void IsAudioTest(RedumpSystem? redumpSystem, bool expected)
|
||||
{
|
||||
bool actual = redumpSystem.IsAudio();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that all marker systems are marked properly
|
||||
/// </summary>
|
||||
/// <param name="redumpSystem">RedumpSystem value to check</param>
|
||||
/// <param name="expected">The expected value to come from the check</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateMarkerSystemsTestData))]
|
||||
public void IsMarkerTest(RedumpSystem? redumpSystem, bool expected)
|
||||
{
|
||||
bool actual = redumpSystem.IsMarker();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that all XGD systems are marked properly
|
||||
/// </summary>
|
||||
/// <param name="redumpSystem">RedumpSystem value to check</param>
|
||||
/// <param name="expected">The expected value to come from the check</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateXGDSystemsTestData))]
|
||||
public void IsXGDTest(RedumpSystem? redumpSystem, bool expected)
|
||||
{
|
||||
bool actual = redumpSystem.IsXGD();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of MediaType values that support drive speeds
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of MediaType values</returns>
|
||||
public static List<object[]> GenerateSupportDriveSpeedsTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, false } };
|
||||
foreach (MediaType mediaType in Enum.GetValues(typeof(MediaType)))
|
||||
{
|
||||
if (_supportDriveSpeeds.Contains(mediaType))
|
||||
testData.Add(new object[] { mediaType, true });
|
||||
else
|
||||
testData.Add(new object[] { mediaType, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of RedumpSystem values that are considered Audio
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of RedumpSystem values</returns>
|
||||
public static List<object[]> GenerateAudioSystemsTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, false } };
|
||||
foreach (RedumpSystem redumpSystem in Enum.GetValues(typeof(RedumpSystem)))
|
||||
{
|
||||
if (_audioSystems.Contains(redumpSystem))
|
||||
testData.Add(new object[] { redumpSystem, true });
|
||||
else
|
||||
testData.Add(new object[] { redumpSystem, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of RedumpSystem values that are considered markers
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of RedumpSystem values</returns>
|
||||
public static List<object[]> GenerateMarkerSystemsTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, false } };
|
||||
foreach (RedumpSystem redumpSystem in Enum.GetValues(typeof(RedumpSystem)))
|
||||
{
|
||||
if (_markerSystems.Contains(redumpSystem))
|
||||
testData.Add(new object[] { redumpSystem, true });
|
||||
else
|
||||
testData.Add(new object[] { redumpSystem, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of RedumpSystem values that are considered markers
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of RedumpSystem values</returns>
|
||||
public static List<object[]> GenerateReversedRingcodeSystemsTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, false } };
|
||||
foreach (RedumpSystem redumpSystem in Enum.GetValues(typeof(RedumpSystem)))
|
||||
{
|
||||
if (_reverseRingcodeSystems.Contains(redumpSystem))
|
||||
testData.Add(new object[] { redumpSystem, true });
|
||||
else
|
||||
testData.Add(new object[] { redumpSystem, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of RedumpSystem values that are considered XGD
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of RedumpSystem values</returns>
|
||||
public static List<object[]> GenerateXGDSystemsTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, false } };
|
||||
foreach (RedumpSystem redumpSystem in Enum.GetValues(typeof(RedumpSystem)))
|
||||
{
|
||||
if (_xgdSystems.Contains(redumpSystem))
|
||||
testData.Add(new object[] { redumpSystem, true });
|
||||
else
|
||||
testData.Add(new object[] { redumpSystem, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
}
|
||||
}
|
||||
33
MPF.Test/Library/DumpEnvironmentTests.cs
Normal file
33
MPF.Test/Library/DumpEnvironmentTests.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.IO;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Library;
|
||||
using RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Library
|
||||
{
|
||||
public class DumpEnvironmentTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(null, 'D', false, MediaType.NONE, false)]
|
||||
[InlineData("", 'D', false, MediaType.NONE, false)]
|
||||
[InlineData("cd F test.bin 8 /c2 20", 'F', false, MediaType.CDROM, true)]
|
||||
[InlineData("fd A test.img", 'A', true, MediaType.FloppyDisk, true)]
|
||||
[InlineData("dvd X test.iso 8 /raw", 'X', false, MediaType.FloppyDisk, false)]
|
||||
[InlineData("stop D", 'D', false, MediaType.DVD, true)]
|
||||
public void ParametersValidTest(string parameters, char letter, bool isFloppy, MediaType? mediaType, bool expected)
|
||||
{
|
||||
var options = new Options() { InternalProgram = InternalProgram.DiscImageCreator };
|
||||
|
||||
// TODO: This relies on creating real objects for the drive. Can we mock this out instead?
|
||||
var drive = isFloppy
|
||||
? 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);
|
||||
|
||||
bool actual = env.ParametersValid();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
200
MPF.Test/Library/InfoToolTests.cs
Normal file
200
MPF.Test/Library/InfoToolTests.cs
Normal file
@@ -0,0 +1,200 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MPF.Library;
|
||||
using RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Library
|
||||
{
|
||||
public class InfoToolTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(null, 0, 0, 0, 0, null)]
|
||||
[InlineData(null, 12345, 0, 0, 0, null)]
|
||||
[InlineData(null, 12345, 1, 0, 0, null)]
|
||||
[InlineData(null, 12345, 1, 2, 0, null)]
|
||||
[InlineData(null, 12345, 1, 2, 3, null)]
|
||||
[InlineData(MediaType.CDROM, 0, 0, 0, 0, "CD-ROM")]
|
||||
[InlineData(MediaType.CDROM, 12345, 0, 0, 0, "CD-ROM")]
|
||||
[InlineData(MediaType.CDROM, 12345, 1, 0, 0, "CD-ROM")]
|
||||
[InlineData(MediaType.CDROM, 12345, 1, 2, 0, "CD-ROM")]
|
||||
[InlineData(MediaType.CDROM, 12345, 1, 2, 3, "CD-ROM")]
|
||||
[InlineData(MediaType.DVD, 0, 0, 0, 0, "DVD-ROM-5")]
|
||||
[InlineData(MediaType.DVD, 12345, 0, 0, 0, "DVD-ROM-5")]
|
||||
[InlineData(MediaType.DVD, 12345, 1, 0, 0, "DVD-ROM-9")]
|
||||
[InlineData(MediaType.DVD, 12345, 1, 2, 0, "DVD-ROM-9")]
|
||||
[InlineData(MediaType.DVD, 12345, 1, 2, 3, "DVD-ROM-9")]
|
||||
[InlineData(MediaType.BluRay, 0, 0, 0, 0, "BD-ROM-25")]
|
||||
[InlineData(MediaType.BluRay, 12345, 0, 0, 0, "BD-ROM-25")]
|
||||
[InlineData(MediaType.BluRay, 26_843_531_857, 0, 0, 0, "BD-ROM-33")]
|
||||
[InlineData(MediaType.BluRay, 12345, 1, 0, 0, "BD-ROM-50")]
|
||||
[InlineData(MediaType.BluRay, 53_687_063_713, 1, 0, 0, "BD-ROM-66")]
|
||||
[InlineData(MediaType.BluRay, 12345, 1, 2, 0, "BD-ROM-100")]
|
||||
[InlineData(MediaType.BluRay, 12345, 1, 2, 3, "BD-ROM-128")]
|
||||
[InlineData(MediaType.UMD, 0, 0, 0, 0, "UMD-SL")]
|
||||
[InlineData(MediaType.UMD, 12345, 0, 0, 0, "UMD-SL")]
|
||||
[InlineData(MediaType.UMD, 12345, 1, 0, 0, "UMD-DL")]
|
||||
[InlineData(MediaType.UMD, 12345, 1, 2, 0, "UMD-DL")]
|
||||
[InlineData(MediaType.UMD, 12345, 1, 2, 3, "UMD-DL")]
|
||||
public void GetFixedMediaTypeTest(
|
||||
MediaType? mediaType,
|
||||
long size,
|
||||
long layerbreak,
|
||||
long layerbreak2,
|
||||
long layerbreak3,
|
||||
string expected)
|
||||
{
|
||||
// TODO: Add tests around BDU
|
||||
string actual = InfoTool.GetFixedMediaType(mediaType, null, size, layerbreak, layerbreak2, layerbreak3);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null)]
|
||||
[InlineData(" ", " ")]
|
||||
[InlineData("super\\blah.bin", "super\\blah.bin")]
|
||||
[InlineData("super\\hero\\blah.bin", "super\\hero\\blah.bin")]
|
||||
[InlineData("super.hero\\blah.bin", "super.hero\\blah.bin")]
|
||||
[InlineData("superhero\\blah.rev.bin", "superhero\\blah.rev.bin")]
|
||||
[InlineData("super&hero\\blah.bin", "super&hero\\blah.bin")]
|
||||
[InlineData("superhero\\blah&foo.bin", "superhero\\blah&foo.bin")]
|
||||
public void NormalizeOutputPathsTest(string outputPath, string expectedPath)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(expectedPath))
|
||||
expectedPath = Path.GetFullPath(expectedPath);
|
||||
|
||||
string actualPath = InfoTool.NormalizeOutputPaths(outputPath);
|
||||
Assert.Equal(expectedPath, actualPath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessSpecialFieldsCompleteTest()
|
||||
{
|
||||
// Create a new SubmissionInfo object
|
||||
SubmissionInfo info = new SubmissionInfo()
|
||||
{
|
||||
CommonDiscInfo = new CommonDiscInfoSection()
|
||||
{
|
||||
Comments = "This is a comments line\n[T:ISBN] ISBN Value",
|
||||
CommentsSpecialFields = new Dictionary<SiteCode?, string>()
|
||||
{
|
||||
[SiteCode.VolumeLabel] = "VOLUME_LABEL",
|
||||
},
|
||||
|
||||
Contents = "This is a contents line\n[T:GF] Game Footage",
|
||||
ContentsSpecialFields = new Dictionary<SiteCode?, string>()
|
||||
{
|
||||
[SiteCode.Patches] = "1.04 patch",
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
// Process the special fields
|
||||
InfoTool.ProcessSpecialFields(info);
|
||||
|
||||
// Validate the basics
|
||||
Assert.NotNull(info.CommonDiscInfo.Comments);
|
||||
Assert.Null(info.CommonDiscInfo.CommentsSpecialFields);
|
||||
Assert.NotNull(info.CommonDiscInfo.Contents);
|
||||
Assert.Null(info.CommonDiscInfo.ContentsSpecialFields);
|
||||
|
||||
// Split the values
|
||||
string[] splitComments = info.CommonDiscInfo.Comments.Split('\n');
|
||||
string[] splitContents = info.CommonDiscInfo.Contents.Split('\n');
|
||||
|
||||
// Validate the lines
|
||||
Assert.Equal(3, splitComments.Length);
|
||||
Assert.Equal(5, splitContents.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessSpecialFieldsNullObjectTest()
|
||||
{
|
||||
// Create a new SubmissionInfo object
|
||||
SubmissionInfo info = new SubmissionInfo()
|
||||
{
|
||||
CommonDiscInfo = null,
|
||||
};
|
||||
|
||||
// Process the special fields
|
||||
InfoTool.ProcessSpecialFields(info);
|
||||
|
||||
// Validate
|
||||
Assert.Null(info.CommonDiscInfo);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessSpecialFieldsNullCommentsContentsTest()
|
||||
{
|
||||
// Create a new SubmissionInfo object
|
||||
SubmissionInfo info = new SubmissionInfo()
|
||||
{
|
||||
CommonDiscInfo = new CommonDiscInfoSection()
|
||||
{
|
||||
Comments = null,
|
||||
CommentsSpecialFields = new Dictionary<SiteCode?, string>()
|
||||
{
|
||||
[SiteCode.VolumeLabel] = "VOLUME_LABEL",
|
||||
},
|
||||
|
||||
Contents = null,
|
||||
ContentsSpecialFields = new Dictionary<SiteCode?, string>()
|
||||
{
|
||||
[SiteCode.Patches] = "1.04 patch",
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
// Process the special fields
|
||||
InfoTool.ProcessSpecialFields(info);
|
||||
|
||||
// Validate the basics
|
||||
Assert.NotNull(info.CommonDiscInfo.Comments);
|
||||
Assert.Null(info.CommonDiscInfo.CommentsSpecialFields);
|
||||
Assert.NotNull(info.CommonDiscInfo.Contents);
|
||||
Assert.Null(info.CommonDiscInfo.ContentsSpecialFields);
|
||||
|
||||
// Split the values
|
||||
string[] splitComments = info.CommonDiscInfo.Comments.Split('\n');
|
||||
string[] splitContents = info.CommonDiscInfo.Contents.Split('\n');
|
||||
|
||||
// Validate the lines
|
||||
Assert.Single(splitComments);
|
||||
Assert.Equal(2, splitContents.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessSpecialFieldsNullDictionariesTest()
|
||||
{
|
||||
// Create a new SubmissionInfo object
|
||||
SubmissionInfo info = new SubmissionInfo()
|
||||
{
|
||||
CommonDiscInfo = new CommonDiscInfoSection()
|
||||
{
|
||||
Comments = "This is a comments line\n[T:ISBN] ISBN Value",
|
||||
CommentsSpecialFields = null,
|
||||
|
||||
Contents = "This is a contents line\n[T:GF] Game Footage",
|
||||
ContentsSpecialFields = null,
|
||||
}
|
||||
};
|
||||
|
||||
// Process the special fields
|
||||
InfoTool.ProcessSpecialFields(info);
|
||||
|
||||
// Validate the basics
|
||||
Assert.NotNull(info.CommonDiscInfo.Comments);
|
||||
Assert.Null(info.CommonDiscInfo.CommentsSpecialFields);
|
||||
Assert.NotNull(info.CommonDiscInfo.Contents);
|
||||
Assert.Null(info.CommonDiscInfo.ContentsSpecialFields);
|
||||
|
||||
// Split the values
|
||||
string[] splitComments = info.CommonDiscInfo.Comments.Split('\n');
|
||||
string[] splitContents = info.CommonDiscInfo.Contents.Split('\n');
|
||||
|
||||
// Validate the lines
|
||||
Assert.Equal(2, splitComments.Length);
|
||||
Assert.Equal(2, splitContents.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
271
MPF.Test/Library/ProtectionTests.cs
Normal file
271
MPF.Test/Library/ProtectionTests.cs
Normal file
@@ -0,0 +1,271 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MPF.Library;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Library
|
||||
{
|
||||
public class ProtectionTests
|
||||
{
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsActiveMARKTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"ActiveMARK",
|
||||
"ActiveMARK 5",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("ActiveMARK 5", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsCactusDataShieldTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"Cactus Data Shield 200",
|
||||
"Cactus Data Shield 200 (Build 3.0.100a)",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("Cactus Data Shield 200 (Build 3.0.100a)", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsCDCheckTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"Anything Else Protection",
|
||||
"Executable-Based CD Check",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("Anything Else Protection", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsCDCopsTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"CD-Cops",
|
||||
"CD-Cops v1.2.0",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("CD-Cops v1.2.0", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsCDKeyTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"Anything Else Protection",
|
||||
"CD-Key / Serial",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("Anything Else Protection", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsEACdKeyTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"EA CdKey Registration Module",
|
||||
"EA CdKey Registration Module v1.2.0",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("EA CdKey Registration Module v1.2.0", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsEADRMTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"EA DRM Protection",
|
||||
"EA DRM Protection v1.2.0",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("EA DRM Protection v1.2.0", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsGFWLTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"Games for Windows LIVE",
|
||||
"Games for Windows LIVE v1.2.0",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("Games for Windows LIVE v1.2.0", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsGFWLZDPPTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"Games for Windows LIVE",
|
||||
"Games for Windows LIVE Zero Day Piracy Protection",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("Games for Windows LIVE, Games for Windows LIVE Zero Day Piracy Protection", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsImpulseReactorTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"Impulse Reactor",
|
||||
"Impulse Reactor Core Module v1.2.0",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("Impulse Reactor Core Module v1.2.0", sanitized);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0)]
|
||||
[InlineData(1)]
|
||||
[InlineData(2)]
|
||||
[InlineData(3)]
|
||||
public void SanitizeFoundProtectionsJoWoodXProtTest(int skip)
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"JoWood X-Prot 1.2.0.00",
|
||||
"JoWood X-Prot v2",
|
||||
"JoWood X-Prot v1.4+",
|
||||
"JoWood X-Prot v1.0-v1.3",
|
||||
"JoWood X-Prot",
|
||||
};
|
||||
|
||||
// Safeguard for the future
|
||||
if (skip >= protections.Count)
|
||||
throw new ArgumentException("Invalid skip value", nameof(skip));
|
||||
|
||||
// The list is in order of preference
|
||||
protections = protections.Skip(skip).ToList();
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal(protections[0], sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsOnlineRegistrationTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"Anything Else Protection",
|
||||
"Executable-Based Online Registration",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("Anything Else Protection", sanitized);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0)]
|
||||
[InlineData(1)]
|
||||
[InlineData(2)]
|
||||
[InlineData(3)]
|
||||
[InlineData(4)]
|
||||
[InlineData(5)]
|
||||
[InlineData(6)]
|
||||
[InlineData(7)]
|
||||
[InlineData(8)]
|
||||
public void SanitizeFoundProtectionsSafeDiscTest(int skip)
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"SafeDisc 1.20.000",
|
||||
"SafeDisc (drvmgt.dll) 1.2.0",
|
||||
"SafeDisc (secdrv.sys) 1.2.0",
|
||||
"SafeDisc (dplayerx.dll) 1.2.0",
|
||||
"SafeDisc 3.20-4.xx (version removed)",
|
||||
"SafeDisc 2",
|
||||
"SafeDisc 1/Lite",
|
||||
"SafeDisc Lite",
|
||||
"SafeDisc 1-3",
|
||||
"SafeDisc",
|
||||
};
|
||||
|
||||
// Safeguard for the future
|
||||
if (skip >= protections.Count)
|
||||
throw new ArgumentException("Invalid skip value", nameof(skip));
|
||||
|
||||
// The list is in order of preference
|
||||
protections = protections.Skip(skip).ToList();
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal(protections[0], sanitized);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0)]
|
||||
[InlineData(1)]
|
||||
[InlineData(2)]
|
||||
[InlineData(3)]
|
||||
public void SanitizeFoundProtectionStarForceTest(int skip)
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"StarForce 1.20.000.000",
|
||||
"StarForce 5 [Protected Module]",
|
||||
"StarForce 5",
|
||||
"StarForce 3-5",
|
||||
"StarForce",
|
||||
};
|
||||
|
||||
// Safeguard for the future
|
||||
if (skip >= protections.Count)
|
||||
throw new ArgumentException("Invalid skip value", nameof(skip));
|
||||
|
||||
// The list is in order of preference
|
||||
protections = protections.Skip(skip).ToList();
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal(protections[0], sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsSysiphusTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"Sysiphus",
|
||||
"Sysiphus v1.2.0",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("Sysiphus v1.2.0", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsXCPTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"XCP",
|
||||
"XCP v1.2.0",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("XCP v1.2.0", sanitized);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +1,54 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net48;netcoreapp3.1</TargetFrameworks>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<TargetFrameworks>net48;net6.0-windows</TargetFrameworks>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj">
|
||||
<Project>{51ab0928-13f9-44bf-a407-b6957a43a056}</Project>
|
||||
<Name>MPF.Library</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MPF\MPF.csproj">
|
||||
<Project>{7b1b75eb-8940-466f-bd51-76471a57f9be}</Project>
|
||||
<Name>MPF</Name>
|
||||
</ProjectReference>
|
||||
<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>
|
||||
<PackageReference Include="Microsoft.CodeCoverage" Version="16.11.0-release-20210626-04" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0-release-20210626-04" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<ProjectReference Include="..\MPF\MPF.csproj" />
|
||||
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj" />
|
||||
<ProjectReference Include="..\MPF.Modules\MPF.Modules.csproj" />
|
||||
<ProjectReference Include="..\RedumpLib\RedumpLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeCoverage" Version="17.6.3" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="xunit" Version="2.5.0" />
|
||||
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
|
||||
<PackageReference Include="xunit.analyzers" Version="0.10.0" />
|
||||
<PackageReference Include="xunit.assert" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.core" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.extensibility.core" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.extensibility.execution" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.console" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PackageReference Include="xunit.analyzers" Version="1.2.0" />
|
||||
<PackageReference Include="xunit.assert" Version="2.5.0" />
|
||||
<PackageReference Include="xunit.core" Version="2.5.0" />
|
||||
<PackageReference Include="xunit.extensibility.core" Version="2.5.0" />
|
||||
<PackageReference Include="xunit.extensibility.execution" Version="2.5.0" />
|
||||
<PackageReference Include="xunit.runner.console" Version="2.5.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
269
MPF.Test/Modules/DiscImageCreatorTests.cs
Normal file
269
MPF.Test/Modules/DiscImageCreatorTests.cs
Normal file
@@ -0,0 +1,269 @@
|
||||
using System.Collections.Generic;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Modules.DiscImageCreator;
|
||||
using RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Modules
|
||||
{
|
||||
public class DiscImageCreatorTests
|
||||
{
|
||||
#region Old Tests
|
||||
|
||||
[Theory]
|
||||
[InlineData(RedumpSystem.MicrosoftXbox, MediaType.CDROM, CommandStrings.CompactDisc)]
|
||||
[InlineData(RedumpSystem.MicrosoftXbox, MediaType.DVD, CommandStrings.XBOX)]
|
||||
[InlineData(RedumpSystem.MicrosoftXbox, MediaType.LaserDisc, null)]
|
||||
[InlineData(RedumpSystem.SonyPlayStation3, MediaType.BluRay, CommandStrings.BluRay)]
|
||||
[InlineData(RedumpSystem.AppleMacintosh, MediaType.FloppyDisk, CommandStrings.Floppy)]
|
||||
[InlineData(RedumpSystem.RawThrillsVarious, MediaType.GDROM, null)]
|
||||
public void ParametersFromSystemAndTypeTest(RedumpSystem? knownSystem, MediaType? mediaType, string expected)
|
||||
{
|
||||
var options = new Options();
|
||||
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, options);
|
||||
Assert.Equal(expected, actual.BaseCommand);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(RedumpSystem.AppleMacintosh, MediaType.LaserDisc, null)] // Deliberately unsupported
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, new string[] { FlagStrings.C2Opcode, FlagStrings.NoFixSubQSecuROM, FlagStrings.ScanFileProtect })]
|
||||
[InlineData(RedumpSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc, new string[] { FlagStrings.Raw })]
|
||||
public void ParametersFromOptionsSpecialDefaultTest(RedumpSystem? knownSystem, MediaType? mediaType,string[] expected)
|
||||
{
|
||||
var options = new Options();
|
||||
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, options);
|
||||
|
||||
HashSet<string> expectedSet = new HashSet<string>(expected ?? new string[0]);
|
||||
HashSet<string> actualSet = GenerateUsedKeys(actual);
|
||||
Assert.Equal(expectedSet, actualSet);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(RedumpSystem.SegaDreamcast, MediaType.GDROM, 1000, new string[] { FlagStrings.C2Opcode })]
|
||||
[InlineData(RedumpSystem.SegaDreamcast, MediaType.GDROM, -1, new string[] { FlagStrings.C2Opcode })]
|
||||
public void ParametersFromOptionsC2RereadTest(RedumpSystem? knownSystem, MediaType? mediaType, int rereadC2, string[] expected)
|
||||
{
|
||||
var options = new Options { DICRereadCount = rereadC2 };
|
||||
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, options);
|
||||
|
||||
HashSet<string> expectedSet = new HashSet<string>(expected ?? new string[0]);
|
||||
HashSet<string> actualSet = GenerateUsedKeys(actual);
|
||||
|
||||
Assert.Equal(expectedSet, actualSet);
|
||||
if (rereadC2 == -1 || !knownSystem.MediaTypes().Contains(mediaType))
|
||||
Assert.Null(actual.C2OpcodeValue[0]);
|
||||
else
|
||||
Assert.Equal(rereadC2, actual.C2OpcodeValue[0]);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, 1000, new string[] { FlagStrings.DVDReread })]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, -1, new string[] { FlagStrings.DVDReread })]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.BluRay, 1000, new string[] { FlagStrings.DVDReread })]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.BluRay, -1, new string[] { FlagStrings.DVDReread })]
|
||||
public void ParametersFromOptionsDVDRereadTest(RedumpSystem? knownSystem, MediaType? mediaType, int rereadDVDBD, string[] expected)
|
||||
{
|
||||
var options = new Options { DICDVDRereadCount = rereadDVDBD };
|
||||
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, options);
|
||||
|
||||
HashSet<string> expectedSet = new HashSet<string>(expected ?? new string[0]);
|
||||
HashSet<string> actualSet = GenerateUsedKeys(actual);
|
||||
|
||||
Assert.Equal(expectedSet, actualSet);
|
||||
if (rereadDVDBD == -1 || !knownSystem.MediaTypes().Contains(mediaType))
|
||||
Assert.Null(actual.DVDRereadValue);
|
||||
else
|
||||
Assert.Equal(rereadDVDBD, actual.DVDRereadValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(RedumpSystem.BDVideo, MediaType.BluRay, true, new string[] { FlagStrings.DVDReread })]
|
||||
[InlineData(RedumpSystem.BDVideo, MediaType.BluRay, false, new string[] { FlagStrings.DVDReread })]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, true, new string[] { FlagStrings.C2Opcode, FlagStrings.NoFixSubQSecuROM, FlagStrings.MultiSectorRead, FlagStrings.ScanFileProtect })]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, false, new string[] { FlagStrings.C2Opcode, FlagStrings.NoFixSubQSecuROM, FlagStrings.ScanFileProtect })]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, true, new string[] { FlagStrings.DVDReread })]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, false, new string[] { FlagStrings.DVDReread })]
|
||||
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, true, new string[] { FlagStrings.DVDReread })]
|
||||
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, false, new string[] { FlagStrings.DVDReread })]
|
||||
public void ParametersFromOptionsMultiSectorReadTest(RedumpSystem? knownSystem, MediaType? mediaType, bool multiSectorRead, string[] expected)
|
||||
{
|
||||
var options = new Options { DICMultiSectorRead = multiSectorRead };
|
||||
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, options);
|
||||
|
||||
HashSet<string> expectedSet = new HashSet<string>(expected ?? new string[0]);
|
||||
HashSet<string> actualSet = GenerateUsedKeys(actual);
|
||||
Assert.Equal(expectedSet, actualSet);
|
||||
if (expectedSet.Count != 1 && multiSectorRead)
|
||||
Assert.Equal(0, actual.MultiSectorReadValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(RedumpSystem.BDVideo, MediaType.BluRay, true, new string[] { FlagStrings.DVDReread })]
|
||||
[InlineData(RedumpSystem.BDVideo, MediaType.BluRay, false, new string[] { FlagStrings.DVDReread })]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, true, new string[] { FlagStrings.C2Opcode, FlagStrings.NoFixSubQSecuROM, FlagStrings.ScanFileProtect, FlagStrings.ScanSectorProtect, FlagStrings.SubchannelReadLevel })]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, false, new string[] { FlagStrings.C2Opcode, FlagStrings.NoFixSubQSecuROM, FlagStrings.ScanFileProtect })]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, true, new string[] { FlagStrings.DVDReread, FlagStrings.ScanFileProtect })]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, false, new string[] { FlagStrings.DVDReread })]
|
||||
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, true, new string[] { FlagStrings.DVDReread })]
|
||||
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, false, new string[] { FlagStrings.DVDReread })]
|
||||
public void ParametersFromOptionsParanoidModeTest(RedumpSystem? knownSystem, MediaType? mediaType, bool paranoidMode, string[] expected)
|
||||
{
|
||||
var options = new Options { DICParanoidMode = paranoidMode };
|
||||
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, options);
|
||||
|
||||
HashSet<string> expectedSet = new HashSet<string>(expected ?? new string[0]);
|
||||
HashSet<string> actualSet = GenerateUsedKeys(actual);
|
||||
Assert.Equal(expectedSet, actualSet);
|
||||
if (paranoidMode)
|
||||
{
|
||||
if (actualSet.Contains(FlagStrings.ScanSectorProtect))
|
||||
Assert.True(actual[FlagStrings.ScanSectorProtect]);
|
||||
|
||||
if (actualSet.Contains(FlagStrings.SubchannelReadLevel))
|
||||
{
|
||||
Assert.True(actual[FlagStrings.SubchannelReadLevel]);
|
||||
Assert.Equal(2, actual.SubchannelReadLevelValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (actualSet.Contains(FlagStrings.ScanSectorProtect))
|
||||
Assert.False(actual[FlagStrings.ScanSectorProtect]);
|
||||
|
||||
if (actualSet.Contains(FlagStrings.SubchannelReadLevel))
|
||||
Assert.False(actual[FlagStrings.SubchannelReadLevel]);
|
||||
|
||||
Assert.Null(actual.SubchannelReadLevelValue);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, false)]
|
||||
[InlineData("", false)]
|
||||
[InlineData("cd F test.bin 8 /c2 20", true)]
|
||||
[InlineData("fd A test.img", true)]
|
||||
[InlineData("dvd X super\\test.iso 8 /raw", true)]
|
||||
[InlineData("bd D longer\\path_test.iso 16", true)]
|
||||
[InlineData("stop D", true)]
|
||||
[InlineData("ls", false)]
|
||||
public void ValidateParametersTest(string parameters, bool expected)
|
||||
{
|
||||
var actual = new Parameters(parameters);
|
||||
Assert.Equal(expected, actual.IsValid());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(MediaType.CDROM, ".bin")]
|
||||
[InlineData(MediaType.DVD, ".iso")]
|
||||
[InlineData(MediaType.LaserDisc, ".raw")]
|
||||
[InlineData(MediaType.NintendoWiiUOpticalDisc, ".wud")]
|
||||
[InlineData(MediaType.FloppyDisk, ".img")]
|
||||
[InlineData(MediaType.Cassette, ".wav")]
|
||||
[InlineData(MediaType.NONE, null)]
|
||||
public void MediaTypeToExtensionTest(MediaType? mediaType, string expected)
|
||||
{
|
||||
string actual = Converters.Extension(mediaType);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(CommandStrings.Audio, MediaType.CDROM)]
|
||||
[InlineData(CommandStrings.BluRay, MediaType.BluRay)]
|
||||
[InlineData(CommandStrings.Close, null)]
|
||||
[InlineData(CommandStrings.CompactDisc, MediaType.CDROM)]
|
||||
[InlineData(CommandStrings.Data, MediaType.CDROM)]
|
||||
[InlineData(CommandStrings.DigitalVideoDisc, MediaType.DVD)]
|
||||
[InlineData(CommandStrings.Eject, null)]
|
||||
[InlineData(CommandStrings.Floppy, MediaType.FloppyDisk)]
|
||||
[InlineData(CommandStrings.GDROM, MediaType.GDROM)]
|
||||
[InlineData(CommandStrings.MDS, null)]
|
||||
[InlineData(CommandStrings.Reset, null)]
|
||||
[InlineData(CommandStrings.SACD, MediaType.CDROM)]
|
||||
[InlineData(CommandStrings.Start, null)]
|
||||
[InlineData(CommandStrings.Stop, null)]
|
||||
[InlineData(CommandStrings.Sub, null)]
|
||||
[InlineData(CommandStrings.Swap, MediaType.GDROM)]
|
||||
[InlineData(CommandStrings.XBOX, MediaType.DVD)]
|
||||
public void BaseCommandToMediaTypeTest(string command, MediaType? expected)
|
||||
{
|
||||
MediaType? actual = Converters.ToMediaType(command);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(CommandStrings.Audio, RedumpSystem.AudioCD)]
|
||||
[InlineData(CommandStrings.BluRay, RedumpSystem.SonyPlayStation3)]
|
||||
[InlineData(CommandStrings.Close, null)]
|
||||
[InlineData(CommandStrings.CompactDisc, RedumpSystem.IBMPCcompatible)]
|
||||
[InlineData(CommandStrings.Data, RedumpSystem.IBMPCcompatible)]
|
||||
[InlineData(CommandStrings.DigitalVideoDisc, RedumpSystem.IBMPCcompatible)]
|
||||
[InlineData(CommandStrings.Eject, null)]
|
||||
[InlineData(CommandStrings.Floppy, RedumpSystem.IBMPCcompatible)]
|
||||
[InlineData(CommandStrings.GDROM, RedumpSystem.SegaDreamcast)]
|
||||
[InlineData(CommandStrings.MDS, null)]
|
||||
[InlineData(CommandStrings.Reset, null)]
|
||||
[InlineData(CommandStrings.SACD, RedumpSystem.SuperAudioCD)]
|
||||
[InlineData(CommandStrings.Start, null)]
|
||||
[InlineData(CommandStrings.Stop, null)]
|
||||
[InlineData(CommandStrings.Sub, null)]
|
||||
[InlineData(CommandStrings.Swap, RedumpSystem.SegaDreamcast)]
|
||||
[InlineData(CommandStrings.XBOX, RedumpSystem.MicrosoftXbox)]
|
||||
public void BaseCommandToRedumpSystemTest(string command, RedumpSystem? expected)
|
||||
{
|
||||
RedumpSystem? actual = Converters.ToRedumpSystem(command);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[Fact]
|
||||
public void DiscImageCreatorAudioParametersTest()
|
||||
{
|
||||
string originalParameters = "audio F \"ISO\\Audio CD\\Audio CD.bin\" 72 -5 0";
|
||||
|
||||
// Validate that a common audio commandline is parsed
|
||||
var parametersObject = new Parameters(originalParameters);
|
||||
Assert.NotNull(parametersObject);
|
||||
|
||||
// Validate that the same set of parameters are generated on the output
|
||||
string newParameters = parametersObject.GenerateParameters();
|
||||
Assert.NotNull(newParameters);
|
||||
Assert.Equal(originalParameters, newParameters);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DiscImageCreatorDataParametersTest()
|
||||
{
|
||||
string originalParameters = "data F \"ISO\\Data CD\\Data CD.bin\" 72 -5 0";
|
||||
|
||||
// Validate that a common audio commandline is parsed
|
||||
var parametersObject = new Parameters(originalParameters);
|
||||
Assert.NotNull(parametersObject);
|
||||
|
||||
// Validate that the same set of parameters are generated on the output
|
||||
string newParameters = parametersObject.GenerateParameters();
|
||||
Assert.NotNull(newParameters);
|
||||
Assert.Equal(originalParameters, newParameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a HashSet of keys that are considered to be set
|
||||
/// </summary>
|
||||
/// <param name="parameters">Parameters object to get keys from</param>
|
||||
/// <returns>HashSet representing the strings</returns>
|
||||
private static HashSet<string> GenerateUsedKeys(Parameters parameters)
|
||||
{
|
||||
HashSet<string> usedKeys = new HashSet<string>();
|
||||
if (parameters?.Keys == null)
|
||||
return usedKeys;
|
||||
|
||||
foreach (string key in parameters.Keys)
|
||||
{
|
||||
if (parameters[key] == true)
|
||||
usedKeys.Add(key);
|
||||
}
|
||||
|
||||
return usedKeys;
|
||||
}
|
||||
}
|
||||
}
|
||||
717
MPF.Test/RedumpLib/ExtensionsTests.cs
Normal file
717
MPF.Test/RedumpLib/ExtensionsTests.cs
Normal file
@@ -0,0 +1,717 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.RedumpLib
|
||||
{
|
||||
// TODO: Add tests for string-to-enum conversion
|
||||
public class ExtensionsTests
|
||||
{
|
||||
#region Cross-Enumeration
|
||||
|
||||
/// <summary>
|
||||
/// DiscType values that map to MediaType
|
||||
/// </summary>
|
||||
private static readonly DiscType?[] _mappableDiscTypes = new DiscType?[]
|
||||
{
|
||||
DiscType.BD25,
|
||||
DiscType.BD33,
|
||||
DiscType.BD50,
|
||||
DiscType.BD66,
|
||||
DiscType.BD100,
|
||||
DiscType.BD128,
|
||||
DiscType.CD,
|
||||
DiscType.DVD5,
|
||||
DiscType.DVD9,
|
||||
DiscType.GDROM,
|
||||
DiscType.HDDVDSL,
|
||||
DiscType.HDDVDDL,
|
||||
DiscType.NintendoGameCubeGameDisc,
|
||||
DiscType.NintendoWiiOpticalDiscSL,
|
||||
DiscType.NintendoWiiOpticalDiscDL,
|
||||
DiscType.NintendoWiiUOpticalDiscSL,
|
||||
DiscType.UMDSL,
|
||||
DiscType.UMDDL,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// MediaType values that map to DiscType
|
||||
/// </summary>
|
||||
private static readonly MediaType?[] _mappableMediaTypes = new MediaType?[]
|
||||
{
|
||||
MediaType.BluRay,
|
||||
MediaType.CDROM,
|
||||
MediaType.DVD,
|
||||
MediaType.GDROM,
|
||||
MediaType.HDDVD,
|
||||
MediaType.NintendoGameCubeGameDisc,
|
||||
MediaType.NintendoWiiOpticalDisc,
|
||||
MediaType.NintendoWiiUOpticalDisc,
|
||||
MediaType.UMD,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Check that every supported system has some set of MediaTypes supported
|
||||
/// </summary>
|
||||
/// <param name="redumpSystem">RedumpSystem value to check</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateRedumpSystemMappingTestData))]
|
||||
public void MediaTypesTest(RedumpSystem? redumpSystem)
|
||||
{
|
||||
var actual = redumpSystem.MediaTypes();
|
||||
Assert.NotEmpty(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that both mappable and unmappable media types output correctly
|
||||
/// </summary>
|
||||
/// <param name="mediaType">MediaType value to check</param>
|
||||
/// <param name="expectNull">True to expect a null mapping, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateMediaTypeMappingTestData))]
|
||||
public void ToDiscTypeTest(MediaType? mediaType, bool expectNull)
|
||||
{
|
||||
DiscType? actual = mediaType.ToDiscType();
|
||||
Assert.Equal(expectNull, actual == null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that DiscType values all map to something appropriate
|
||||
/// </summary>
|
||||
/// <param name="discType">DiscType value to check</param>
|
||||
/// <param name="expectNull">True to expect a null mapping, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateDiscTypeMappingTestData))]
|
||||
public void ToMediaTypeTest(DiscType? discType, bool expectNull)
|
||||
{
|
||||
MediaType? actual = discType.ToMediaType();
|
||||
Assert.Equal(expectNull, actual == null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of DiscType values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of DiscType values</returns>
|
||||
public static List<object[]> GenerateDiscTypeMappingTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (DiscType? discType in Enum.GetValues(typeof(DiscType)))
|
||||
{
|
||||
if (_mappableDiscTypes.Contains(discType))
|
||||
testData.Add(new object[] { discType, false });
|
||||
else
|
||||
testData.Add(new object[] { discType, true });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of RedumpSystem values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of RedumpSystem values</returns>
|
||||
public static List<object[]> GenerateRedumpSystemMappingTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null } };
|
||||
foreach (RedumpSystem? redumpSystem in Enum.GetValues(typeof(RedumpSystem)))
|
||||
{
|
||||
testData.Add(new object[] { redumpSystem });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of mappable media types
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of MediaTypes</returns>
|
||||
public static List<object[]> GenerateMediaTypeMappingTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
|
||||
foreach (MediaType? mediaType in Enum.GetValues(typeof(MediaType)))
|
||||
{
|
||||
if (_mappableMediaTypes.Contains(mediaType))
|
||||
testData.Add(new object[] { mediaType, false });
|
||||
else
|
||||
testData.Add(new object[] { mediaType, true });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Disc Category
|
||||
|
||||
/// <summary>
|
||||
/// Check that every DiscCategory has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="discCategory">DiscCategory value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateDiscCategoryTestData))]
|
||||
public void DiscCategoryLongNameTest(DiscCategory? discCategory, bool expectNull)
|
||||
{
|
||||
string actual = discCategory.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of DiscCategory values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of DiscCategory values</returns>
|
||||
public static List<object[]> GenerateDiscCategoryTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (DiscCategory? discCategory in Enum.GetValues(typeof(DiscCategory)))
|
||||
{
|
||||
testData.Add(new object[] { discCategory, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Disc Type
|
||||
|
||||
/// <summary>
|
||||
/// Check that every DiscType has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="discType">DiscType value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateDiscTypeTestData))]
|
||||
public void DiscTypeLongNameTest(DiscType? discType, bool expectNull)
|
||||
{
|
||||
string actual = discType.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of DiscType values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of DiscType values</returns>
|
||||
public static List<object[]> GenerateDiscTypeTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (DiscType? discType in Enum.GetValues(typeof(DiscType)))
|
||||
{
|
||||
if (discType == DiscType.NONE)
|
||||
testData.Add(new object[] { discType, true });
|
||||
else
|
||||
testData.Add(new object[] { discType, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Language
|
||||
|
||||
/// <summary>
|
||||
/// Check that every Language has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="language">Language value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateLanguageTestData))]
|
||||
public void LanguageLongNameTest(Language? language, bool expectNull)
|
||||
{
|
||||
string actual = language.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that every Language has a short name provided
|
||||
/// </summary>
|
||||
/// <param name="language">Language value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateLanguageTestData))]
|
||||
public void LanguageShortNameTest(Language? language, bool expectNull)
|
||||
{
|
||||
string actual = language.ShortName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure that every Language that has an ISO 639-1 code is unique
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void LanguageNoDuplicateTwoLetterCodeTest()
|
||||
{
|
||||
var fullLanguages = Enum.GetValues(typeof(Language)).Cast<Language?>().ToList();
|
||||
var filteredLanguages = new Dictionary<string, Language?>();
|
||||
|
||||
int totalCount = 0;
|
||||
foreach (Language? language in fullLanguages)
|
||||
{
|
||||
string code = language.TwoLetterCode();
|
||||
if (string.IsNullOrWhiteSpace(code))
|
||||
continue;
|
||||
|
||||
// Throw if the code already exists
|
||||
if (filteredLanguages.ContainsKey(code))
|
||||
throw new DuplicateNameException($"Code {code} already in dictionary");
|
||||
|
||||
filteredLanguages[code] = language;
|
||||
totalCount++;
|
||||
}
|
||||
|
||||
Assert.Equal(totalCount, filteredLanguages.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure that every Language that has a standard/bibliographic ISO 639-2 code is unique
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void LanguageNoDuplicateThreeLetterCodeTest()
|
||||
{
|
||||
var fullLanguages = Enum.GetValues(typeof(Language)).Cast<Language?>().ToList();
|
||||
var filteredLanguages = new Dictionary<string, Language?>();
|
||||
|
||||
int totalCount = 0;
|
||||
foreach (Language? language in fullLanguages)
|
||||
{
|
||||
string code = language.ThreeLetterCode();
|
||||
if (string.IsNullOrWhiteSpace(code))
|
||||
continue;
|
||||
|
||||
// Throw if the code already exists
|
||||
if (filteredLanguages.ContainsKey(code))
|
||||
throw new DuplicateNameException($"Code {code} already in dictionary");
|
||||
|
||||
filteredLanguages[code] = language;
|
||||
totalCount++;
|
||||
}
|
||||
|
||||
Assert.Equal(totalCount, filteredLanguages.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure that every Language that has a terminology ISO 639-2 code is unique
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void LanguageNoDuplicateThreeLetterCodeAltTest()
|
||||
{
|
||||
var fullLanguages = Enum.GetValues(typeof(Language)).Cast<Language?>().ToList();
|
||||
var filteredLanguages = new Dictionary<string, Language?>();
|
||||
|
||||
int totalCount = 0;
|
||||
foreach (Language? language in fullLanguages)
|
||||
{
|
||||
string code = language.ThreeLetterCodeAlt();
|
||||
if (string.IsNullOrWhiteSpace(code))
|
||||
continue;
|
||||
|
||||
// Throw if the code already exists
|
||||
if (filteredLanguages.ContainsKey(code))
|
||||
throw new DuplicateNameException($"Code {code} already in dictionary");
|
||||
|
||||
filteredLanguages[code] = language;
|
||||
totalCount++;
|
||||
}
|
||||
|
||||
Assert.Equal(totalCount, filteredLanguages.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of Language values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of Language values</returns>
|
||||
public static List<object[]> GenerateLanguageTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (Language? language in Enum.GetValues(typeof(Language)))
|
||||
{
|
||||
testData.Add(new object[] { language, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Language Selection
|
||||
|
||||
/// <summary>
|
||||
/// Check that every LanguageSelection has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="languageSelection">LanguageSelection value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateLanguageSelectionTestData))]
|
||||
public void LanguageSelectionLongNameTest(LanguageSelection? languageSelection, bool expectNull)
|
||||
{
|
||||
string actual = languageSelection.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of LanguageSelection values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of LanguageSelection values</returns>
|
||||
public static List<object[]> GenerateLanguageSelectionTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (LanguageSelection? languageSelection in Enum.GetValues(typeof(LanguageSelection)))
|
||||
{
|
||||
testData.Add(new object[] { languageSelection, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Media Type
|
||||
|
||||
/// <summary>
|
||||
/// Check that every MediaType has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="mediaType">MediaType value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateMediaTypeTestData))]
|
||||
public void MediaTypeLongNameTest(MediaType? mediaType, bool expectNull)
|
||||
{
|
||||
string actual = mediaType.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that every MediaType has a short name provided
|
||||
/// </summary>
|
||||
/// <param name="mediaType">MediaType value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateMediaTypeTestData))]
|
||||
public void MediaTypeShortNameTest(MediaType? mediaType, bool expectNull)
|
||||
{
|
||||
string actual = mediaType.ShortName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of MediaType values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of MediaType values</returns>
|
||||
public static List<object[]> GenerateMediaTypeTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (MediaType? mediaType in Enum.GetValues(typeof(MediaType)))
|
||||
{
|
||||
testData.Add(new object[] { mediaType, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Region
|
||||
|
||||
/// <summary>
|
||||
/// Check that every Region has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="region">Region value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateRegionTestData))]
|
||||
public void RegionLongNameTest(Region? region, bool expectNull)
|
||||
{
|
||||
string actual = region.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that every Region has a short name provided
|
||||
/// </summary>
|
||||
/// <param name="region">Region value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateRegionTestData))]
|
||||
public void RegionShortNameTest(Region? region, bool expectNull)
|
||||
{
|
||||
string actual = region.ShortName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure that every Language that has an ISO 639-1 code is unique
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void RegionNoDuplicateShortNameTest()
|
||||
{
|
||||
var fullRegions = Enum.GetValues(typeof(Region)).Cast<Region?>().ToList();
|
||||
var filteredRegions = new Dictionary<string, Region?>();
|
||||
|
||||
int totalCount = 0;
|
||||
foreach (Region? region in fullRegions)
|
||||
{
|
||||
string code = region.ShortName();
|
||||
if (string.IsNullOrWhiteSpace(code))
|
||||
continue;
|
||||
|
||||
// Throw if the code already exists
|
||||
if (filteredRegions.ContainsKey(code))
|
||||
throw new DuplicateNameException($"Code {code} already in dictionary");
|
||||
|
||||
filteredRegions[code] = region;
|
||||
totalCount++;
|
||||
}
|
||||
|
||||
Assert.Equal(totalCount, filteredRegions.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of Region values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of Region values</returns>
|
||||
public static List<object[]> GenerateRegionTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (Region? region in Enum.GetValues(typeof(Region)))
|
||||
{
|
||||
testData.Add(new object[] { region, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Site Code
|
||||
|
||||
/// <summary>
|
||||
/// Check that every SiteCode has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="siteCode">SiteCode value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateSiteCodeTestData))]
|
||||
public void SiteCodeLongNameTest(SiteCode? siteCode, bool expectNull)
|
||||
{
|
||||
string actual = siteCode.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that every SiteCode has a short name provided
|
||||
/// </summary>
|
||||
/// <param name="siteCode">SiteCode value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateSiteCodeTestData))]
|
||||
public void SiteCodeShortNameTest(SiteCode? siteCode, bool expectNull)
|
||||
{
|
||||
string actual = siteCode.ShortName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of SiteCode values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of SiteCode values</returns>
|
||||
public static List<object[]> GenerateSiteCodeTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (SiteCode? siteCode in Enum.GetValues(typeof(SiteCode)))
|
||||
{
|
||||
testData.Add(new object[] { siteCode, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region System
|
||||
|
||||
/// <summary>
|
||||
/// Check that every RedumpSystem has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="redumpSystem">RedumpSystem value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateRedumpSystemTestData))]
|
||||
public void RedumpSystemLongNameTest(RedumpSystem? redumpSystem, bool expectNull)
|
||||
{
|
||||
string actual = redumpSystem.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
// TODO: Re-enable the following test once non-Redump systems are accounted for
|
||||
|
||||
/// <summary>
|
||||
/// Check that every RedumpSystem has a short name provided
|
||||
/// </summary>
|
||||
/// <param name="redumpSystem">RedumpSystem value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
//[Theory]
|
||||
//[MemberData(nameof(GenerateRedumpSystemTestData))]
|
||||
//public void RedumpSystemShortNameTest(RedumpSystem? redumpSystem, bool expectNull)
|
||||
//{
|
||||
// string actual = redumpSystem.ShortName();
|
||||
|
||||
// if (expectNull)
|
||||
// Assert.Null(actual);
|
||||
// else
|
||||
// Assert.NotNull(actual);
|
||||
//}
|
||||
|
||||
// TODO: Test the other attributes as well
|
||||
// Most are bool checks so they're not as interesting to have unit tests around
|
||||
// SystemCategory always returns something as well, so is it worth testing?
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of RedumpSystem values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of RedumpSystem values</returns>
|
||||
public static List<object[]> GenerateRedumpSystemTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (RedumpSystem? redumpSystem in Enum.GetValues(typeof(RedumpSystem)))
|
||||
{
|
||||
// We want to skip all markers for this
|
||||
if (redumpSystem.IsMarker())
|
||||
continue;
|
||||
|
||||
testData.Add(new object[] { redumpSystem, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region System Category
|
||||
|
||||
/// <summary>
|
||||
/// Check that every SystemCategory has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="systemCategory">SystemCategory value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateSystemCategoryTestData))]
|
||||
public void SystemCategoryLongNameTest(SystemCategory? systemCategory, bool expectNull)
|
||||
{
|
||||
string actual = systemCategory.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of SystemCategory values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of SystemCategory values</returns>
|
||||
public static List<object[]> GenerateSystemCategoryTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (SystemCategory? systemCategory in Enum.GetValues(typeof(SystemCategory)))
|
||||
{
|
||||
if (systemCategory == SystemCategory.NONE)
|
||||
testData.Add(new object[] { systemCategory, true });
|
||||
else
|
||||
testData.Add(new object[] { systemCategory, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Yes/No
|
||||
|
||||
/// <summary>
|
||||
/// Check that every YesNo has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="yesNo">YesNo value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateYesNoTestData))]
|
||||
public void YesNoLongNameTest(YesNo? yesNo, bool expectNull)
|
||||
{
|
||||
string actual = yesNo.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of YesNo values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of YesNo values</returns>
|
||||
public static List<object[]> GenerateYesNoTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, false } };
|
||||
foreach (YesNo? yesNo in Enum.GetValues(typeof(YesNo)))
|
||||
{
|
||||
testData.Add(new object[] { yesNo, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
179
MPF.Test/RedumpLib/SubmissionInfoTests.cs
Normal file
179
MPF.Test/RedumpLib/SubmissionInfoTests.cs
Normal file
@@ -0,0 +1,179 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.RedumpLib
|
||||
{
|
||||
public class SubmissionInfoTests
|
||||
{
|
||||
[Fact]
|
||||
public void EmptySerializationTest()
|
||||
{
|
||||
var submissionInfo = new SubmissionInfo();
|
||||
string json = JsonConvert.SerializeObject(submissionInfo, Formatting.Indented);
|
||||
Assert.NotNull(json);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PartialSerializationTest()
|
||||
{
|
||||
var submissionInfo = new SubmissionInfo()
|
||||
{
|
||||
CommonDiscInfo = new CommonDiscInfoSection(),
|
||||
VersionAndEditions = new VersionAndEditionsSection(),
|
||||
EDC = new EDCSection(),
|
||||
ParentCloneRelationship = new ParentCloneRelationshipSection(),
|
||||
Extras = new ExtrasSection(),
|
||||
CopyProtection = new CopyProtectionSection(),
|
||||
DumpersAndStatus = new DumpersAndStatusSection(),
|
||||
TracksAndWriteOffsets = new TracksAndWriteOffsetsSection(),
|
||||
SizeAndChecksums = new SizeAndChecksumsSection(),
|
||||
};
|
||||
|
||||
string json = JsonConvert.SerializeObject(submissionInfo, Formatting.Indented);
|
||||
Assert.NotNull(json);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FullSerializationTest()
|
||||
{
|
||||
var submissionInfo = new SubmissionInfo()
|
||||
{
|
||||
SchemaVersion = 1,
|
||||
FullyMatchedID = 3,
|
||||
PartiallyMatchedIDs = new List<int> { 0, 1, 2, 3 },
|
||||
Added = DateTime.UtcNow,
|
||||
LastModified = DateTime.UtcNow,
|
||||
|
||||
CommonDiscInfo = new CommonDiscInfoSection()
|
||||
{
|
||||
System = RedumpSystem.IBMPCcompatible,
|
||||
Media = DiscType.CD,
|
||||
Title = "Game Title",
|
||||
ForeignTitleNonLatin = "Foreign Game Title",
|
||||
DiscNumberLetter = "1",
|
||||
DiscTitle = "Install Disc",
|
||||
Category = DiscCategory.Games,
|
||||
Region = Region.World,
|
||||
Languages = new Language?[] { Language.English, Language.Spanish, Language.French },
|
||||
LanguageSelection = new LanguageSelection?[] { LanguageSelection.BiosSettings },
|
||||
Serial = "Disc Serial",
|
||||
Layer0MasteringRing = "L0 Mastering Ring",
|
||||
Layer0MasteringSID = "L0 Mastering SID",
|
||||
Layer0ToolstampMasteringCode = "L0 Toolstamp",
|
||||
Layer0MouldSID = "L0 Mould SID",
|
||||
Layer0AdditionalMould = "L0 Additional Mould",
|
||||
Layer1MasteringRing = "L1 Mastering Ring",
|
||||
Layer1MasteringSID = "L1 Mastering SID",
|
||||
Layer1ToolstampMasteringCode = "L1 Toolstamp",
|
||||
Layer1MouldSID = "L1 Mould SID",
|
||||
Layer1AdditionalMould = "L1 Additional Mould",
|
||||
Layer2MasteringRing = "L2 Mastering Ring",
|
||||
Layer2MasteringSID = "L2 Mastering SID",
|
||||
Layer2ToolstampMasteringCode = "L2 Toolstamp",
|
||||
Layer3MasteringRing = "L3 Mastering Ring",
|
||||
Layer3MasteringSID = "L3 Mastering SID",
|
||||
Layer3ToolstampMasteringCode = "L3 Toolstamp",
|
||||
RingWriteOffset = "+12",
|
||||
Barcode = "UPC Barcode",
|
||||
EXEDateBuildDate = "19xx-xx-xx",
|
||||
ErrorsCount = "0",
|
||||
Comments = "Comment data line 1\r\nComment data line 2",
|
||||
CommentsSpecialFields = new Dictionary<SiteCode?, string>()
|
||||
{
|
||||
[SiteCode.ISBN] = "ISBN",
|
||||
},
|
||||
Contents = "Special contents 1\r\nSpecial contents 2",
|
||||
ContentsSpecialFields = new Dictionary<SiteCode?, string>()
|
||||
{
|
||||
[SiteCode.PlayableDemos] = "Game Demo 1",
|
||||
},
|
||||
},
|
||||
|
||||
VersionAndEditions = new VersionAndEditionsSection()
|
||||
{
|
||||
Version = "Original",
|
||||
VersionDatfile = "Alt",
|
||||
CommonEditions = new string[] { "Taikenban" },
|
||||
OtherEditions = "Rerelease",
|
||||
},
|
||||
|
||||
EDC = new EDCSection()
|
||||
{
|
||||
EDC = YesNo.Yes,
|
||||
},
|
||||
|
||||
ParentCloneRelationship = new ParentCloneRelationshipSection()
|
||||
{
|
||||
ParentID = "12345",
|
||||
RegionalParent = false,
|
||||
},
|
||||
|
||||
Extras = new ExtrasSection()
|
||||
{
|
||||
PVD = "PVD",
|
||||
DiscKey = "Disc key",
|
||||
DiscID = "Disc ID",
|
||||
PIC = "PIC",
|
||||
Header = "Header",
|
||||
BCA = "BCA",
|
||||
SecuritySectorRanges = "SSv1 Ranges",
|
||||
},
|
||||
|
||||
CopyProtection = new CopyProtectionSection()
|
||||
{
|
||||
AntiModchip = YesNo.Yes,
|
||||
LibCrypt = YesNo.No,
|
||||
LibCryptData = "LibCrypt data",
|
||||
Protection = "List of protections",
|
||||
SecuROMData = "SecuROM data",
|
||||
},
|
||||
|
||||
DumpersAndStatus = new DumpersAndStatusSection()
|
||||
{
|
||||
Status = DumpStatus.TwoOrMoreGreen,
|
||||
Dumpers = new string[] { "Dumper1", "Dumper2" },
|
||||
OtherDumpers = "Dumper3",
|
||||
},
|
||||
|
||||
TracksAndWriteOffsets = new TracksAndWriteOffsetsSection()
|
||||
{
|
||||
ClrMameProData = "Datfile",
|
||||
Cuesheet = "Cuesheet",
|
||||
CommonWriteOffsets = new int[] { 0, 12, -12 },
|
||||
OtherWriteOffsets = "-2",
|
||||
},
|
||||
|
||||
SizeAndChecksums = new SizeAndChecksumsSection()
|
||||
{
|
||||
Layerbreak = 0,
|
||||
Layerbreak2 = 1,
|
||||
Layerbreak3 = 2,
|
||||
Size = 12345,
|
||||
CRC32 = "CRC32",
|
||||
MD5 = "MD5",
|
||||
SHA1 = "SHA1",
|
||||
},
|
||||
|
||||
DumpingInfo = new DumpingInfoSection()
|
||||
{
|
||||
DumpingProgram = "DiscImageCreator 20500101",
|
||||
Manufacturer = "ATAPI",
|
||||
Model = "Optical Drive",
|
||||
Firmware = "1.23",
|
||||
ReportedDiscType = "CD-R",
|
||||
},
|
||||
|
||||
Artifacts = new Dictionary<string, string>()
|
||||
{
|
||||
["Sample Artifact"] = "Sample Data",
|
||||
},
|
||||
};
|
||||
|
||||
string json = JsonConvert.SerializeObject(submissionInfo, Formatting.Indented);
|
||||
Assert.NotNull(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using MPF.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test
|
||||
{
|
||||
public class ResultTest
|
||||
{
|
||||
[Fact]
|
||||
public void ResultSuccessTest()
|
||||
{
|
||||
Result actual = Result.Success();
|
||||
Assert.Empty(actual.Message);
|
||||
|
||||
string message = "Success!";
|
||||
actual = Result.Success(message);
|
||||
Assert.Equal(message, actual.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResultFailureTest()
|
||||
{
|
||||
Result actual = Result.Failure();
|
||||
Assert.Empty(actual.Message);
|
||||
|
||||
string message = "Failure!";
|
||||
actual = Result.Failure(message);
|
||||
Assert.Equal(message, actual.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Linq;
|
||||
using MPF.Data;
|
||||
using MPF.Core.Data;
|
||||
using RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Data
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MPF.Data;
|
||||
using MPF.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Utilities
|
||||
{
|
||||
public class ConvertersTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Set of all known systems for testing
|
||||
/// </summary>
|
||||
public static IEnumerable<object[]> KnownSystems = KnownSystemComboBoxItem.GenerateElements().Select(e => new object[] { e });
|
||||
|
||||
[Theory]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Audio, MediaType.CDROM)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.BluRay, MediaType.BluRay)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Close, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.CompactDisc, MediaType.CDROM)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Data, MediaType.CDROM)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.DigitalVideoDisc, MediaType.DVD)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Eject, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Floppy, MediaType.FloppyDisk)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.GDROM, MediaType.GDROM)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.MDS, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Reset, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.SACD, MediaType.CDROM)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Start, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Stop, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Sub, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Swap, MediaType.GDROM)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.XBOX, MediaType.DVD)]
|
||||
public void BaseCommandToMediaTypeTest(string command, MediaType? expected)
|
||||
{
|
||||
MediaType? actual = DiscImageCreator.Converters.ToMediaType(command);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Audio, KnownSystem.AudioCD)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.BluRay, KnownSystem.SonyPlayStation3)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Close, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.CompactDisc, KnownSystem.IBMPCCompatible)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Data, KnownSystem.IBMPCCompatible)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.DigitalVideoDisc, KnownSystem.IBMPCCompatible)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Eject, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Floppy, KnownSystem.IBMPCCompatible)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.GDROM, KnownSystem.SegaDreamcast)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.MDS, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Reset, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.SACD, KnownSystem.SuperAudioCD)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Start, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Stop, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Sub, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Swap, KnownSystem.SegaDreamcast)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.XBOX, KnownSystem.MicrosoftXBOX)]
|
||||
public void BaseCommandToKnownSystemTest(string command, KnownSystem? expected)
|
||||
{
|
||||
KnownSystem? actual = DiscImageCreator.Converters.ToKnownSystem(command);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(MediaType.CDROM, ".bin")]
|
||||
[InlineData(MediaType.DVD, ".iso")]
|
||||
[InlineData(MediaType.LaserDisc, ".raw")]
|
||||
[InlineData(MediaType.NintendoWiiUOpticalDisc, ".wud")]
|
||||
[InlineData(MediaType.FloppyDisk, ".img")]
|
||||
[InlineData(MediaType.Cassette, ".wav")]
|
||||
[InlineData(MediaType.NONE, null)]
|
||||
public void MediaTypeToExtensionTest(MediaType? mediaType, string expected)
|
||||
{
|
||||
string actual = DiscImageCreator.Converters.Extension(mediaType);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(MediaType.CDROM, "CD-ROM")]
|
||||
[InlineData(MediaType.LaserDisc, "LD-ROM / LV-ROM")]
|
||||
[InlineData(MediaType.NONE, "Unknown")]
|
||||
public void MediaTypeToStringTest(MediaType? mediaType, string expected)
|
||||
{
|
||||
string actual = Converters.LongName(mediaType);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(KnownSystem.MicrosoftXBOX, "Microsoft XBOX")]
|
||||
[InlineData(KnownSystem.NECPC88, "NEC PC-88")]
|
||||
[InlineData(KnownSystem.KonamiPython, "Konami Python")]
|
||||
[InlineData(KnownSystem.HDDVDVideo, "HD-DVD-Video")]
|
||||
[InlineData(KnownSystem.NONE, "Unknown")]
|
||||
public void KnownSystemToStringTest(KnownSystem? knownSystem, string expected)
|
||||
{
|
||||
string actual = Converters.LongName(knownSystem);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(KnownSystems))]
|
||||
public void KnownSystemHasValidCategory(KnownSystemComboBoxItem system)
|
||||
{
|
||||
KnownSystem[] markers = { KnownSystem.MarkerArcadeEnd, KnownSystem.MarkerDiscBasedConsoleEnd, /* KnownSystem.MarkerOtherConsoleEnd, */ KnownSystem.MarkerComputerEnd, KnownSystem.MarkerOtherEnd };
|
||||
|
||||
// Non-system items won't map
|
||||
if (system.IsHeader)
|
||||
return;
|
||||
|
||||
// NONE will never map
|
||||
if (system == KnownSystem.NONE)
|
||||
return;
|
||||
|
||||
// we check that the category is the first category value higher than the system
|
||||
KnownSystemCategory category = ((KnownSystem?)system).Category();
|
||||
KnownSystem marker = KnownSystem.NONE;
|
||||
|
||||
switch (category)
|
||||
{
|
||||
case KnownSystemCategory.Arcade: marker = KnownSystem.MarkerArcadeEnd; break;
|
||||
case KnownSystemCategory.DiscBasedConsole: marker = KnownSystem.MarkerDiscBasedConsoleEnd; break;
|
||||
/* case KnownSystemCategory.OtherConsole: marker = KnownSystem.MarkerOtherConsoleEnd; break; */
|
||||
case KnownSystemCategory.Computer: marker = KnownSystem.MarkerComputerEnd; break;
|
||||
case KnownSystemCategory.Other: marker = KnownSystem.MarkerOtherEnd; break;
|
||||
}
|
||||
|
||||
Assert.NotEqual(KnownSystem.NONE, marker);
|
||||
Assert.True(marker > system);
|
||||
|
||||
Array.ForEach(markers, mmarker =>
|
||||
{
|
||||
// a marker can be the same of the found one, or one of a category before or a category after but never in the middle between
|
||||
// the system and the mapped category
|
||||
Assert.True(mmarker == marker || mmarker < system || mmarker > marker);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
using System.IO;
|
||||
using MPF.Data;
|
||||
using MPF.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test
|
||||
{
|
||||
public class DumpEnvironmentTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(null, 'D', false, MediaType.NONE, false)]
|
||||
[InlineData("", 'D', false, MediaType.NONE, false)]
|
||||
[InlineData("cd F test.bin 8 /c2 20", 'F', false, MediaType.CDROM, true)]
|
||||
[InlineData("fd A test.img", 'A', true, MediaType.FloppyDisk, true)]
|
||||
[InlineData("dvd X test.iso 8 /raw", 'X', false, MediaType.FloppyDisk, false)]
|
||||
[InlineData("stop D", 'D', false, MediaType.DVD, true)]
|
||||
public void ParametersValidTest(string parameters, char letter, bool isFloppy, MediaType? mediaType, bool expected)
|
||||
{
|
||||
var options = new Options() { InternalProgram = InternalProgram.DiscImageCreator };
|
||||
var drive = isFloppy
|
||||
? new Drive(InternalDriveType.Floppy, new DriveInfo(letter.ToString()))
|
||||
: new Drive(InternalDriveType.Optical, new DriveInfo(letter.ToString()));
|
||||
|
||||
var env = new DumpEnvironment(options, string.Empty, string.Empty, drive, KnownSystem.IBMPCCompatible, mediaType, parameters);
|
||||
|
||||
bool actual = env.ParametersValid();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null, null, null)]
|
||||
[InlineData(" ", "", " ", "")]
|
||||
[InlineData("super", "blah.bin", "super", "blah.bin")]
|
||||
[InlineData("super\\hero", "blah.bin", "super\\hero", "blah.bin")]
|
||||
[InlineData("super.hero", "blah.bin", "super.hero", "blah.bin")]
|
||||
[InlineData("superhero", "blah.rev.bin", "superhero", "blah.rev.bin")]
|
||||
[InlineData("super&hero", "blah.bin", "super&hero", "blah.bin")]
|
||||
[InlineData("superhero", "blah&foo.bin", "superhero", "blah&foo.bin")]
|
||||
public void FixOutputPathsTest(string outputDirectory, string outputFilename, string expectedOutputDirectory, string expectedOutputFilename)
|
||||
{
|
||||
(string actualOutputDirectory, string actualOutputFilename) = DumpEnvironment.NormalizeOutputPaths(outputDirectory, outputFilename, false);
|
||||
Assert.Equal(expectedOutputDirectory, actualOutputDirectory);
|
||||
Assert.Equal(expectedOutputFilename, actualOutputFilename);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFirstTrackTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatOutputDataTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteOutputDataTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EjectDiscTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CancelDumpingTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StartDumpingTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
using System;
|
||||
using MPF.Data;
|
||||
using MPF.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Utilities
|
||||
{
|
||||
public class KnownSystemExtensionsTest
|
||||
{
|
||||
[Fact]
|
||||
public void IsMarkerTest()
|
||||
{
|
||||
var values = (KnownSystem[])Enum.GetValues(typeof(KnownSystem));
|
||||
foreach(var system in values)
|
||||
{
|
||||
bool expected = system == KnownSystem.MarkerArcadeEnd || system == KnownSystem.MarkerComputerEnd ||
|
||||
system == KnownSystem.MarkerOtherEnd || system == KnownSystem.MarkerDiscBasedConsoleEnd;
|
||||
// || system == KnownSystem.MarkerOtherConsoleEnd;
|
||||
|
||||
bool actual = ((KnownSystem?)system).IsMarker();
|
||||
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CategoryNameNotEmptyTest()
|
||||
{
|
||||
var values = (KnownSystemCategory[])Enum.GetValues(typeof(KnownSystemCategory));
|
||||
foreach (var system in values)
|
||||
{
|
||||
string actual = ((KnownSystem?)system).LongName();
|
||||
Assert.NotEqual("", actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
using MPF.Data;
|
||||
using MPF.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Utilities
|
||||
{
|
||||
public class MediaTypeExtensionsTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(MediaType.CDROM, "CD-ROM")]
|
||||
[InlineData(MediaType.LaserDisc, "LD-ROM / LV-ROM")]
|
||||
[InlineData(MediaType.NONE, "Unknown")]
|
||||
public void NameTest(MediaType? mediaType, string expected)
|
||||
{
|
||||
string actual = mediaType.LongName();
|
||||
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(MediaType.CDROM, ".bin")]
|
||||
[InlineData(MediaType.DVD, ".iso")]
|
||||
[InlineData(MediaType.LaserDisc, ".raw")]
|
||||
[InlineData(MediaType.FloppyDisk, ".img")]
|
||||
[InlineData(MediaType.NONE, null)]
|
||||
public void ExtensionTest(MediaType? mediaType, string expected)
|
||||
{
|
||||
string actual = DiscImageCreator.Converters.Extension(mediaType);
|
||||
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(MediaType.CDROM, true)]
|
||||
[InlineData(MediaType.DVD, true)]
|
||||
[InlineData(MediaType.FloppyDisk, false)]
|
||||
[InlineData(MediaType.BluRay, true)]
|
||||
[InlineData(MediaType.LaserDisc, false)]
|
||||
public void DriveSpeedSupportedTest(MediaType? mediaType, bool expected)
|
||||
{
|
||||
bool actual = mediaType.DoesSupportDriveSpeed();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MPF.Data;
|
||||
using MPF.DiscImageCreator;
|
||||
using MPF.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Utilities
|
||||
{
|
||||
public class ParametersTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(KnownSystem.MicrosoftXBOX, MediaType.CDROM, CommandStrings.CompactDisc)]
|
||||
[InlineData(KnownSystem.MicrosoftXBOX, MediaType.DVD, CommandStrings.XBOX)]
|
||||
[InlineData(KnownSystem.MicrosoftXBOX, MediaType.LaserDisc, null)]
|
||||
[InlineData(KnownSystem.SegaNu, MediaType.BluRay, CommandStrings.BluRay)]
|
||||
[InlineData(KnownSystem.AppleMacintosh, MediaType.FloppyDisk, CommandStrings.Floppy)]
|
||||
[InlineData(KnownSystem.RawThrillsVarious, MediaType.GDROM, null)]
|
||||
public void ParametersFromSystemAndTypeTest(KnownSystem? knownSystem, MediaType? mediaType, string expected)
|
||||
{
|
||||
var options = new Options { };
|
||||
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, options);
|
||||
Assert.Equal(expected, actual.BaseCommand);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(KnownSystem.AppleMacintosh, MediaType.LaserDisc, true, 20, null, null)]
|
||||
[InlineData(KnownSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc, false, 20, null, new string[] { FlagStrings.Raw })]
|
||||
[InlineData(KnownSystem.IBMPCCompatible, MediaType.DVD, false, 20, null, new string[] { FlagStrings.CopyrightManagementInformation, FlagStrings.ScanFileProtect })]
|
||||
/* paranoid mode tests */
|
||||
[InlineData(KnownSystem.IBMPCCompatible, MediaType.CDROM, true, 1000, 2, new string[] { FlagStrings.C2Opcode, FlagStrings.NoFixSubQSecuROM, FlagStrings.ScanFileProtect, FlagStrings.ScanSectorProtect, FlagStrings.SubchannelReadLevel })]
|
||||
[InlineData(KnownSystem.AppleMacintosh, MediaType.CDROM, false, 20, null, new string[] { FlagStrings.C2Opcode, FlagStrings.NoFixSubQSecuROM, FlagStrings.ScanFileProtect, FlagStrings.ScanSectorProtect, FlagStrings.SubchannelReadLevel })]
|
||||
[InlineData(KnownSystem.IBMPCCompatible, MediaType.DVD, true, 500, null, new string[] { FlagStrings.CopyrightManagementInformation, FlagStrings.ScanFileProtect })]
|
||||
[InlineData(KnownSystem.HDDVDVideo, MediaType.HDDVD, true, 500, null, new string[] { FlagStrings.CopyrightManagementInformation })]
|
||||
[InlineData(KnownSystem.IBMPCCompatible, MediaType.DVD, false, 500, null, new string[] { FlagStrings.CopyrightManagementInformation, FlagStrings.ScanFileProtect })]
|
||||
[InlineData(KnownSystem.HDDVDVideo, MediaType.HDDVD, false, 500, null, new string[] { FlagStrings.CopyrightManagementInformation })]
|
||||
/* reread c2 */
|
||||
[InlineData(KnownSystem.SegaDreamcast, MediaType.GDROM, false, 1000, null, new string[] { FlagStrings.C2Opcode })]
|
||||
[InlineData(KnownSystem.SegaDreamcast, MediaType.GDROM, false, -1, null, new string[] { FlagStrings.C2Opcode })]
|
||||
|
||||
public void ParametersFromOptionsTest(KnownSystem? knownSystem, MediaType? mediaType, bool paranoid, int rereadC2, int? subchannelLevel, string[] expected)
|
||||
{
|
||||
var options = new Options { DICParanoidMode = paranoid, DICRereadCount = rereadC2 };
|
||||
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, options);
|
||||
|
||||
HashSet<string> expectedSet = new HashSet<string>(expected ?? new string[0]);
|
||||
HashSet<string> actualSet = new HashSet<string>(actual.Keys.Cast<string>() ?? new string[0]);
|
||||
Assert.Equal(expectedSet, actualSet);
|
||||
if (rereadC2 == -1 || !Validators.GetValidMediaTypes(knownSystem).Contains(mediaType))
|
||||
Assert.Null(actual.C2OpcodeValue[0]);
|
||||
else
|
||||
Assert.Equal(rereadC2, actual.C2OpcodeValue[0]);
|
||||
Assert.Equal(subchannelLevel, actual.SubchannelReadLevelValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, false)]
|
||||
[InlineData("", false)]
|
||||
[InlineData("cd F test.bin 8 /c2 20", true)]
|
||||
[InlineData("fd A test.img", true)]
|
||||
[InlineData("dvd X super\\test.iso 8 /raw", true)]
|
||||
[InlineData("bd D longer\\path_test.iso 16", true)]
|
||||
[InlineData("stop D", true)]
|
||||
[InlineData("ls", false)]
|
||||
public void ValidateParametersTest(string parameters, bool expected)
|
||||
{
|
||||
var actual = new Parameters(parameters);
|
||||
Assert.Equal(expected, actual.IsValid());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using MPF.Data;
|
||||
using MPF.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Utilities
|
||||
{
|
||||
public class ValidatorsTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(KnownSystem.BandaiApplePippin, MediaType.CDROM)]
|
||||
[InlineData(KnownSystem.MicrosoftXBOX, MediaType.DVD)]
|
||||
[InlineData(KnownSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc)]
|
||||
[InlineData(KnownSystem.NintendoWii, MediaType.NintendoWiiOpticalDisc)]
|
||||
[InlineData(KnownSystem.NintendoWiiU, MediaType.NintendoWiiUOpticalDisc)]
|
||||
[InlineData(KnownSystem.SonyPlayStationPortable, MediaType.UMD)]
|
||||
public void GetValidMediaTypesTest(KnownSystem? knownSystem, MediaType? expected)
|
||||
{
|
||||
var actual = Validators.GetValidMediaTypes(knownSystem);
|
||||
Assert.Contains(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateListOfSystemsTest()
|
||||
{
|
||||
int expected = Enum.GetValues(typeof(KnownSystem)).Length;
|
||||
var actual = KnownSystemComboBoxItem.GenerateElements().ToList();
|
||||
Assert.Equal(expected, actual.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateListOfDrivesTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDiscTypeTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MPF.Utilities;
|
||||
using MPF.Core.Converters;
|
||||
|
||||
namespace MPF
|
||||
namespace MPF.UI.Core.ComboBoxItems
|
||||
{
|
||||
/// <summary>
|
||||
/// A generic combo box element
|
||||
@@ -22,7 +22,7 @@ namespace MPF
|
||||
public static implicit operator T? (Element<T> item) => item?.Data;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => Converters.GetLongName(Data);
|
||||
public string Name => EnumConverter.GetLongName(Data);
|
||||
|
||||
public override string ToString() => Name;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace MPF
|
||||
namespace MPF.UI.Core.ComboBoxItems
|
||||
{
|
||||
public interface IElement
|
||||
{
|
||||
|
Before Width: | Height: | Size: 423 KiB After Width: | Height: | Size: 423 KiB |
BIN
MPF.UI.Core/Images/ring-code-guide-2-layer.png
Normal file
BIN
MPF.UI.Core/Images/ring-code-guide-2-layer.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
62
MPF.UI.Core/MPF.UI.Core.csproj
Normal file
62
MPF.UI.Core/MPF.UI.Core.csproj
Normal file
@@ -0,0 +1,62 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net48;net6.0-windows</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win7-x64;win8-x64;win81-x64;win10-x64</RuntimeIdentifiers>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<UseWPF>true</UseWPF>
|
||||
<Title>MPF.UI.Core</Title>
|
||||
<AssemblyName>MPF.UI.Core</AssemblyName>
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
<Copyright>Copyright (c)2019-2023</Copyright>
|
||||
<Version>2.6.2</Version>
|
||||
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||
<FileVersion>$(Version)</FileVersion>
|
||||
<IncludeSource>true</IncludeSource>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<NrtRevisionFormat>$(Version)-{chash:8}</NrtRevisionFormat>
|
||||
<NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes>
|
||||
<NrtShowRevision>false</NrtShowRevision>
|
||||
<UserSecretsId>27abb4ca-bf7a-431e-932f-49153303d5ff</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Resource Include="Images\ring-code-guide-1-layer.png" />
|
||||
<Resource Include="Images\ring-code-guide-2-layer.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
|
||||
<ProjectReference Include="..\RedumpLib\RedumpLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="PresentationFramework.Aero" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Images\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="UserControls\UserInput.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
<Page Update="Windows\DiscInformationWindow.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
<Page Update="Windows\RingCodeGuideWindow.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
400
MPF.UI.Core/Theme.cs
Normal file
400
MPF.UI.Core/Theme.cs
Normal file
@@ -0,0 +1,400 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MPF.UI.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents all required mapping values for the UI
|
||||
/// </summary>
|
||||
public class Theme
|
||||
{
|
||||
#region Application-Wide
|
||||
|
||||
/// <summary>
|
||||
/// SolidColorBrush used to paint the active window's border.
|
||||
/// </summary>
|
||||
public SolidColorBrush ActiveBorderBrush { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// SolidColorBrush that paints the face of a three-dimensional display element.
|
||||
/// </summary>
|
||||
public SolidColorBrush ControlBrush { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// SolidColorBrush that paints text in a three-dimensional display element.
|
||||
/// </summary>
|
||||
public SolidColorBrush ControlTextBrush { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// SolidColorBrush that paints disabled text.
|
||||
/// </summary>
|
||||
public SolidColorBrush GrayTextBrush { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// SolidColorBrush that paints the background of a window's client area.
|
||||
/// </summary>
|
||||
public SolidColorBrush WindowBrush { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// SolidColorBrush that paints the text in the client area of a window.
|
||||
/// </summary>
|
||||
public SolidColorBrush WindowTextBrush { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Button
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the Button.Disabled.Background resource
|
||||
/// </summary>
|
||||
public Brush Button_Disabled_Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the Button.MouseOver.Background resource
|
||||
/// </summary>
|
||||
public Brush Button_MouseOver_Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the Button.Pressed.Background resource
|
||||
/// </summary>
|
||||
public Brush Button_Pressed_Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the Button.Static.Background resource
|
||||
/// </summary>
|
||||
public Brush Button_Static_Background { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ComboBox
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the ComboBox.Disabled.Background resource
|
||||
/// </summary>
|
||||
public Brush ComboBox_Disabled_Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the ComboBox.Disabled.Editable.Background resource
|
||||
/// </summary>
|
||||
public Brush ComboBox_Disabled_Editable_Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the ComboBox.Disabled.Editable.Button.Background resource
|
||||
/// </summary>
|
||||
public Brush ComboBox_Disabled_Editable_Button_Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the ComboBox.MouseOver.Background resource
|
||||
/// </summary>
|
||||
public Brush ComboBox_MouseOver_Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the ComboBox.MouseOver.Editable.Background resource
|
||||
/// </summary>
|
||||
public Brush ComboBox_MouseOver_Editable_Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the ComboBox.MouseOver.Editable.Button.Background resource
|
||||
/// </summary>
|
||||
public Brush ComboBox_MouseOver_Editable_Button_Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the ComboBox.Pressed.Background resource
|
||||
/// </summary>
|
||||
public Brush ComboBox_Pressed_Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the ComboBox.Pressed.Editable.Background resource
|
||||
/// </summary>
|
||||
public Brush ComboBox_Pressed_Editable_Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the ComboBox.Pressed.Editable.Button.Background resource
|
||||
/// </summary>
|
||||
public Brush ComboBox_Pressed_Editable_Button_Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the ComboBox.Static.Background resource
|
||||
/// </summary>
|
||||
public Brush ComboBox_Static_Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the ComboBox.Static.Editable.Background resource
|
||||
/// </summary>
|
||||
public Brush ComboBox_Static_Editable_Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the ComboBox.Static.Editable.Button.Background resource
|
||||
/// </summary>
|
||||
public Brush ComboBox_Static_Editable_Button_Background { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region CustomMessageBox
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the CustomMessageBox.Static.Background resource
|
||||
/// </summary>
|
||||
public Brush CustomMessageBox_Static_Background { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region MenuItem
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the MenuItem.SubMenu.Background resource
|
||||
/// </summary>
|
||||
public Brush MenuItem_SubMenu_Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the MenuItem.SubMenu.Border resource
|
||||
/// </summary>
|
||||
public Brush MenuItem_SubMenu_Border { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ProgressBar
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the ProgressBar.Background resource
|
||||
/// </summary>
|
||||
public Brush ProgressBar_Background { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ScrollViewer
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the ScrollViewer.ScrollBar.Background resource
|
||||
/// </summary>
|
||||
public Brush ScrollViewer_ScrollBar_Background { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region TabItem
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the TabItem.Selected.Background resource
|
||||
/// </summary>
|
||||
public Brush TabItem_Selected_Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the TabItem.Static.Background resource
|
||||
/// </summary>
|
||||
public Brush TabItem_Static_Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the TabItem.Static.Border resource
|
||||
/// </summary>
|
||||
public Brush TabItem_Static_Border { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region TextBox
|
||||
|
||||
/// <summary>
|
||||
/// Brush for the TextBox.Static.Background resource
|
||||
/// </summary>
|
||||
public Brush TextBox_Static_Background { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Apply the theme to the current application
|
||||
/// </summary>
|
||||
public void Apply()
|
||||
{
|
||||
// Handle application-wide resources
|
||||
Application.Current.Resources[SystemColors.ActiveBorderBrushKey] = this.ActiveBorderBrush;
|
||||
Application.Current.Resources[SystemColors.ControlBrushKey] = this.ControlBrush;
|
||||
Application.Current.Resources[SystemColors.ControlTextBrushKey] = this.ControlTextBrush;
|
||||
Application.Current.Resources[SystemColors.GrayTextBrushKey] = this.GrayTextBrush;
|
||||
Application.Current.Resources[SystemColors.WindowBrushKey] = this.WindowBrush;
|
||||
Application.Current.Resources[SystemColors.WindowTextBrushKey] = this.WindowTextBrush;
|
||||
|
||||
// Handle Button-specific resources
|
||||
Application.Current.Resources["Button.Disabled.Background"] = this.Button_Disabled_Background;
|
||||
Application.Current.Resources["Button.MouseOver.Background"] = this.Button_MouseOver_Background;
|
||||
Application.Current.Resources["Button.Pressed.Background"] = this.Button_Pressed_Background;
|
||||
Application.Current.Resources["Button.Static.Background"] = this.Button_Static_Background;
|
||||
|
||||
// Handle ComboBox-specific resources
|
||||
Application.Current.Resources["ComboBox.Disabled.Background"] = this.ComboBox_Disabled_Background;
|
||||
Application.Current.Resources["ComboBox.Disabled.Editable.Background"] = this.ComboBox_Disabled_Editable_Background;
|
||||
Application.Current.Resources["ComboBox.Disabled.Editable.Button.Background"] = this.ComboBox_Disabled_Editable_Button_Background;
|
||||
Application.Current.Resources["ComboBox.MouseOver.Background"] = this.ComboBox_MouseOver_Background;
|
||||
Application.Current.Resources["ComboBox.MouseOver.Editable.Background"] = this.ComboBox_MouseOver_Editable_Background;
|
||||
Application.Current.Resources["ComboBox.MouseOver.Editable.Button.Background"] = this.ComboBox_MouseOver_Editable_Button_Background;
|
||||
Application.Current.Resources["ComboBox.Pressed.Background"] = this.ComboBox_Pressed_Background;
|
||||
Application.Current.Resources["ComboBox.Pressed.Editable.Background"] = this.ComboBox_Pressed_Editable_Background;
|
||||
Application.Current.Resources["ComboBox.Pressed.Editable.Button.Background"] = this.ComboBox_Pressed_Editable_Button_Background;
|
||||
Application.Current.Resources["ComboBox.Static.Background"] = this.ComboBox_Static_Background;
|
||||
Application.Current.Resources["ComboBox.Static.Editable.Background"] = this.ComboBox_Static_Editable_Background;
|
||||
Application.Current.Resources["ComboBox.Static.Editable.Button.Background"] = this.ComboBox_Static_Editable_Button_Background;
|
||||
|
||||
// Handle CustomMessageBox-specific resources
|
||||
Application.Current.Resources["CustomMessageBox.Static.Background"] = this.CustomMessageBox_Static_Background;
|
||||
|
||||
// Handle MenuItem-specific resources
|
||||
Application.Current.Resources["MenuItem.SubMenu.Background"] = this.MenuItem_SubMenu_Background;
|
||||
Application.Current.Resources["MenuItem.SubMenu.Border"] = this.MenuItem_SubMenu_Border;
|
||||
|
||||
// Handle ProgressBar-specific resources
|
||||
Application.Current.Resources["ProgressBar.Background"] = this.ProgressBar_Background;
|
||||
|
||||
// Handle ScrollViewer-specific resources
|
||||
Application.Current.Resources["ScrollViewer.ScrollBar.Background"] = this.ScrollViewer_ScrollBar_Background;
|
||||
|
||||
// Handle TabItem-specific resources
|
||||
Application.Current.Resources["TabItem.Selected.Background"] = this.TabItem_Selected_Background;
|
||||
Application.Current.Resources["TabItem.Static.Background"] = this.TabItem_Static_Background;
|
||||
Application.Current.Resources["TabItem.Static.Border"] = this.TabItem_Static_Border;
|
||||
|
||||
// Handle TextBox-specific resources
|
||||
Application.Current.Resources["TextBox.Static.Background"] = this.TextBox_Static_Background;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default light-mode theme
|
||||
/// </summary>
|
||||
public class LightModeTheme : Theme
|
||||
{
|
||||
public LightModeTheme()
|
||||
{
|
||||
// Handle application-wide resources
|
||||
this.ActiveBorderBrush = null;
|
||||
this.ControlBrush = null;
|
||||
this.ControlTextBrush = null;
|
||||
this.GrayTextBrush = null;
|
||||
this.WindowBrush = null;
|
||||
this.WindowTextBrush = null;
|
||||
|
||||
// Handle Button-specific resources
|
||||
this.Button_Disabled_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xF4, 0xF4, 0xF4));
|
||||
this.Button_MouseOver_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xBE, 0xE6, 0xFD));
|
||||
this.Button_Pressed_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xC4, 0xE5, 0xF6));
|
||||
this.Button_Static_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xDD, 0xDD, 0xDD));
|
||||
|
||||
// Handle ComboBox-specific resources
|
||||
this.ComboBox_Disabled_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xF0, 0xF0, 0xF0));
|
||||
this.ComboBox_Disabled_Editable_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF));
|
||||
this.ComboBox_Disabled_Editable_Button_Background = Brushes.Transparent;
|
||||
this.ComboBox_MouseOver_Background = new LinearGradientBrush(
|
||||
Color.FromArgb(0xFF, 0xEC, 0xF4, 0xFC),
|
||||
Color.FromArgb(0xFF, 0xDC, 0xEC, 0xFC),
|
||||
new Point(0, 0),
|
||||
new Point(0, 1));
|
||||
this.ComboBox_MouseOver_Editable_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF));
|
||||
this.ComboBox_MouseOver_Editable_Button_Background = new LinearGradientBrush(
|
||||
Color.FromArgb(0xFF, 0xEB, 0xF4, 0xFC),
|
||||
Color.FromArgb(0xFF, 0xDC, 0xEC, 0xFC),
|
||||
new Point(0, 0),
|
||||
new Point(0, 1));
|
||||
this.ComboBox_Pressed_Background = new LinearGradientBrush(
|
||||
Color.FromArgb(0xFF, 0xDA, 0xEC, 0xFC),
|
||||
Color.FromArgb(0xFF, 0xC4, 0xE0, 0xFC),
|
||||
new Point(0, 0),
|
||||
new Point(0, 1));
|
||||
this.ComboBox_Pressed_Editable_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF));
|
||||
this.ComboBox_Pressed_Editable_Button_Background = new LinearGradientBrush(
|
||||
Color.FromArgb(0xFF, 0xDA, 0xEB, 0xFC),
|
||||
Color.FromArgb(0xFF, 0xC4, 0xE0, 0xFC),
|
||||
new Point(0, 0),
|
||||
new Point(0, 1));
|
||||
this.ComboBox_Static_Background = new LinearGradientBrush(
|
||||
Color.FromArgb(0xFF, 0xF0, 0xF0, 0xF0),
|
||||
Color.FromArgb(0xFF, 0xE5, 0xE5, 0xE5),
|
||||
new Point(0, 0),
|
||||
new Point(0, 1));
|
||||
this.ComboBox_Static_Editable_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF));
|
||||
this.ComboBox_Static_Editable_Button_Background = Brushes.Transparent;
|
||||
|
||||
// Handle CustomMessageBox-specific resources
|
||||
this.CustomMessageBox_Static_Background = null;
|
||||
|
||||
// Handle MenuItem-specific resources
|
||||
this.MenuItem_SubMenu_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xF0, 0xF0, 0xF0));
|
||||
this.MenuItem_SubMenu_Border = Brushes.DarkGray;
|
||||
|
||||
// Handle ProgressBar-specific resources
|
||||
this.ProgressBar_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xE6, 0xE6, 0xE6));
|
||||
|
||||
// Handle ScrollViewer-specific resources
|
||||
this.ScrollViewer_ScrollBar_Background = Brushes.LightGray;
|
||||
|
||||
// Handle TabItem-specific resources
|
||||
this.TabItem_Selected_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF));
|
||||
this.TabItem_Static_Background = new LinearGradientBrush(
|
||||
Color.FromArgb(0xFF, 0xF0, 0xF0, 0xF0),
|
||||
Color.FromArgb(0xFF, 0xE5, 0xE5, 0xE5),
|
||||
new Point(0, 0),
|
||||
new Point(0, 1));
|
||||
this.TabItem_Static_Border = Brushes.DarkGray;
|
||||
|
||||
// Handle TextBox-specific resources
|
||||
this.TextBox_Static_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default dark-mode theme
|
||||
/// </summary>
|
||||
public class DarkModeTheme : Theme
|
||||
{
|
||||
public DarkModeTheme()
|
||||
{
|
||||
// Setup needed brushes
|
||||
var darkModeBrush = new SolidColorBrush { Color = Color.FromArgb(0xff, 0x20, 0x20, 0x20) };
|
||||
|
||||
// Handle application-wide resources
|
||||
this.ActiveBorderBrush = Brushes.Black;
|
||||
this.ControlBrush = darkModeBrush;
|
||||
this.ControlTextBrush = Brushes.White;
|
||||
this.GrayTextBrush = Brushes.DarkGray;
|
||||
this.WindowBrush = darkModeBrush;
|
||||
this.WindowTextBrush = Brushes.White;
|
||||
|
||||
// Handle Button-specific resources
|
||||
this.Button_Disabled_Background = darkModeBrush;
|
||||
this.Button_MouseOver_Background = darkModeBrush;
|
||||
this.Button_Pressed_Background = darkModeBrush;
|
||||
this.Button_Static_Background = darkModeBrush;
|
||||
|
||||
// Handle ComboBox-specific resources
|
||||
this.ComboBox_Disabled_Background = darkModeBrush;
|
||||
this.ComboBox_Disabled_Editable_Background = darkModeBrush;
|
||||
this.ComboBox_Disabled_Editable_Button_Background = darkModeBrush;
|
||||
this.ComboBox_MouseOver_Background = darkModeBrush;
|
||||
this.ComboBox_MouseOver_Editable_Background = darkModeBrush;
|
||||
this.ComboBox_MouseOver_Editable_Button_Background = darkModeBrush;
|
||||
this.ComboBox_Pressed_Background = darkModeBrush;
|
||||
this.ComboBox_Pressed_Editable_Background = darkModeBrush;
|
||||
this.ComboBox_Pressed_Editable_Button_Background = darkModeBrush;
|
||||
this.ComboBox_Static_Background = darkModeBrush;
|
||||
this.ComboBox_Static_Editable_Background = darkModeBrush;
|
||||
this.ComboBox_Static_Editable_Button_Background = darkModeBrush;
|
||||
|
||||
// Handle CustomMessageBox-specific resources
|
||||
this.CustomMessageBox_Static_Background = darkModeBrush;
|
||||
|
||||
// Handle MenuItem-specific resources
|
||||
this.MenuItem_SubMenu_Background = darkModeBrush;
|
||||
this.MenuItem_SubMenu_Border = Brushes.DarkGray;
|
||||
|
||||
// Handle ProgressBar-specific resources
|
||||
this.ProgressBar_Background = darkModeBrush;
|
||||
|
||||
// Handle ScrollViewer-specific resources
|
||||
this.ScrollViewer_ScrollBar_Background = darkModeBrush;
|
||||
|
||||
// Handle TabItem-specific resources
|
||||
this.TabItem_Selected_Background = darkModeBrush;
|
||||
this.TabItem_Static_Background = darkModeBrush;
|
||||
this.TabItem_Static_Border = Brushes.DarkGray;
|
||||
|
||||
// Handle TextBox-specific resources
|
||||
this.TextBox_Static_Background = darkModeBrush;
|
||||
}
|
||||
}
|
||||
}
|
||||
30
MPF.UI.Core/UserControls/UserInput.xaml
Normal file
30
MPF.UI.Core/UserControls/UserInput.xaml
Normal file
@@ -0,0 +1,30 @@
|
||||
<UserControl x:Class="MPF.UI.Core.UserControls.UserInput"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800" x:Name="userInput">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="0.75*" />
|
||||
<ColumnDefinition Width="1.25*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Right"
|
||||
Content="{Binding ElementName=userInput, Path=Label}" />
|
||||
|
||||
<TextBox Grid.Row="0" Grid.Column="1"
|
||||
Height="{Binding ElementName=userInput, Path=TextHeight}"
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding ElementName=userInput, Path=Text}"
|
||||
AcceptsTab="{Binding ElementName=userInput, Path=Tab}"
|
||||
AcceptsReturn="{Binding ElementName=userInput, Path=Enter}"
|
||||
TextWrapping="{Binding ElementName=userInput, Path=TextWrapping}"
|
||||
IsReadOnly="{Binding ElementName=userInput, Path=IsReadOnly}"
|
||||
VerticalContentAlignment="{Binding ElementName=userInput, Path=VerticalContentAlignmentValue}"
|
||||
HorizontalScrollBarVisibility="{Binding ElementName=userInput, Path=HorizontalScrollBarVisibility}"
|
||||
VerticalScrollBarVisibility="{Binding ElementName=userInput, Path=VerticalScrollBarVisibility}"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
124
MPF.UI.Core/UserControls/UserInput.xaml.cs
Normal file
124
MPF.UI.Core/UserControls/UserInput.xaml.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace MPF.UI.Core.UserControls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for UserInput.xaml
|
||||
/// </summary>
|
||||
public partial class UserInput : UserControl
|
||||
{
|
||||
#region Dependency Properties
|
||||
|
||||
public static readonly DependencyProperty LabelProperty =
|
||||
DependencyProperty.Register("Label", typeof(string), typeof(UserInput));
|
||||
|
||||
public static readonly DependencyProperty TextProperty =
|
||||
DependencyProperty.Register("Text", typeof(string), typeof(UserInput));
|
||||
|
||||
public static readonly DependencyProperty TextHeightProperty =
|
||||
DependencyProperty.Register("TextHeight", typeof(string), typeof(UserInput));
|
||||
|
||||
public static readonly DependencyProperty TabProperty =
|
||||
DependencyProperty.Register("Tab", typeof(bool), typeof(UserInput));
|
||||
|
||||
public static readonly DependencyProperty EnterProperty =
|
||||
DependencyProperty.Register("Enter", typeof(bool), typeof(UserInput));
|
||||
|
||||
public static readonly DependencyProperty TextWrappingProperty =
|
||||
DependencyProperty.Register("TextWrapping", typeof(TextWrapping), typeof(UserInput));
|
||||
|
||||
public static readonly DependencyProperty IsReadOnlyProperty =
|
||||
DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(UserInput));
|
||||
|
||||
public static readonly DependencyProperty VerticalContentAlignmentValueProperty =
|
||||
DependencyProperty.Register("VerticalContentAlignmentValue", typeof(VerticalAlignment), typeof(UserInput));
|
||||
|
||||
public static readonly DependencyProperty HorizontalScrollBarVisibilityProperty =
|
||||
DependencyProperty.Register("HorizontalScrollBarVisibility", typeof(ScrollBarVisibility), typeof(UserInput));
|
||||
|
||||
public static readonly DependencyProperty VerticalScrollBarVisibilityProperty =
|
||||
DependencyProperty.Register("VerticalScrollBarVisibility", typeof(ScrollBarVisibility), typeof(UserInput));
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public string Label
|
||||
{
|
||||
get => (string)GetValue(LabelProperty);
|
||||
set => SetValue(LabelProperty, value);
|
||||
}
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => (string)GetValue(TextProperty);
|
||||
set => SetValue(TextProperty, value);
|
||||
}
|
||||
|
||||
public string TextHeight
|
||||
{
|
||||
get => (string)GetValue(TextHeightProperty);
|
||||
set => SetValue(TextHeightProperty, value);
|
||||
}
|
||||
|
||||
public bool Tab
|
||||
{
|
||||
get => (bool)GetValue(TabProperty);
|
||||
set => SetValue(TabProperty, value);
|
||||
}
|
||||
|
||||
public bool Enter
|
||||
{
|
||||
get => (bool)GetValue(EnterProperty);
|
||||
set => SetValue(EnterProperty, value);
|
||||
}
|
||||
|
||||
public TextWrapping TextWrapping
|
||||
{
|
||||
get => (TextWrapping)GetValue(TextWrappingProperty);
|
||||
set => SetValue(TextWrappingProperty, value);
|
||||
}
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get => (bool)GetValue(IsReadOnlyProperty);
|
||||
set => SetValue(IsReadOnlyProperty, value);
|
||||
}
|
||||
|
||||
public VerticalAlignment VerticalContentAlignmentValue
|
||||
{
|
||||
get => (VerticalAlignment)GetValue(VerticalContentAlignmentValueProperty);
|
||||
set => SetValue(VerticalContentAlignmentValueProperty, value);
|
||||
}
|
||||
|
||||
public ScrollBarVisibility HorizontalScrollBarVisibility
|
||||
{
|
||||
get => (ScrollBarVisibility)GetValue(HorizontalScrollBarVisibilityProperty);
|
||||
set => SetValue(HorizontalScrollBarVisibilityProperty, value);
|
||||
}
|
||||
|
||||
public ScrollBarVisibility VerticalScrollBarVisibility
|
||||
{
|
||||
get => (ScrollBarVisibility)GetValue(VerticalScrollBarVisibilityProperty);
|
||||
set => SetValue(VerticalScrollBarVisibilityProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public UserInput()
|
||||
{
|
||||
// Set default values
|
||||
TextHeight = "22";
|
||||
Tab = false;
|
||||
Enter = false;
|
||||
TextWrapping = TextWrapping.NoWrap;
|
||||
IsReadOnly = false;
|
||||
VerticalContentAlignmentValue = VerticalAlignment.Center;
|
||||
HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
|
||||
VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
|
||||
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
839
MPF.UI.Core/ViewModels/DiscInformationViewModel.cs
Normal file
839
MPF.UI.Core/ViewModels/DiscInformationViewModel.cs
Normal file
@@ -0,0 +1,839 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.Utilities;
|
||||
using MPF.UI.Core.ComboBoxItems;
|
||||
using MPF.UI.Core.Windows;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.UI.Core.ViewModels
|
||||
{
|
||||
public class DiscInformationViewModel
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Parent DiscInformationWindow object
|
||||
/// </summary>
|
||||
public DiscInformationWindow Parent { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Application-level Options object
|
||||
/// </summary>
|
||||
public Options Options { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// SubmissionInfo object to fill and save
|
||||
/// </summary>
|
||||
public SubmissionInfo SubmissionInfo { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Lists
|
||||
|
||||
/// <summary>
|
||||
/// List of available disc categories
|
||||
/// </summary>
|
||||
public List<Element<DiscCategory>> Categories { get; private set; } = Element<DiscCategory>.GenerateElements().ToList();
|
||||
|
||||
/// <summary>
|
||||
/// List of available regions
|
||||
/// </summary>
|
||||
public List<Element<Region>> Regions { get; private set; } = Element<Region>.GenerateElements().ToList();
|
||||
|
||||
/// <summary>
|
||||
/// List of Redump-supported Regions
|
||||
/// </summary>
|
||||
private static readonly List<Region> RedumpRegions = new List<Region>
|
||||
{
|
||||
Region.Argentina,
|
||||
Region.Asia,
|
||||
Region.AsiaEurope,
|
||||
Region.AsiaUSA,
|
||||
Region.Australia,
|
||||
Region.AustraliaGermany,
|
||||
Region.AustraliaNewZealand,
|
||||
Region.Austria,
|
||||
Region.AustriaSwitzerland,
|
||||
Region.Belarus,
|
||||
Region.Belgium,
|
||||
Region.BelgiumNetherlands,
|
||||
Region.Brazil,
|
||||
Region.Bulgaria,
|
||||
Region.Canada,
|
||||
Region.China,
|
||||
Region.Croatia,
|
||||
Region.Czechia,
|
||||
Region.Denmark,
|
||||
Region.Estonia,
|
||||
Region.Europe,
|
||||
Region.EuropeAsia,
|
||||
Region.EuropeAustralia,
|
||||
Region.EuropeCanada,
|
||||
Region.EuropeGermany,
|
||||
Region.Export,
|
||||
Region.Finland,
|
||||
Region.France,
|
||||
Region.FranceSpain,
|
||||
Region.Germany,
|
||||
Region.GreaterChina,
|
||||
Region.Greece,
|
||||
Region.Hungary,
|
||||
Region.Iceland,
|
||||
Region.India,
|
||||
Region.Ireland,
|
||||
Region.Israel,
|
||||
Region.Italy,
|
||||
Region.Japan,
|
||||
Region.JapanAsia,
|
||||
Region.JapanEurope,
|
||||
Region.JapanKorea,
|
||||
Region.JapanUSA,
|
||||
Region.SouthKorea,
|
||||
Region.LatinAmerica,
|
||||
Region.Lithuania,
|
||||
Region.Netherlands,
|
||||
Region.NewZealand,
|
||||
Region.Norway,
|
||||
Region.Poland,
|
||||
Region.Portugal,
|
||||
Region.Romania,
|
||||
Region.RussianFederation,
|
||||
Region.Scandinavia,
|
||||
Region.Serbia,
|
||||
Region.Singapore,
|
||||
Region.Slovakia,
|
||||
Region.SouthAfrica,
|
||||
Region.Spain,
|
||||
Region.SpainPortugal,
|
||||
Region.Sweden,
|
||||
Region.Switzerland,
|
||||
Region.Taiwan,
|
||||
Region.Thailand,
|
||||
Region.Turkey,
|
||||
Region.UnitedArabEmirates,
|
||||
Region.UnitedKingdom,
|
||||
Region.UKAustralia,
|
||||
Region.Ukraine,
|
||||
Region.UnitedStatesOfAmerica,
|
||||
Region.USAAsia,
|
||||
Region.USAAustralia,
|
||||
Region.USABrazil,
|
||||
Region.USACanada,
|
||||
Region.USAEurope,
|
||||
Region.USAGermany,
|
||||
Region.USAJapan,
|
||||
Region.USAKorea,
|
||||
Region.World,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of available languages
|
||||
/// </summary>
|
||||
public List<Element<Language>> Languages { get; private set; } = Element<Language>.GenerateElements().ToList();
|
||||
|
||||
/// <summary>
|
||||
/// List of Redump-supported Languages
|
||||
/// </summary>
|
||||
private static readonly List<Language> RedumpLanguages = new List<Language>
|
||||
{
|
||||
Language.Afrikaans,
|
||||
Language.Albanian,
|
||||
Language.Arabic,
|
||||
Language.Armenian,
|
||||
Language.Basque,
|
||||
Language.Belarusian,
|
||||
Language.Bulgarian,
|
||||
Language.Catalan,
|
||||
Language.Chinese,
|
||||
Language.Croatian,
|
||||
Language.Czech,
|
||||
Language.Danish,
|
||||
Language.Dutch,
|
||||
Language.English,
|
||||
Language.Estonian,
|
||||
Language.Finnish,
|
||||
Language.French,
|
||||
Language.Gaelic,
|
||||
Language.German,
|
||||
Language.Greek,
|
||||
Language.Hebrew,
|
||||
Language.Hindi,
|
||||
Language.Hungarian,
|
||||
Language.Icelandic,
|
||||
Language.Indonesian,
|
||||
Language.Italian,
|
||||
Language.Japanese,
|
||||
Language.Korean,
|
||||
Language.Latin,
|
||||
Language.Latvian,
|
||||
Language.Lithuanian,
|
||||
Language.Macedonian,
|
||||
Language.Norwegian,
|
||||
Language.Polish,
|
||||
Language.Portuguese,
|
||||
Language.Panjabi,
|
||||
Language.Romanian,
|
||||
Language.Russian,
|
||||
Language.Serbian,
|
||||
Language.Slovak,
|
||||
Language.Slovenian,
|
||||
Language.Spanish,
|
||||
Language.Swedish,
|
||||
Language.Tamil,
|
||||
Language.Thai,
|
||||
Language.Turkish,
|
||||
Language.Ukrainian,
|
||||
Language.Vietnamese,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of available languages
|
||||
/// </summary>
|
||||
public List<Element<LanguageSelection>> LanguageSelections { get; private set; } = Element<LanguageSelection>.GenerateElements().ToList();
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public DiscInformationViewModel(DiscInformationWindow parent, Options options, SubmissionInfo submissionInfo)
|
||||
{
|
||||
Parent = parent;
|
||||
Options = options;
|
||||
SubmissionInfo = submissionInfo.Clone() as SubmissionInfo ?? new SubmissionInfo();
|
||||
|
||||
// Limit lists, if necessary
|
||||
if (this.Options.EnableRedumpCompatibility)
|
||||
{
|
||||
SetRedumpRegions();
|
||||
SetRedumpLanguages();
|
||||
}
|
||||
|
||||
// Add handlers
|
||||
Parent.AcceptButton.Click += OnAcceptClick;
|
||||
Parent.CancelButton.Click += OnCancelClick;
|
||||
Parent.RingCodeGuideButton.Click += OnRingCodeGuideClick;
|
||||
|
||||
// Update UI with new values
|
||||
ManipulateFields();
|
||||
Load();
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Enable tab entry on supported fields
|
||||
/// </summary>
|
||||
private void EnableTabsInInputFields()
|
||||
{
|
||||
// Additional Information
|
||||
Parent.CommentsTextBox.Tab = true;
|
||||
|
||||
// Contents
|
||||
Parent.GeneralContent.Tab = true;
|
||||
Parent.GamesTextBox.Tab = true;
|
||||
Parent.NetYarozeGamesTextBox.Tab = true;
|
||||
Parent.PlayableDemosTextBox.Tab = true;
|
||||
Parent.RollingDemosTextBox.Tab = true;
|
||||
Parent.TechDemosTextBox.Tab = true;
|
||||
Parent.GameFootageTextBox.Tab = true;
|
||||
Parent.VideosTextBox.Tab = true;
|
||||
Parent.PatchesTextBox.Tab = true;
|
||||
Parent.SavegamesTextBox.Tab = true;
|
||||
Parent.ExtrasTextBox.Tab = true;
|
||||
|
||||
// L0
|
||||
Parent.L0MasteringRing.Tab = true;
|
||||
Parent.L0MasteringSID.Tab = true;
|
||||
Parent.L0Toolstamp.Tab = true;
|
||||
Parent.L0MouldSID.Tab = true;
|
||||
Parent.L0AdditionalMould.Tab = true;
|
||||
|
||||
// L1
|
||||
Parent.L1MasteringRing.Tab = true;
|
||||
Parent.L1MasteringSID.Tab = true;
|
||||
Parent.L1Toolstamp.Tab = true;
|
||||
Parent.L1MouldSID.Tab = true;
|
||||
Parent.L1AdditionalMould.Tab = true;
|
||||
|
||||
// L2
|
||||
Parent.L2MasteringRing.Tab = true;
|
||||
Parent.L2MasteringSID.Tab = true;
|
||||
Parent.L2Toolstamp.Tab = true;
|
||||
|
||||
// L3
|
||||
Parent.L3MasteringRing.Tab = true;
|
||||
Parent.L3MasteringSID.Tab = true;
|
||||
Parent.L3Toolstamp.Tab = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hide any optional, read-only fields if they don't have a value
|
||||
/// </summary>
|
||||
private void HideReadOnlyFields()
|
||||
{
|
||||
if (SubmissionInfo?.FullyMatchedID == null)
|
||||
Parent.FullyMatchedID.Visibility = Visibility.Collapsed;
|
||||
else
|
||||
Parent.FullyMatchedID.Text = SubmissionInfo.FullyMatchedID.ToString();
|
||||
if (SubmissionInfo?.PartiallyMatchedIDs == null)
|
||||
Parent.PartiallyMatchedIDs.Visibility = Visibility.Collapsed;
|
||||
else
|
||||
Parent.PartiallyMatchedIDs.Text = string.Join(", ", SubmissionInfo.PartiallyMatchedIDs);
|
||||
if (SubmissionInfo?.CopyProtection?.AntiModchip == null)
|
||||
Parent.AntiModchip.Visibility = Visibility.Collapsed;
|
||||
else
|
||||
Parent.AntiModchip.Text = SubmissionInfo.CopyProtection.AntiModchip.LongName();
|
||||
if (SubmissionInfo?.TracksAndWriteOffsets?.OtherWriteOffsets == null)
|
||||
Parent.DiscOffset.Visibility = Visibility.Collapsed;
|
||||
else
|
||||
Parent.DiscOffset.Text = SubmissionInfo.TracksAndWriteOffsets.OtherWriteOffsets;
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.DMIHash) != true)
|
||||
Parent.DMIHash.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrWhiteSpace(SubmissionInfo?.CommonDiscInfo?.ErrorsCount))
|
||||
Parent.ErrorsCount.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrWhiteSpace(SubmissionInfo?.CommonDiscInfo?.EXEDateBuildDate))
|
||||
Parent.EXEDateBuildDate.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.EDC?.EDC == null)
|
||||
Parent.EDC.Visibility = Visibility.Collapsed;
|
||||
else
|
||||
Parent.EDC.Text = SubmissionInfo.EDC.EDC.LongName();
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.Filename) != true)
|
||||
Parent.Filename.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrWhiteSpace(SubmissionInfo?.Extras?.Header))
|
||||
Parent.Header.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.InternalName) != true)
|
||||
Parent.InternalName.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.InternalSerialName) != true)
|
||||
Parent.InternalSerialName.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CopyProtection?.LibCrypt == null)
|
||||
Parent.LibCrypt.Visibility = Visibility.Collapsed;
|
||||
else
|
||||
Parent.LibCrypt.Text = SubmissionInfo.CopyProtection.LibCrypt.LongName();
|
||||
if (string.IsNullOrWhiteSpace(SubmissionInfo?.CopyProtection?.LibCryptData))
|
||||
Parent.LibCryptData.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.PFIHash) != true)
|
||||
Parent.PFIHash.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrWhiteSpace(SubmissionInfo?.Extras?.PIC))
|
||||
Parent.PIC.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrWhiteSpace(SubmissionInfo?.Extras?.PVD))
|
||||
Parent.PVD.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.Multisession) != true)
|
||||
Parent.Multisession.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.RingNonZeroDataStart) != true)
|
||||
Parent.RingNonZeroDataStart.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrWhiteSpace(SubmissionInfo?.CopyProtection?.SecuROMData))
|
||||
Parent.SecuROMData.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.SSHash) != true)
|
||||
Parent.SSHash.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrWhiteSpace(SubmissionInfo?.Extras?.SecuritySectorRanges))
|
||||
Parent.SecuritySectorRanges.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.SSVersion) != true)
|
||||
Parent.SSVersion.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.UniversalHash) != true)
|
||||
Parent.UniversalHash.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.VolumeLabel) != true)
|
||||
Parent.VolumeLabel.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.XeMID) != true)
|
||||
Parent.XeMID.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.XMID) != true)
|
||||
Parent.XMID.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manipulate fields based on the current disc
|
||||
/// </summary>
|
||||
private void ManipulateFields()
|
||||
{
|
||||
// Enable tabs in all fields, if required
|
||||
if (this.Options.EnableTabsInInputFields)
|
||||
EnableTabsInInputFields();
|
||||
|
||||
// Hide read-only fields that don't have values set
|
||||
HideReadOnlyFields();
|
||||
|
||||
// Different media types mean different fields available
|
||||
UpdateFromDiscType();
|
||||
|
||||
// Different systems mean different fields available
|
||||
UpdateFromSystemType();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load the current contents of the base SubmissionInfo to the UI
|
||||
/// </summary>
|
||||
private void Load()
|
||||
{
|
||||
Parent.CategoryComboBox.SelectedIndex = Categories.FindIndex(r => r == SubmissionInfo.CommonDiscInfo.Category);
|
||||
Parent.RegionComboBox.SelectedIndex = Regions.FindIndex(r => r == SubmissionInfo.CommonDiscInfo.Region);
|
||||
if (SubmissionInfo.CommonDiscInfo.Languages != null)
|
||||
Languages.ForEach(l => l.IsChecked = SubmissionInfo.CommonDiscInfo.Languages.Contains(l));
|
||||
if (SubmissionInfo.CommonDiscInfo.LanguageSelection != null)
|
||||
LanguageSelections.ForEach(ls => ls.IsChecked = SubmissionInfo.CommonDiscInfo.LanguageSelection.Contains(ls));
|
||||
|
||||
// TODO: Figure out if this can be automatically mapped instead
|
||||
|
||||
// Comment Fields
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields != null)
|
||||
{
|
||||
// Additional Information
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.AlternativeTitle))
|
||||
Parent.AlternativeTitleTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.AlternativeTitle];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.AlternativeForeignTitle))
|
||||
Parent.AlternativeForeignTitleTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.AlternativeForeignTitle];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.Genre))
|
||||
Parent.GenreTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.Genre];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.PostgapType))
|
||||
Parent.PostgapTypeCheckBox.IsChecked = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PostgapType] != null;
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.Series))
|
||||
Parent.SeriesTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.Series];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.VCD))
|
||||
Parent.VCDCheckBox.IsChecked = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.VCD] != null;
|
||||
|
||||
// Physical Identifiers
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.BBFCRegistrationNumber))
|
||||
Parent.BBFCRegistrationNumberTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.BBFCRegistrationNumber];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.DiscHologramID))
|
||||
Parent.DiscHologramIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.DiscHologramID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.DNASDiscID))
|
||||
Parent.DNASDiscIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.DNASDiscID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.ISBN))
|
||||
Parent.ISBNTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ISBN];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.ISSN))
|
||||
Parent.ISSNTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ISSN];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.PPN))
|
||||
Parent.PPNTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PPN];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.VFCCode))
|
||||
Parent.VFCCodeTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.VFCCode];
|
||||
|
||||
// Publisher Identifiers
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.AcclaimID))
|
||||
Parent.AcclaimIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.AcclaimID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.ActivisionID))
|
||||
Parent.ActivisionIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ActivisionID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.BandaiID))
|
||||
Parent.BandaiIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.BandaiID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.ElectronicArtsID))
|
||||
Parent.ElectronicArtsIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ElectronicArtsID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.FoxInteractiveID))
|
||||
Parent.FoxInteractiveIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.FoxInteractiveID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.GTInteractiveID))
|
||||
Parent.GTInteractiveIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.GTInteractiveID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.JASRACID))
|
||||
Parent.JASRACIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.JASRACID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.KingRecordsID))
|
||||
Parent.KingRecordsIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.KingRecordsID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.KoeiID))
|
||||
Parent.KoeiIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.KoeiID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.KonamiID))
|
||||
Parent.KonamiIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.KonamiID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.LucasArtsID))
|
||||
Parent.LucasArtsIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.LucasArtsID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.MicrosoftID))
|
||||
Parent.MicrosoftIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.MicrosoftID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.NaganoID))
|
||||
Parent.NaganoIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.NaganoID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.NamcoID))
|
||||
Parent.NamcoIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.NamcoID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.NipponIchiSoftwareID))
|
||||
Parent.NipponIchiSoftwareIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.NipponIchiSoftwareID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.OriginID))
|
||||
Parent.OriginIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.OriginID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.PonyCanyonID))
|
||||
Parent.PonyCanyonIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PonyCanyonID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.SegaID))
|
||||
Parent.SegaIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SegaID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.SelenID))
|
||||
Parent.SelenIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SelenID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.SierraID))
|
||||
Parent.SierraIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SierraID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.TaitoID))
|
||||
Parent.TaitoIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.TaitoID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.UbisoftID))
|
||||
Parent.UbisoftIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.UbisoftID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.ValveID))
|
||||
Parent.ValveIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ValveID];
|
||||
|
||||
// Read-Only Information
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.DMIHash))
|
||||
Parent.DMIHash.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.DMIHash];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.Filename))
|
||||
Parent.Filename.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.Filename];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.InternalName))
|
||||
Parent.InternalName.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalName];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.InternalSerialName))
|
||||
Parent.InternalSerialName.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.Multisession))
|
||||
Parent.Multisession.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.Multisession];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.PFIHash))
|
||||
Parent.PFIHash.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.RingNonZeroDataStart))
|
||||
Parent.RingNonZeroDataStart.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.RingNonZeroDataStart];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.SSHash))
|
||||
Parent.SSHash.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.SSVersion))
|
||||
Parent.SSVersion.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSVersion];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.UniversalHash))
|
||||
Parent.UniversalHash.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.UniversalHash];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.VolumeLabel))
|
||||
Parent.VolumeLabel.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.VolumeLabel];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.XeMID))
|
||||
Parent.XeMID.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.XeMID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.XMID))
|
||||
Parent.XMID.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.XMID];
|
||||
}
|
||||
|
||||
// Content Fields
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields != null)
|
||||
{
|
||||
// Games
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.Games))
|
||||
Parent.GamesTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Games];
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.NetYarozeGames))
|
||||
Parent.NetYarozeGamesTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.NetYarozeGames];
|
||||
|
||||
// Demos
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.PlayableDemos))
|
||||
Parent.PlayableDemosTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.PlayableDemos];
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.RollingDemos))
|
||||
Parent.RollingDemosTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.RollingDemos];
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.TechDemos))
|
||||
Parent.TechDemosTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.TechDemos];
|
||||
|
||||
// Video
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.GameFootage))
|
||||
Parent.GameFootageTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.GameFootage];
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.Videos))
|
||||
Parent.VideosTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Videos];
|
||||
|
||||
// Miscellaneous
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.Patches))
|
||||
Parent.PatchesTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Patches];
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.Savegames))
|
||||
Parent.SavegamesTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Savegames];
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.Extras))
|
||||
Parent.ExtrasTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Extras];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save the current contents of the UI to the base SubmissionInfo
|
||||
/// </summary>
|
||||
public void Save()
|
||||
{
|
||||
SubmissionInfo.CommonDiscInfo.Category = (Parent.CategoryComboBox.SelectedItem as Element<DiscCategory>)?.Value ?? DiscCategory.Games;
|
||||
SubmissionInfo.CommonDiscInfo.Region = (Parent.RegionComboBox.SelectedItem as Element<Region>)?.Value ?? Region.World;
|
||||
SubmissionInfo.CommonDiscInfo.Languages = Languages.Where(l => l.IsChecked).Select(l => l?.Value).ToArray();
|
||||
if (!SubmissionInfo.CommonDiscInfo.Languages.Any())
|
||||
SubmissionInfo.CommonDiscInfo.Languages = new Language?[] { null };
|
||||
SubmissionInfo.CommonDiscInfo.LanguageSelection = LanguageSelections.Where(ls => ls.IsChecked).Select(ls => ls?.Value).ToArray();
|
||||
|
||||
// TODO: Figure out if this can be automatically mapped instead
|
||||
|
||||
// Initialize the dictionaries, if needed
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields == null)
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields == null)
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields = new Dictionary<SiteCode?, string>();
|
||||
|
||||
#region Comment Fields
|
||||
|
||||
// Additional Information
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.AlternativeTitle] = Parent.AlternativeTitleTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.AlternativeForeignTitle] = Parent.AlternativeForeignTitleTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.Genre] = Parent.GenreTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PostgapType] = Parent.PostgapTypeCheckBox.IsChecked?.ToString();
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.Series] = Parent.SeriesTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.VCD] = Parent.VCDCheckBox.IsChecked?.ToString();
|
||||
|
||||
// Physical Identifiers
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.BBFCRegistrationNumber] = Parent.BBFCRegistrationNumberTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.DiscHologramID] = Parent.DiscHologramIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.DNASDiscID] = Parent.DNASDiscIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ISBN] = Parent.ISBNTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ISSN] = Parent.ISSNTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PPN] = Parent.PPNTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.VFCCode] = Parent.VFCCodeTextBox.Text;
|
||||
|
||||
// Publisher Identifiers
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.AcclaimID] = Parent.AcclaimIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ActivisionID] = Parent.ActivisionIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.BandaiID] = Parent.BandaiIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ElectronicArtsID] = Parent.ElectronicArtsIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.FoxInteractiveID] = Parent.FoxInteractiveIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.GTInteractiveID] = Parent.GTInteractiveIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.JASRACID] = Parent.JASRACIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.KingRecordsID] = Parent.KingRecordsIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.KoeiID] = Parent.KoeiIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.KonamiID] = Parent.KonamiIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.LucasArtsID] = Parent.LucasArtsIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.MicrosoftID] = Parent.MicrosoftIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.NaganoID] = Parent.NaganoIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.NamcoID] = Parent.NamcoIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.NipponIchiSoftwareID] = Parent.NipponIchiSoftwareIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.OriginID] = Parent.OriginIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PonyCanyonID] = Parent.PonyCanyonIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SegaID] = Parent.SegaIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SelenID] = Parent.SelenIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SierraID] = Parent.SierraIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.TaitoID] = Parent.TaitoIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.UbisoftID] = Parent.UbisoftIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ValveID] = Parent.ValveIDTextBox.Text;
|
||||
|
||||
// Read-Only Information
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.DMIHash] = Parent.DMIHash.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.Filename] = Parent.Filename.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalName] = Parent.InternalName.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = Parent.InternalSerialName.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.Multisession] = Parent.Multisession.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash] = Parent.PFIHash.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.RingNonZeroDataStart] = Parent.RingNonZeroDataStart.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash] = Parent.SSHash.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSVersion] = Parent.SSVersion.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.UniversalHash] = Parent.UniversalHash.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.VolumeLabel] = Parent.VolumeLabel.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.XeMID] = Parent.XeMID.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.XMID] = Parent.XMID.Text;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Content Fields
|
||||
|
||||
// Games
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Games] = Parent.GamesTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.NetYarozeGames] = Parent.NetYarozeGamesTextBox.Text;
|
||||
|
||||
// Demos
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.PlayableDemos] = Parent.PlayableDemosTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.RollingDemos] = Parent.RollingDemosTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.TechDemos] = Parent.TechDemosTextBox.Text;
|
||||
|
||||
// Video
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.GameFootage] = Parent.GameFootageTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Videos] = Parent.VideosTextBox.Text;
|
||||
|
||||
// Miscellaneous
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Patches] = Parent.PatchesTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Savegames] = Parent.SavegamesTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Extras] = Parent.ExtrasTextBox.Text;
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Repopulate the list of Languages based on Redump support
|
||||
/// </summary>
|
||||
private void SetRedumpLanguages()
|
||||
{
|
||||
this.Languages = RedumpLanguages.Select(l => new Element<Language>(l)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Repopulate the list of Regions based on Redump support
|
||||
/// </summary>
|
||||
private void SetRedumpRegions()
|
||||
{
|
||||
this.Regions = RedumpRegions.Select(r => new Element<Region>(r)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update visible fields and sections based on the media type
|
||||
/// </summary>
|
||||
private void UpdateFromDiscType()
|
||||
{
|
||||
// Sony-printed discs have layers in the opposite order
|
||||
var system = SubmissionInfo?.CommonDiscInfo?.System;
|
||||
bool reverseOrder = system.HasReversedRingcodes();
|
||||
|
||||
switch (SubmissionInfo?.CommonDiscInfo?.Media)
|
||||
{
|
||||
case DiscType.CD:
|
||||
case DiscType.GDROM:
|
||||
Parent.L0Info.Header = "Data Side";
|
||||
Parent.L0MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L0MasteringSID.Label = "Mastering SID";
|
||||
Parent.L0Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
Parent.L0MouldSID.Label = "Mould SID";
|
||||
Parent.L0AdditionalMould.Label = "Additional Mould";
|
||||
|
||||
Parent.L1Info.Header = "Label Side";
|
||||
Parent.L1MasteringRing.Visibility = Visibility.Collapsed;
|
||||
Parent.L1MasteringSID.Visibility = Visibility.Collapsed;
|
||||
Parent.L1Toolstamp.Visibility = Visibility.Collapsed;
|
||||
Parent.L1MouldSID.Label = "Mould SID";
|
||||
Parent.L1AdditionalMould.Label = "Additional Mould";
|
||||
break;
|
||||
|
||||
case DiscType.DVD5:
|
||||
case DiscType.DVD9:
|
||||
case DiscType.HDDVDSL:
|
||||
case DiscType.HDDVDDL:
|
||||
case DiscType.BD25:
|
||||
case DiscType.BD33:
|
||||
case DiscType.BD50:
|
||||
case DiscType.BD66:
|
||||
case DiscType.BD100:
|
||||
case DiscType.BD128:
|
||||
case DiscType.NintendoGameCubeGameDisc:
|
||||
case DiscType.NintendoWiiOpticalDiscSL:
|
||||
case DiscType.NintendoWiiOpticalDiscDL:
|
||||
case DiscType.NintendoWiiUOpticalDiscSL:
|
||||
// Quad-layer discs
|
||||
if (SubmissionInfo?.SizeAndChecksums?.Layerbreak3 != default(long))
|
||||
{
|
||||
Parent.L2Info.Visibility = Visibility.Visible;
|
||||
Parent.L3Info.Visibility = Visibility.Visible;
|
||||
|
||||
Parent.L0Info.Header = reverseOrder ? "Layer 0 (Outer)" : "Layer 0 (Inner)";
|
||||
Parent.L0MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L0MasteringSID.Label = "Mastering SID";
|
||||
Parent.L0Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
Parent.L0MouldSID.Label = "Data Side Mould SID";
|
||||
Parent.L0AdditionalMould.Label = "Data Side Additional Mould";
|
||||
|
||||
Parent.L1Info.Header = "Layer 1";
|
||||
Parent.L1MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L1MasteringSID.Label = "Mastering SID";
|
||||
Parent.L1Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
Parent.L1MouldSID.Label = "Label Side Mould SID";
|
||||
Parent.L1AdditionalMould.Label = "Label Side Additional Mould";
|
||||
|
||||
Parent.L2Info.Header = "Layer 2";
|
||||
Parent.L2MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L2MasteringSID.Label = "Mastering SID";
|
||||
Parent.L2Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
|
||||
Parent.L3Info.Header = reverseOrder ? "Layer 3 (Inner)" : "Layer 3 (Outer)";
|
||||
Parent.L3MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L3MasteringSID.Label = "Mastering SID";
|
||||
Parent.L3Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
}
|
||||
|
||||
// Triple-layer discs
|
||||
else if (SubmissionInfo?.SizeAndChecksums?.Layerbreak2 != default(long))
|
||||
{
|
||||
Parent.L2Info.Visibility = Visibility.Visible;
|
||||
|
||||
Parent.L0Info.Header = reverseOrder ? "Layer 0 (Outer)" : "Layer 0 (Inner)";
|
||||
Parent.L0MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L0MasteringSID.Label = "Mastering SID";
|
||||
Parent.L0Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
Parent.L0MouldSID.Label = "Data Side Mould SID";
|
||||
Parent.L0AdditionalMould.Label = "Data Side Additional Mould";
|
||||
|
||||
Parent.L1Info.Header = "Layer 1";
|
||||
Parent.L1MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L1MasteringSID.Label = "Mastering SID";
|
||||
Parent.L1Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
Parent.L1MouldSID.Label = "Label Side Mould SID";
|
||||
Parent.L1AdditionalMould.Label = "Label Side Additional Mould";
|
||||
|
||||
Parent.L2Info.Header = reverseOrder ? "Layer 2 (Inner)" : "Layer 2 (Outer)";
|
||||
Parent.L2MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L2MasteringSID.Label = "Mastering SID";
|
||||
Parent.L2Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
}
|
||||
|
||||
// Double-layer discs
|
||||
else if (SubmissionInfo?.SizeAndChecksums?.Layerbreak != default(long))
|
||||
{
|
||||
Parent.L0Info.Header = reverseOrder ? "Layer 0 (Outer)" : "Layer 0 (Inner)";
|
||||
Parent.L0MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L0MasteringSID.Label = "Mastering SID";
|
||||
Parent.L0Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
Parent.L0MouldSID.Label = "Data Side Mould SID";
|
||||
Parent.L0AdditionalMould.Label = "Data Side Additional Mould";
|
||||
|
||||
Parent.L1Info.Header = reverseOrder ? "Layer 1 (Inner)" : "Layer 1 (Outer)";
|
||||
Parent.L1MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L1MasteringSID.Label = "Mastering SID";
|
||||
Parent.L1Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
Parent.L1MouldSID.Label = "Label Side Mould SID";
|
||||
Parent.L1AdditionalMould.Label = "Label Side Additional Mould";
|
||||
}
|
||||
|
||||
// Single-layer discs
|
||||
else
|
||||
{
|
||||
Parent.L0Info.Header = "Data Side";
|
||||
Parent.L0MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L0MasteringSID.Label = "Mastering SID";
|
||||
Parent.L0Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
Parent.L0MouldSID.Label = "Mould SID";
|
||||
Parent.L0AdditionalMould.Label = "Additional Mould";
|
||||
|
||||
Parent.L1Info.Header = "Label Side";
|
||||
Parent.L1MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L1MasteringSID.Label = "Mastering SID";
|
||||
Parent.L1Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
Parent.L1MouldSID.Label = "Mould SID";
|
||||
Parent.L1AdditionalMould.Label = "Additional Mould";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// All other media we assume to have no rings
|
||||
default:
|
||||
Parent.L0Info.Visibility = Visibility.Collapsed;
|
||||
Parent.L1Info.Visibility = Visibility.Collapsed;
|
||||
Parent.L2Info.Visibility = Visibility.Collapsed;
|
||||
Parent.L3Info.Visibility = Visibility.Collapsed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update visible fields and sections based on the system type
|
||||
/// </summary>
|
||||
private void UpdateFromSystemType()
|
||||
{
|
||||
var system = SubmissionInfo?.CommonDiscInfo?.System;
|
||||
switch (system)
|
||||
{
|
||||
case RedumpSystem.SonyPlayStation2:
|
||||
Parent.LanguageSelectionGrid.Visibility = Visibility.Visible;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Handler for AcceptButton Click event
|
||||
/// </summary>
|
||||
private void OnAcceptClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Save();
|
||||
Parent.DialogResult = true;
|
||||
Parent.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for CancelButton Click event
|
||||
/// </summary>
|
||||
private void OnCancelClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Parent.DialogResult = false;
|
||||
Parent.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for RingCodeGuideButton Click event
|
||||
/// </summary>
|
||||
private void OnRingCodeGuideClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var ringCodeGuideWindow = new RingCodeGuideWindow()
|
||||
{
|
||||
Owner = Parent,
|
||||
WindowStartupLocation = WindowStartupLocation.CenterOwner,
|
||||
};
|
||||
ringCodeGuideWindow.Show();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user