mirror of
https://github.com/SabreTools/MPF.git
synced 2026-02-05 13:49:40 +00:00
Compare commits
455 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f4921a47c | ||
|
|
07359d2a63 | ||
|
|
e5ba670c04 | ||
|
|
3096c369d3 | ||
|
|
333368675a | ||
|
|
d78d744ae2 | ||
|
|
a8efe056c1 | ||
|
|
9b2475a854 | ||
|
|
33e2b27e6d | ||
|
|
91fe9d9bec | ||
|
|
b1b9b3134f | ||
|
|
ca5386b529 | ||
|
|
347beca874 | ||
|
|
27ca4fd1af | ||
|
|
6d57a05f8c | ||
|
|
4d81449cfa | ||
|
|
76fcb3ae10 | ||
|
|
b913f5f9ae | ||
|
|
68fa1eecfb | ||
|
|
dc84f17ac5 | ||
|
|
c91137130b | ||
|
|
972b07551f | ||
|
|
61562fe995 | ||
|
|
01b6c3cc98 | ||
|
|
b461dc76b9 | ||
|
|
03eeed4113 | ||
|
|
07615cb336 | ||
|
|
9a9a977cc4 | ||
|
|
ab5869331b | ||
|
|
1c9ebfd703 | ||
|
|
a9bc3587a6 | ||
|
|
b1af2b6061 | ||
|
|
2fccd53098 | ||
|
|
a7ad3e41d9 | ||
|
|
1fc6476f71 | ||
|
|
53e5a1b1b1 | ||
|
|
119e9dc4cc | ||
|
|
9263769906 | ||
|
|
ebaf9539b2 | ||
|
|
818fb5ab34 | ||
|
|
2f514082a9 | ||
|
|
5c5379e972 | ||
|
|
c39894d9fc | ||
|
|
2c6cf0e736 | ||
|
|
7e96bbee27 | ||
|
|
f7019546d1 | ||
|
|
086f54abf0 | ||
|
|
143a4149bd | ||
|
|
20aed68d58 | ||
|
|
7a2061a36e | ||
|
|
191c7b080e | ||
|
|
aab0813688 | ||
|
|
9ad564772c | ||
|
|
20bb34c3c7 | ||
|
|
b15ddf390b | ||
|
|
18d1562ad3 | ||
|
|
d6f2ecbd25 | ||
|
|
3620686afa | ||
|
|
1524224bc3 | ||
|
|
35200d53d6 | ||
|
|
4b7d4e05e7 | ||
|
|
7e73f69433 | ||
|
|
9e1a972df5 | ||
|
|
1edac34c1a | ||
|
|
9adc588c9c | ||
|
|
71bfdcba8f | ||
|
|
9854c9970a | ||
|
|
0c68164d6d | ||
|
|
a413357b57 | ||
|
|
5e283c9e80 | ||
|
|
500eb66e30 | ||
|
|
411e5245a5 | ||
|
|
d270501c2d | ||
|
|
f7f924593f | ||
|
|
5126a66eb9 | ||
|
|
7fddef238d | ||
|
|
ace673f90d | ||
|
|
e063df63df | ||
|
|
22b15710d0 | ||
|
|
87199c1b0d | ||
|
|
7e5952bbb8 | ||
|
|
1a52a3a205 | ||
|
|
742db4c854 | ||
|
|
4fd51dbe45 | ||
|
|
096a8a6a06 | ||
|
|
ad5cd5b8f9 | ||
|
|
3230d59f6a | ||
|
|
96fa8d8cef | ||
|
|
01bf3c9efb | ||
|
|
da0bf64e94 | ||
|
|
d39cf5d13f | ||
|
|
7c7e78fd4e | ||
|
|
d2c504898a | ||
|
|
58028b4f18 | ||
|
|
54e835687b | ||
|
|
10f2318541 | ||
|
|
eb4e95e5db | ||
|
|
203418eebc | ||
|
|
136c6c8fbf | ||
|
|
2c216d6a58 | ||
|
|
f7ec19cc5d | ||
|
|
e8c4a97158 | ||
|
|
5e5fc4c812 | ||
|
|
5e0d99ff5d | ||
|
|
e88e67c927 | ||
|
|
d963dbbd5f | ||
|
|
11ce78fca2 | ||
|
|
fd4022ba84 | ||
|
|
f91aecad8e | ||
|
|
709b7d357f | ||
|
|
59980fa160 | ||
|
|
180caf83cc | ||
|
|
7047ee832a | ||
|
|
4b5532e1b0 | ||
|
|
137155d3dc | ||
|
|
793dd8289a | ||
|
|
bcf298e40b | ||
|
|
589aef1e21 | ||
|
|
9ab0b7ab3b | ||
|
|
4c5ea13aac | ||
|
|
0cf48bbdaa | ||
|
|
8fc9cc18a3 | ||
|
|
b1e156eed6 | ||
|
|
a8b3a837ef | ||
|
|
3f3a1c9a44 | ||
|
|
cf4d2f5055 | ||
|
|
2d19d51bc7 | ||
|
|
4842bdd38b | ||
|
|
7cc4f6d6a7 | ||
|
|
b284ffd99d | ||
|
|
81d0cc2cc2 | ||
|
|
70f368d6e9 | ||
|
|
bfbae5cf5c | ||
|
|
7cc231f5fd | ||
|
|
eda34b3477 | ||
|
|
bfb67ec0c9 | ||
|
|
275fd0da48 | ||
|
|
1ad5c25ed0 | ||
|
|
512f7ae016 | ||
|
|
3a00efc7fd | ||
|
|
3068c74ad7 | ||
|
|
9bdead5616 | ||
|
|
0ed5feb96b | ||
|
|
ec80ef2ede | ||
|
|
617591cc26 | ||
|
|
c855aa5cef | ||
|
|
e2a27479f5 | ||
|
|
c8cfe76aa3 | ||
|
|
ecb0234258 | ||
|
|
24ce4bcc51 | ||
|
|
162af3de31 | ||
|
|
7c0af96dc9 | ||
|
|
026f999b46 | ||
|
|
bbbc3e98a0 | ||
|
|
f78ad4e7b6 | ||
|
|
d756ae2163 | ||
|
|
701738ce25 | ||
|
|
620bdc9132 | ||
|
|
71f474c26c | ||
|
|
c48137a5c1 | ||
|
|
e248368484 | ||
|
|
7225b8c32d | ||
|
|
20e475e130 | ||
|
|
88dc005592 | ||
|
|
40792ff0eb | ||
|
|
6ae59e91de | ||
|
|
5c7aa5f7f5 | ||
|
|
aaa1ed674f | ||
|
|
42def3bbe5 | ||
|
|
9cdab52556 | ||
|
|
5c104ebf3d | ||
|
|
7ab72e542c | ||
|
|
3a8420cd2f | ||
|
|
916aa9fd70 | ||
|
|
8809df10b6 | ||
|
|
34d65a9d70 | ||
|
|
2830d7c8a2 | ||
|
|
c702c8b0ac | ||
|
|
e1df9a9754 | ||
|
|
03fe5ce8a5 | ||
|
|
432a9dda16 | ||
|
|
1dfc0f731e | ||
|
|
af515e0adf | ||
|
|
2222b57143 | ||
|
|
d8cfa2e6a4 | ||
|
|
a622cdd4e0 | ||
|
|
2a4ec83d0d | ||
|
|
b1d144d091 | ||
|
|
23a8b66c16 | ||
|
|
381ebd5961 | ||
|
|
b4d1f7d6c3 | ||
|
|
b3eff64275 | ||
|
|
f15c00acca | ||
|
|
a66d0d4722 | ||
|
|
66cdade01b | ||
|
|
9e9f001768 | ||
|
|
3514bdcbc4 | ||
|
|
312df37365 | ||
|
|
6214d91940 | ||
|
|
23d500434b | ||
|
|
7ee5e3ab43 | ||
|
|
6be4bb7c85 | ||
|
|
d620c13e22 | ||
|
|
73b585cdd2 | ||
|
|
2f33581e4a | ||
|
|
f3dba9a026 | ||
|
|
d7d0af369c | ||
|
|
2ab9a45a71 | ||
|
|
dc0bf642a9 | ||
|
|
9e32435972 | ||
|
|
c2b724e949 | ||
|
|
195d3c6ff7 | ||
|
|
04a8079cee | ||
|
|
0b2daf7d30 | ||
|
|
1353ee603b | ||
|
|
e9d272d139 | ||
|
|
0308c7a81e | ||
|
|
4caad10c9b | ||
|
|
85c1623d33 | ||
|
|
5be1825bb5 | ||
|
|
ec5e533bd8 | ||
|
|
c3e4c7fa78 | ||
|
|
bf66a3fcbd | ||
|
|
101193cb78 | ||
|
|
b610c29be6 | ||
|
|
999c4dceb5 | ||
|
|
2957370fac | ||
|
|
5dd36d7b06 | ||
|
|
47b5bbe7e7 | ||
|
|
5a2e4ca77e | ||
|
|
c479ddb80b | ||
|
|
da1f59e0c1 | ||
|
|
9574832e86 | ||
|
|
3df7842d23 | ||
|
|
62a0f6e49a | ||
|
|
60c180e4dd | ||
|
|
343d937362 | ||
|
|
f20b321433 | ||
|
|
ba19b0825f | ||
|
|
5abb44957c | ||
|
|
b9d9cf812f | ||
|
|
d1529f428a | ||
|
|
5061a79c4c | ||
|
|
eab3e25cf2 | ||
|
|
33e73a8992 | ||
|
|
a63972b549 | ||
|
|
bc57df7fc1 | ||
|
|
e16f616286 | ||
|
|
c5497d787b | ||
|
|
64f60004c4 | ||
|
|
020c063177 | ||
|
|
a3e6f8157f | ||
|
|
f27040cd1c | ||
|
|
3a490cfc8d | ||
|
|
1f8c5998c1 | ||
|
|
f96d4ee37e | ||
|
|
d0d15f03af | ||
|
|
eff6407206 | ||
|
|
c1e559568a | ||
|
|
ef030b290c | ||
|
|
71630591a1 | ||
|
|
31505745be | ||
|
|
e40444b60c | ||
|
|
44edf387a6 | ||
|
|
d3d225644d | ||
|
|
3afd9200a9 | ||
|
|
c5c340ff12 | ||
|
|
b28b85f7c6 | ||
|
|
c60684b83c | ||
|
|
a183a1ec91 | ||
|
|
abd8488185 | ||
|
|
e6dea158e5 | ||
|
|
24150c7b3c | ||
|
|
040720a1c2 | ||
|
|
70d30d370f | ||
|
|
a50b99da07 | ||
|
|
2cecbe69ad | ||
|
|
557410660f | ||
|
|
0d75dbaaa2 | ||
|
|
d38f95c73a | ||
|
|
c9d59a90e4 | ||
|
|
fc6a34d987 | ||
|
|
8acabb692f | ||
|
|
61f8871839 | ||
|
|
69d61ad185 | ||
|
|
27391ed31b | ||
|
|
ed56c92101 | ||
|
|
ab8ae1524f | ||
|
|
de7c247583 | ||
|
|
997fd8f7ac | ||
|
|
e39e07246a | ||
|
|
e0b0406d76 | ||
|
|
1efbe9a784 | ||
|
|
fab921c2dd | ||
|
|
56896b4bea | ||
|
|
54eb7d8ecd | ||
|
|
114587b9f6 | ||
|
|
cad33c6c07 | ||
|
|
8154999f1c | ||
|
|
3a30c14085 | ||
|
|
db8b1df480 | ||
|
|
e20cac8a80 | ||
|
|
ce9b4e39f5 | ||
|
|
ddff4b2e58 | ||
|
|
16a470475c | ||
|
|
6e01473e87 | ||
|
|
8682089151 | ||
|
|
f45cb0075f | ||
|
|
afccb48798 | ||
|
|
ce6995fba0 | ||
|
|
3328d1adea | ||
|
|
33d79df9a8 | ||
|
|
4fb64b19d6 | ||
|
|
bf0f495c8b | ||
|
|
5d5f8e8d8c | ||
|
|
91aa248355 | ||
|
|
633c6c1efb | ||
|
|
facb1f673f | ||
|
|
9c8938c7f2 | ||
|
|
17f75f3ce6 | ||
|
|
b99c48afa2 | ||
|
|
9481fada23 | ||
|
|
7efbc5043c | ||
|
|
92880d3148 | ||
|
|
9800f2b8ae | ||
|
|
a5d01604cb | ||
|
|
aaab84f90a | ||
|
|
318a1a303c | ||
|
|
0061de6b2e | ||
|
|
b3db7c547f | ||
|
|
1da29464a8 | ||
|
|
d1d4ff41c6 | ||
|
|
673c2745a9 | ||
|
|
4ad88441cc | ||
|
|
71bb822856 | ||
|
|
2a7789bd12 | ||
|
|
1d0417cc1c | ||
|
|
905c578d90 | ||
|
|
a457c85e53 | ||
|
|
36630fc0ed | ||
|
|
f509ac60da | ||
|
|
bf8aac6f81 | ||
|
|
ceddcc0722 | ||
|
|
3a2bda6fb6 | ||
|
|
aea2403153 | ||
|
|
6e334df42f | ||
|
|
04cb68c9bd | ||
|
|
06060c071b | ||
|
|
02903686ad | ||
|
|
00cbed725d | ||
|
|
dabccd3a8a | ||
|
|
0e1e499a66 | ||
|
|
b4f485a0cc | ||
|
|
5bad68b9ff | ||
|
|
2db686fc47 | ||
|
|
d705a4b316 | ||
|
|
0154ee5bb6 | ||
|
|
29f14f5690 | ||
|
|
dd6f7b0794 | ||
|
|
e5c9591d64 | ||
|
|
df8da8bd46 | ||
|
|
c9b21006d1 | ||
|
|
2b37882322 | ||
|
|
8a2b3f2c89 | ||
|
|
c16a9aeb70 | ||
|
|
d5a0797c92 | ||
|
|
a55a769886 | ||
|
|
fd18c60f28 | ||
|
|
2704d1f88d | ||
|
|
c16c938fa4 | ||
|
|
497e2a09fd | ||
|
|
8bc8887ce6 | ||
|
|
7e5a5586f9 | ||
|
|
eee068db7e | ||
|
|
79e70173fa | ||
|
|
4f732557b9 | ||
|
|
6cbcebd661 | ||
|
|
f74dc01657 | ||
|
|
4735bef7b4 | ||
|
|
52a925df12 | ||
|
|
3e10199cb0 | ||
|
|
470e641a8c | ||
|
|
f61b84d058 | ||
|
|
5e77b43be1 | ||
|
|
46530a9fca | ||
|
|
12610c0d69 | ||
|
|
9bb9d3f407 | ||
|
|
a0ed20042c | ||
|
|
37c253aac2 | ||
|
|
68135c58ae | ||
|
|
f9efa71fcc | ||
|
|
184913ad28 | ||
|
|
ff52767a02 | ||
|
|
34ac5f9ba0 | ||
|
|
7296d109cc | ||
|
|
9be705ae30 | ||
|
|
af8b376f5a | ||
|
|
03f9668048 | ||
|
|
3bb23fa7cc | ||
|
|
f85c9d4e7e | ||
|
|
5de3d209be | ||
|
|
f1b136c817 | ||
|
|
c18829e0b3 | ||
|
|
d114b7f868 | ||
|
|
445cc173ce | ||
|
|
1e28fcad2e | ||
|
|
8d4e5155d9 | ||
|
|
027f562573 | ||
|
|
74caf084ca | ||
|
|
7396b02543 | ||
|
|
8035826b1b | ||
|
|
c6e73582c5 | ||
|
|
ca09d8c703 | ||
|
|
40b6551c7a | ||
|
|
95b664705d | ||
|
|
6bda7b35a2 | ||
|
|
6fedebf2a9 | ||
|
|
02f98c674b | ||
|
|
fb1e4130df | ||
|
|
c507f52b80 | ||
|
|
7b2784f1a2 | ||
|
|
7a7c83e8cf | ||
|
|
b86ef09763 | ||
|
|
71c050edf6 | ||
|
|
988f25b514 | ||
|
|
e878e8b904 | ||
|
|
bd3484cb3d | ||
|
|
3d769ed707 | ||
|
|
613be66f91 | ||
|
|
81e0ffbc3c | ||
|
|
8f3d325e7d | ||
|
|
a63472c6e6 | ||
|
|
8c98005605 | ||
|
|
8062d6cf17 | ||
|
|
78bf6e63ed | ||
|
|
68e0d759f7 | ||
|
|
26e72284af | ||
|
|
0efecd6601 | ||
|
|
9a3c2eb626 | ||
|
|
ca753b4526 | ||
|
|
230b6ca721 | ||
|
|
dc90f9af3f | ||
|
|
b5898c7ea3 | ||
|
|
36f1aea509 | ||
|
|
6742444182 | ||
|
|
e01fd37e6b | ||
|
|
ca7071f82a | ||
|
|
3cb67e3e65 | ||
|
|
e67dd589b5 | ||
|
|
74f491eaaa | ||
|
|
9ebd28ef5a | ||
|
|
2a58052bfd | ||
|
|
5ed73aff2b | ||
|
|
5a6ad09004 | ||
|
|
6a43b74043 |
28
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
28
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: For when you know better than me what you want
|
||||
title: "[Request]"
|
||||
labels: enhancement
|
||||
assignees: mnadareski
|
||||
|
||||
---
|
||||
|
||||
**Before You Submit**
|
||||
- Remember to try the [latest WIP build](https://ci.appveyor.com/project/mnadareski/mpf/build/artifacts) to see if the feature already exists.
|
||||
- Is it copy protection related? If so, report the issue [here](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.
|
||||
- Check [previous issues](https://github.com/SabreTools/MPF/issues) to see if any of those are related to what you're about to ask for.
|
||||
|
||||
If none of those apply, then continue...
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
22
.github/ISSUE_TEMPLATE/informational.md
vendored
Normal file
22
.github/ISSUE_TEMPLATE/informational.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
name: Info
|
||||
about: Something you need to tell me
|
||||
title: "[Info]"
|
||||
labels: question
|
||||
assignees: mnadareski
|
||||
|
||||
---
|
||||
|
||||
**Before You Submit**
|
||||
- Remember to try the [latest WIP build](https://ci.appveyor.com/project/mnadareski/mpf/build/artifacts) to see if the feature already exists.
|
||||
- Is it copy protection related? If so, report the issue [here](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.
|
||||
- Check [previous issues](https://github.com/SabreTools/MPF/issues) to see if any of those are related to what you're about to ask for.
|
||||
|
||||
If none of those apply, then continue...
|
||||
|
||||
**Is your information related to one of the dumping programs supported or something that isn't a bug in the code? Please describe.**
|
||||
A clear and concise description of what the information is. Ex. With the latest build of DumpingProgram, it [...]
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the information here.
|
||||
49
.github/ISSUE_TEMPLATE/issue-report.md
vendored
Normal file
49
.github/ISSUE_TEMPLATE/issue-report.md
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
---
|
||||
name: Issue Report
|
||||
about: Tell me what's wrong, seriously
|
||||
title: "[Problem]"
|
||||
labels: bug
|
||||
assignees: mnadareski
|
||||
|
||||
---
|
||||
|
||||
**Before You Submit**
|
||||
- Remember to try the [latest WIP build](https://ci.appveyor.com/project/mnadareski/mpf/build/artifacts) to see if the issue has already been addressed.
|
||||
- Is it copy protection related? If so, report the issue [here](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
|
||||
- Check multiple discs to help narrow down the issue
|
||||
- Check the Options to see if changing any of those affects your issue.
|
||||
|
||||
If all of those fail, then continue...
|
||||
|
||||
**Version**
|
||||
What version are you using?
|
||||
|
||||
- [ ] Stable release (version here)
|
||||
- [ ] WIP release (version here)
|
||||
|
||||
**Build**
|
||||
What runtime version are you using?
|
||||
|
||||
- [ ] .NET Framework 4.7.2 running on (Operating System)
|
||||
- [ ] .NET Framework 4.8 running on (Operating System)
|
||||
- [ ] .NET Core 3.1 running on (Operating System)
|
||||
|
||||
**Describe the issue**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "MPF.Library/Aaru/CICMMetadata"]
|
||||
path = MPF.Library/Aaru/CICMMetadata
|
||||
url = https://github.com/claunia/CICMMetadata
|
||||
27
.vscode/launch.json
vendored
Normal file
27
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
// Use IntelliSense to find out which attributes exist for C# debugging
|
||||
// Use hover for the description of the existing attributes
|
||||
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": ".NET Core Launch (console)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/MPF/bin/Debug/netcoreapp3.1/MPF.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/MPF",
|
||||
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Attach",
|
||||
"type": "coreclr",
|
||||
"request": "attach",
|
||||
"processId": "${command:pickProcess}"
|
||||
}
|
||||
]
|
||||
}
|
||||
42
.vscode/tasks.json
vendored
Normal file
42
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/MPF/MPF.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "publish",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"publish",
|
||||
"${workspaceFolder}/MPF/MPF.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "watch",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"watch",
|
||||
"run",
|
||||
"${workspaceFolder}/MPF/MPF.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
}
|
||||
136
CHANGELIST.md
136
CHANGELIST.md
@@ -1,4 +1,140 @@
|
||||
### 2.1 (2021-07-22)
|
||||
- Enum, no more
|
||||
- Sony works backward
|
||||
- Add experimental dark mode
|
||||
- Allow users to customize protection scanning
|
||||
- Fix negative offsets for `/a` flag
|
||||
- Always check for all DIC log files, just in case
|
||||
- Check for the zipped logs for dealing with overwrites
|
||||
- Be smarter about checking for zipped logs
|
||||
- Change offset value for HVN discs
|
||||
- Update to DIC 20210601
|
||||
- Fix Aaru command normalization
|
||||
- Handle carriage returns better
|
||||
- Add logging helper class
|
||||
- Set matcher on carriage return for log formatting
|
||||
- Replace dumping program output processing
|
||||
- Fix volume name detection for XBOX discs
|
||||
- Add new setting for including artifacts in serialzied JSON
|
||||
- Fix logging in to Redump for verifications
|
||||
- Gracefully handle timeouts during login
|
||||
- Update to DIC 20210701
|
||||
- Support `/mr` value parameter
|
||||
- Support new mainInfo header
|
||||
- Add BD to IBM-PC supported discs
|
||||
- Fix launching MPF on Windows 7
|
||||
- Fix log window background turning white
|
||||
- Add DMI/PFI/SS to log zipfile
|
||||
- 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
|
||||
- Add preliminary support for user-defined default system
|
||||
- Change labels in media info window depending on media type
|
||||
- Update to Aaru v5.2
|
||||
- Only pull disc information if every track returns at least one ID
|
||||
- Add new supported Redump regions
|
||||
- Remove Philips CD-i Digital Video from supported profiles
|
||||
- Remove experimental Avalonia UI, will wait for MAUI next year
|
||||
- ~~Updated to DIC version 20210102~~
|
||||
- Add support for `/mr` DIC flag
|
||||
- UI initialization code refactored to have more consistent results
|
||||
- Support DIC `.imgtmp`, `.scmtmp`, and `.subtmp` possible output files
|
||||
- Fix BCA formatting for CleanRip outputs
|
||||
- Add hashing for UMDs from UIC outputs
|
||||
- Fix information gathering for UIC outputs
|
||||
- Fix issue with duplicate security sector data in XGD DiscImageCreator outputs
|
||||
- ~~Update to BurnOutSharp 1.5.1~~
|
||||
- ~~Update to DIC version 20210202~~
|
||||
- Add VCD detection
|
||||
- Fix UI not updating properly on drive change
|
||||
- Add Xbox Series and PS5 to supported systems
|
||||
- Add PS5 type detection and version extraction
|
||||
- Add internal support for 3- and 4-layer discs
|
||||
- Revamp disc information window
|
||||
- Add PIC layerbreak extraction
|
||||
- Overhaul main window and logging panel
|
||||
- Overhaul options window
|
||||
- Update attributions and about text
|
||||
- ~~Updated to DIC version 20210301~~
|
||||
- Add user-selectable Language Selection via dropdown in disc submission window for PS2
|
||||
- Separate out Aaru- and DIC-specific settings
|
||||
- Add new options based on original "Paranoid Mode" mega-option
|
||||
- Internal overhaul of options and dump environment
|
||||
- VideoNow discs are audio only
|
||||
- Hook up default system in options
|
||||
- Make inner and outer layers in UI and outputs more clear
|
||||
- Program output to log by default, setting otherwise
|
||||
- DVDs and BDs can have label-side data
|
||||
- Remove .NET Framework 4.7.2 support
|
||||
- Make logging window a bit safer
|
||||
- Support new Redump languages and regions
|
||||
- Implement internal log queue
|
||||
- It's a secret...
|
||||
- Updated to DIC version 20210401
|
||||
- Support log file compression
|
||||
- Add ring code guide button to disc submission window
|
||||
- ~~Update to BurnOutSharp 1.6.0~~
|
||||
- Fix "rewinding" issue when inputting output paths with spaces
|
||||
- Add version to About box
|
||||
- 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
|
||||
- Fix PVD retrieval for multi-session discs
|
||||
- Updated to DIC version 20200921
|
||||
- Add and fix multiple Sega disc header pieces or submission info
|
||||
- Fixed issues in parsing the alternate mainInfo format
|
||||
- Fixed issue with logging clear not working properly
|
||||
- ~~Updated to BurnOutSharp 1.4.1~~
|
||||
- Added split archives for AppVeyor builds
|
||||
- Remove subdump from both UI and run steps
|
||||
- Removed default config file
|
||||
- Fixed copy protect scan using wrong drive when using UI option
|
||||
- Changed default to skip fixed drives
|
||||
- Fixed default media type when skipping type detection
|
||||
- Attempt sector reading for Saturn system detection
|
||||
- Fixed default media type when detection fails
|
||||
- Add option to allow users to select dumping program
|
||||
- ~~Updated to DIC version 20201101~~
|
||||
- Add support for `/ps` DIC flag
|
||||
- Updated to BurnOutSharp 1.5.0
|
||||
- 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
|
||||
- Fixed DIC flags based on code (not documentation)
|
||||
- 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
|
||||
- Added experimental Avalonia UI
|
||||
- Created wiki
|
||||
- Removed .NET 4.6.2 and .NET Core 3.0 builds
|
||||
- Added .NET 4.8 and .NET Core 3.1 builds
|
||||
- Fix numerous things related to PS1/PS2
|
||||
- Make subdump running optional
|
||||
- Overhaul DICUI.Check with more options
|
||||
- Numerous small bug- and regression-fixes
|
||||
|
||||
### 1.16.1 (2020-05-07)
|
||||
|
||||
- Add preliminary support for DD for Windows (end to end still NW)
|
||||
- Add CNF parsing for Konami Python 2 discs (PS2-based)
|
||||
- Updated included Aaru version
|
||||
- Massive cleanup effort to detangle large chunks of code
|
||||
- Miscellaneous bugfixes that came from the above
|
||||
|
||||
### 1.16 (2020-04-13)
|
||||
|
||||
- Updated to DIC version 20200403
|
||||
- UI updates based on user feedback
|
||||
- Added support for Aaru (formerly DiscImageChef)
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net462;net472;net48;netcoreapp3.1</TargetFrameworks>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<OutputType>Exe</OutputType>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DICUI.Library\DICUI.Library.csproj">
|
||||
<Project>{51ab0928-13f9-44bf-a407-b6957a43a056}</Project>
|
||||
<Name>DICUI.Library</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,202 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
|
||||
namespace DICUI.Check
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// Help options
|
||||
if (args.Length == 0
|
||||
|| args[0] == "/h" || args[0] == "/?"
|
||||
|| args[0] == "-h" || args[0] == "-?")
|
||||
{
|
||||
DisplayHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
// List options
|
||||
if (args[0] == "/lm" || args[0] == "/listmedia"
|
||||
|| args[0] == "-lm" || args[0] == "--listmedia")
|
||||
{
|
||||
ListMediaTypes();
|
||||
Console.ReadLine();
|
||||
return;
|
||||
}
|
||||
else if (args[0] == "/ls" || args[0] == "/listsystems"
|
||||
|| args[0] == "-ls" || args[0] == "--listsystems")
|
||||
{
|
||||
ListKnownSystems();
|
||||
Console.ReadLine();
|
||||
return;
|
||||
}
|
||||
|
||||
// Normal operation check
|
||||
if (args.Length < 3)
|
||||
{
|
||||
DisplayHelp("Invalid number of arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the MediaType
|
||||
var mediaType = Converters.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;
|
||||
}
|
||||
|
||||
// Check for additional flags
|
||||
string username = null, password = null;
|
||||
string internalProgram = "DiscImageCreator";
|
||||
int startIndex = 2;
|
||||
for (; startIndex < args.Length; startIndex++)
|
||||
{
|
||||
// Redump login
|
||||
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];
|
||||
}
|
||||
|
||||
// Default, we fall out
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Make a new Progress object
|
||||
var progress = new Progress<Result>();
|
||||
progress.ProgressChanged += ProgressUpdated;
|
||||
|
||||
// Loop through all the rest of the args
|
||||
for (int i = startIndex; i < args.Length; i++)
|
||||
{
|
||||
// Check for a file
|
||||
if (!File.Exists(args[i]))
|
||||
{
|
||||
DisplayHelp($"{args[i]} does not exist");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the full file path
|
||||
string filepath = Path.GetFullPath(args[i]);
|
||||
|
||||
// Now populate an environment
|
||||
var env = new DumpEnvironment
|
||||
{
|
||||
OutputDirectory = "",
|
||||
OutputFilename = filepath,
|
||||
System = knownSystem,
|
||||
Type = mediaType,
|
||||
ScanForProtection = false,
|
||||
PromptForDiscInformation = false,
|
||||
InternalProgram = Converters.ToInternalProgram(internalProgram),
|
||||
|
||||
Username = username,
|
||||
Password = password,
|
||||
};
|
||||
env.FixOutputPaths();
|
||||
|
||||
// Finally, attempt to do the output dance
|
||||
var result = env.VerifyAndSaveDumpOutput(progress);
|
||||
Console.WriteLine(result.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display help for DICUI.Check
|
||||
/// </summary>
|
||||
/// <param name="error">Error string to prefix the help text with</param>
|
||||
private static void DisplayHelp(string error = null)
|
||||
{
|
||||
if (error != null)
|
||||
Console.WriteLine(error);
|
||||
|
||||
Console.WriteLine("Usage:");
|
||||
Console.WriteLine("DICUI.Check.exe <mediatype> <system> [options] </path/to/output.bin> ...");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(@"Common Media Types:\r\n
|
||||
bd / bluray - BD-ROM
|
||||
cd / cdrom - CD-ROM
|
||||
dvd - DVD-ROM
|
||||
fd / floppy - Floppy Disk
|
||||
gd / gdrom - GD-ROM
|
||||
umd - UMD");
|
||||
Console.WriteLine("Run 'DICUI.Check.exe [-lm|--listmedia' for more options");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(@"Common Systems:\r\n
|
||||
apple / mac - Apple Macintosh
|
||||
cdi - Philips CD-i
|
||||
ibm / ibmpc - IBM PC Compatible
|
||||
psx / ps1 - Sony PlayStation
|
||||
ps2 - Sony PlayStation 2
|
||||
psp - Sony PlayStation Portable
|
||||
saturn - Sega Saturn
|
||||
xbox - Microsoft XBOX
|
||||
x360 - Microsoft XBOX 360");
|
||||
Console.WriteLine("Run 'DICUI.Check.exe [-ls|--listsystems' for more options");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(@"Common Options:\r\n
|
||||
-c username password - Redump credentials
|
||||
-u - Check for Aaru");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List all media types with their short usable names
|
||||
/// </summary>
|
||||
private static void ListMediaTypes()
|
||||
{
|
||||
Console.WriteLine("Supported Media Types:");
|
||||
foreach (var val in Enum.GetValues(typeof(MediaType)))
|
||||
{
|
||||
if (((MediaType)val) == MediaType.NONE)
|
||||
continue;
|
||||
|
||||
Console.WriteLine($"{((MediaType?)val).ShortName()} - {((MediaType?)val).LongName()}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List all known systems with their short usable names
|
||||
/// </summary>
|
||||
private static void ListKnownSystems()
|
||||
{
|
||||
Console.WriteLine("Supported Known Systems:");
|
||||
foreach (var val in Enum.GetValues(typeof(KnownSystem)))
|
||||
{
|
||||
if (((KnownSystem)val) == KnownSystem.NONE)
|
||||
continue;
|
||||
|
||||
Console.WriteLine($"{((KnownSystem?)val).ShortName()} - {((KnownSystem?)val).LongName()}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple process counter to write to console
|
||||
/// </summary>
|
||||
private static void ProgressUpdated(object sender, Result value)
|
||||
{
|
||||
Console.WriteLine(value.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("DICUI.Check")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("DICUI.Check")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2019")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("8cfde289-e171-4d49-a40d-5293265c1253")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.16")]
|
||||
[assembly: AssemblyFileVersion("1.16.0.0")]
|
||||
@@ -1,455 +0,0 @@
|
||||
namespace DICUI.Aaru
|
||||
{
|
||||
/// <summary>
|
||||
/// Top-level commands for Aaru
|
||||
/// </summary>
|
||||
public static class CommandStrings
|
||||
{
|
||||
// Database Family
|
||||
public const string DatabasePrefixShort = "db";
|
||||
public const string DatabasePrefixLong = "database";
|
||||
public const string DatabaseStats = "stats";
|
||||
public const string DatabaseUpdate = "update";
|
||||
|
||||
// Device Family
|
||||
public const string DevicePrefixShort = "dev";
|
||||
public const string DevicePrefixLong = "device";
|
||||
public const string DeviceInfo = "info";
|
||||
public const string DeviceList = "list";
|
||||
public const string DeviceReport = "report";
|
||||
|
||||
// Filesystem Family
|
||||
public const string FilesystemPrefixShort = "fi";
|
||||
public const string FilesystemPrefixShortAlt = "fs";
|
||||
public const string FilesystemPrefixLong = "filesystem";
|
||||
public const string FilesystemExtract = "extract";
|
||||
public const string FilesystemListShort = "ls";
|
||||
public const string FilesystemListLong = "list";
|
||||
public const string FilesystemOptions = "options";
|
||||
|
||||
// Image Family
|
||||
public const string ImagePrefixShort = "i";
|
||||
public const string ImagePrefixLong = "image";
|
||||
public const string ImageAnalyze = "analyze";
|
||||
public const string ImageChecksumShort = "chk";
|
||||
public const string ImageChecksumLong = "checksum";
|
||||
public const string ImageCompareShort = "cmp";
|
||||
public const string ImageCompareLong = "compare";
|
||||
public const string ImageConvert = "convert";
|
||||
public const string ImageCreateSidecar = "create-sidecar";
|
||||
public const string ImageDecode = "decode";
|
||||
public const string ImageEntropy = "entropy";
|
||||
public const string ImageInfo = "info";
|
||||
public const string ImageOptions = "options";
|
||||
public const string ImagePrint = "print";
|
||||
public const string ImageVerify = "verify";
|
||||
|
||||
// Media Family
|
||||
public const string MediaPrefixShort = "m";
|
||||
public const string MediaPrefixLong = "media";
|
||||
public const string MediaDump = "dump";
|
||||
public const string MediaInfo = "info";
|
||||
public const string MediaScan = "scan";
|
||||
|
||||
// Standalone Commands
|
||||
public const string Configure = "configure";
|
||||
public const string Formats = "formats";
|
||||
public const string ListEncodings = "list-encodings";
|
||||
public const string ListNamespaces = "list-namespaces";
|
||||
public const string Remote = "remote";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supported encodings for Aaru
|
||||
/// </summary>
|
||||
public static class EncodingStrings
|
||||
{
|
||||
public static string ArabicMac = "x-mac-arabic";
|
||||
public static string AtariASCII = "atascii";
|
||||
public static string CentralEuropeanMac = "x-mac-ce";
|
||||
public static string CommodorePETSCII = "petscii";
|
||||
public static string CroatianMac = "x-mac-croatian";
|
||||
public static string CyrillicMac = "x-mac-cryillic";
|
||||
public static string FarsiMac = "x-mac-farsi";
|
||||
public static string GreekMac = "x-mac-greek";
|
||||
public static string HebrewMac = "x-mac-hebrew";
|
||||
public static string RomanianMac = "x-mac-romanian";
|
||||
public static string SinclairZXSpectrum = "spectrum";
|
||||
public static string SinclairZX80 = "zx80";
|
||||
public static string SinclairZX81 = "zx81";
|
||||
public static string TurkishMac = "x-mac-turkish";
|
||||
public static string UkrainianMac = "x-mac-ukrainian";
|
||||
public static string Unicode = "utf-16";
|
||||
public static string UnicodeBigEndian = "utf-16BE";
|
||||
public static string UnicodeUTF32BigEndian = "utf-32BE";
|
||||
public static string UnicodeUTF32 = "utf-32";
|
||||
public static string UnicodeUTF7 = "utf-7";
|
||||
public static string UnicodeUTF8 = "utf-8";
|
||||
public static string USASCII = "us-ascii";
|
||||
public static string WesternEuropeanAppleII = "apple2";
|
||||
public static string WesternEuropeanAppleIIc = "apple2c";
|
||||
public static string WesternEuropeanAppleIIe = "apple2e";
|
||||
public static string WesternEuropeanAppleIIgs = "apple2gs";
|
||||
public static string WesternEuropeanAppleLisa = "lisa";
|
||||
public static string WesternEuropeanAtariST = "atarist";
|
||||
public static string WesternEuropeanGEM = "gem";
|
||||
public static string WesternEuropeanGEOS = "geos";
|
||||
public static string WesternEuropeanISO = "iso-8859-1";
|
||||
public static string WesternEuropeanMac = "macintosh";
|
||||
public static string WesternEuropeanRadix50 = "radix50";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dumping flags for Aaru
|
||||
/// </summary>
|
||||
public static class FlagStrings
|
||||
{
|
||||
// Boolean flags
|
||||
public const string Adler32Short = "-a";
|
||||
public const string Adler32Long = "--adler32";
|
||||
public const string ClearLong = "--clear";
|
||||
public const string ClearAllLong = "--clear-all";
|
||||
public const string CRC16Long = "--crc16";
|
||||
public const string CRC32Short = "-c";
|
||||
public const string CRC32Long = "--crc32";
|
||||
public const string CRC64Long = "--crc64";
|
||||
public const string DebugShort = "-d";
|
||||
public const string DebugLong = "--debug";
|
||||
public const string DiskTagsShort = "-f";
|
||||
public const string DiskTagsLong = "--disk-tags";
|
||||
public const string DuplicatedSectorsShort = "-p";
|
||||
public const string DuplicatedSectorsLong = "--duplicated-sectors";
|
||||
public const string ExtendedAttributesShort = "-x";
|
||||
public const string ExtendedAttributesLong = "--xattrs";
|
||||
public const string FilesystemsShort = "-f";
|
||||
public const string FilesystemsLong = "--filesystems";
|
||||
public const string FirstPregapLong = "--first-pregap";
|
||||
public const string FixOffsetLong = "--fix-offset";
|
||||
public const string Fletcher16Long = "--fletcher16";
|
||||
public const string Fletcher32Long = "--fletcher32";
|
||||
public const string ForceShort = "-f";
|
||||
public const string ForceLong = "--force";
|
||||
public const string LongFormatShort = "-l";
|
||||
public const string LongFormatLong = "--long-format";
|
||||
public const string LongSectorsShort = "-r";
|
||||
public const string LongSectorsLong = "--long-sectors";
|
||||
public const string MD5Short = "-m";
|
||||
public const string MD5Long = "--md5";
|
||||
public const string MetadataLong = "--metadata";
|
||||
public const string PartitionsShort = "-p";
|
||||
public const string PartitionsLong = "--partitions";
|
||||
public const string PersistentLong = "--persistent";
|
||||
public const string ResumeShort = "-r";
|
||||
public const string ResumeLong = "--resume";
|
||||
public const string SectorTagsShort = "-p";
|
||||
public const string SectorTagsLong = "--sector-tags";
|
||||
public const string SeparatedTracksShort = "-t";
|
||||
public const string SeparatedTracksLong = "--separated-tracks";
|
||||
public const string SHA1Short = "-s";
|
||||
public const string SHA1Long = "--sha1";
|
||||
public const string SHA256Long = "--sha256";
|
||||
public const string SHA384Long = "--sha384";
|
||||
public const string SHA512Long = "--sha512";
|
||||
public const string SpamSumShort = "-f";
|
||||
public const string SpamSumLong = "--spamsum";
|
||||
public const string StopOnErrorShort = "-s";
|
||||
public const string StopOnErrorLong = "--stop-on-error";
|
||||
public const string TapeShort = "-t";
|
||||
public const string TapeLong = "--tape";
|
||||
public const string TrimLong = "--trim";
|
||||
public const string VerboseShort = "-v";
|
||||
public const string VerboseLong = "--verbose";
|
||||
public const string VerifyDiscShort = "-w";
|
||||
public const string VerifyDiscLong = "--verify-disc";
|
||||
public const string VerifySectorsShort = "-s";
|
||||
public const string VerifySectorsLong = "--verify-sectors";
|
||||
public const string VersionLong = "--version";
|
||||
public const string WholeDiscShort = "-w";
|
||||
public const string WholeDiscLong = "--whole-disc";
|
||||
|
||||
// Int8 flags
|
||||
public const string SpeedLong = "--speed";
|
||||
|
||||
// Int16 flags
|
||||
public const string RetryPassesShort = "-p";
|
||||
public const string RetryPassesLong = "--retry-passes";
|
||||
public const string WidthShort = "-w";
|
||||
public const string WidthLong = "--width";
|
||||
|
||||
// Int32 flags
|
||||
public const string BlockSizeShort = "-b";
|
||||
public const string BlockSizeLong = "--block-size";
|
||||
public const string CountShort = "-c";
|
||||
public const string CountLong = "--count";
|
||||
public const string MediaLastSequenceLong = "--media-lastsequence";
|
||||
public const string MediaSequenceLong = "--media-sequence";
|
||||
public const string SkipShort = "-k";
|
||||
public const string SkipLong = "--skip";
|
||||
|
||||
// Int64 flags
|
||||
public const string LengthShort = "-l"; // or "all"
|
||||
public const string LengthLong = "--length"; // or "all"
|
||||
public const string StartShort = "-s";
|
||||
public const string StartLong = "--start";
|
||||
|
||||
// String flags
|
||||
public const string CommentsLong = "--comments";
|
||||
public const string CreatorLong = "--creator";
|
||||
public const string DriveManufacturerLong = "--drive-manufacturer";
|
||||
public const string DriveModelLong = "--drive-model";
|
||||
public const string DriveRevisionLong = "--drive-revision";
|
||||
public const string DriveSerialLong = "--drive-serial";
|
||||
public const string EncodingShort = "-e";
|
||||
public const string EncodingLong = "--encoding";
|
||||
public const string FormatConvertShort = "-p";
|
||||
public const string FormatConvertLong = "--format";
|
||||
public const string FormatDumpShort = "-t";
|
||||
public const string FormatDumpLong = "--format";
|
||||
public const string ImgBurnLogShort = "-b";
|
||||
public const string ImgBurnLogLong = "--ibg-log";
|
||||
public const string MediaBarcodeLong = "--media-barcode";
|
||||
public const string MediaManufacturerLong = "--media-manufacturer";
|
||||
public const string MediaModelLong = "--media-model";
|
||||
public const string MediaPartNumberLong = "--media-partnumber";
|
||||
public const string MediaSerialLong = "--media-serial";
|
||||
public const string MediaTitleLong = "--media-title";
|
||||
public const string MHDDLogShort = "-m";
|
||||
public const string MHDDLogLong = "--mhdd-log";
|
||||
public const string NamespaceShort = "-n";
|
||||
public const string NamespaceLong = "--namespace";
|
||||
public const string OptionsShort = "-O";
|
||||
public const string OptionsLong = "--options";
|
||||
public const string OutputPrefixShort = "-w";
|
||||
public const string OutputPrefixLong = "--output-prefix";
|
||||
public const string ResumeFileShort = "-r";
|
||||
public const string ResumeFileLong = "--resume-file";
|
||||
public const string SubchannelLong = "--subchannel";
|
||||
public const string XMLSidecarShort = "-x";
|
||||
public const string XMLSidecarLong = "--cicm-xml";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supported formats for Aaru
|
||||
/// </summary>
|
||||
public static class FormatStrings
|
||||
{
|
||||
// Supported filters
|
||||
public static string AppleDouble = "AppleDouble";
|
||||
public static string AppleSingle = "AppleSingle";
|
||||
public static string BZip2 = "BZip2";
|
||||
public static string GZip = "GZip";
|
||||
public static string LZip = "LZip";
|
||||
public static string MacBinary = "MacBinary";
|
||||
public static string NoFilter = "No filter";
|
||||
public static string PCExchange = "PCExchange";
|
||||
public static string XZ = "XZ";
|
||||
|
||||
// Read-only media image formats
|
||||
public static string AppleDiskArchivalRetrievalTool = "Apple Disk Archival/Retrieval Tool";
|
||||
public static string AppleNewDiskImageFormat = "Apple New Disk Image Format";
|
||||
public static string AppleNIB = "Apple NIB";
|
||||
public static string BlindWrite4 = "BlindWrite 4";
|
||||
public static string BlindWrite5 = "BlindWrite 5";
|
||||
public static string CPCEMUDiskFileAndExtendedCPCDiskFile = "CPCEMU Disk-File and Extended CPC Disk-File";
|
||||
public static string D2FDiskImage = "d2f disk image";
|
||||
public static string D88DiskImage = "D88 Disk Image";
|
||||
public static string DIMDiskImage = "DIM Disk Image";
|
||||
public static string DiscFerret = "DiscFerret";
|
||||
public static string DiscJuggler = "DiscJuggler";
|
||||
public static string DreamcastGDIImage = "Dreamcast GDI image";
|
||||
public static string DunfieldsIMD = "Dunfield's IMD";
|
||||
public static string HDCopyDiskImage = "HD-Copy disk image";
|
||||
public static string KryoFluxSTREAM = "KryoFlux STREAM";
|
||||
public static string MAMECompressedHunksOfData = "MAME Compressed Hunks of Data";
|
||||
public static string MicrosoftVHDX = "Microsoft VHDX";
|
||||
public static string NeroBurningROMImage = "Nero Burning ROM image";
|
||||
public static string PartCloneDiskImage = "PartClone disk image";
|
||||
public static string PartimageDiskImage = "Partimage disk image";
|
||||
public static string SpectrumFloppyDiskImage = "Spectrum Floppy Disk Image";
|
||||
public static string SuperCardPro = "SuperCardPro";
|
||||
public static string SydexCopyQM = "Sydex CopyQM";
|
||||
public static string SydexTeleDisk = "Sydex TeleDisk";
|
||||
|
||||
// Read/write media image formats
|
||||
public static string ACTApricotDiskImage = "ACT Apricot Disk Image";
|
||||
public static string Alcohol120MediaDescriptorStructure = "Alcohol 120% Media Descriptor Structure";
|
||||
public static string Anex86DiskImage = "Anex86 Disk Image";
|
||||
public static string Apple2InterleavedDiskImage = "Apple ][Interleaved Disk Image";
|
||||
public static string Apple2IMG = "Apple 2IMG";
|
||||
public static string AppleDiskCopy42 = "Apple DiskCopy 4.2";
|
||||
public static string AppleUniversalDiskImageFormat = "Apple Universal Disk Image Format";
|
||||
public static string BasicLisaUtility = "Basic Lisa Utility";
|
||||
public static string CDRDAOTocfile = "CDRDAO tocfile";
|
||||
public static string CDRWinCuesheet = "CDRWin cuesheet";
|
||||
public static string CisCopyDiskImageDCFile = "CisCopy Disk Image(DC-File)";
|
||||
public static string CloneCD = "CloneCD";
|
||||
public static string CopyTape = "CopyTape";
|
||||
public static string DigitalResearchDiskCopy = "Digital Research DiskCopy";
|
||||
public static string AaruFormat = "Aaru format";
|
||||
public static string IBMSaveDskF = "IBM SaveDskF";
|
||||
public static string MAXIDiskImage = "MAXI Disk image";
|
||||
public static string ParallelsDiskImage = "Parallels disk image";
|
||||
public static string QEMUCopyOnWriteDiskImage = "QEMU Copy-On-Write disk image";
|
||||
public static string QEMUCopyOnWriteDiskImageV2 = "QEMU Copy-On-Write disk image v2";
|
||||
public static string QEMUEnhancedDiskImage = "QEMU Enhanced Disk image";
|
||||
public static string RawDiskImage = "Raw Disk Image";
|
||||
public static string RayAracheliansDiskIMage = "Ray Arachelian's Disk IMage";
|
||||
public static string RSIDEHardDiskImage = "RS-IDE Hard Disk Image";
|
||||
public static string T98HardDiskImage = "T98 Hard Disk Image";
|
||||
public static string T98NextNHDr0DiskImage = "T98-Next NHD r0 Disk Image";
|
||||
public static string Virtual98DiskImage = "Virtual98 Disk Image";
|
||||
public static string VirtualBoxDiskImage = "VirtualBox Disk Image";
|
||||
public static string VirtualPC = "VirtualPC";
|
||||
public static string VMwareDiskImage = "VMware disk image";
|
||||
|
||||
// Supported filesystems for identification and information only
|
||||
public static string AcornAdvancedDiscFilingSystem = "Acorn Advanced Disc Filing System";
|
||||
public static string AlexanderOsipovDOSFileSystem = "Alexander Osipov DOS file system";
|
||||
public static string AmigaDOSFilesystem = "Amiga DOS filesystem";
|
||||
public static string AppleFileSystem = "Apple File System";
|
||||
public static string AppleHFSPlusFilesystem = "Apple HFS+ filesystem";
|
||||
public static string AppleHierarchicalFileSystem = "Apple Hierarchical File System";
|
||||
public static string AppleProDOSFilesystem = "Apple ProDOS filesystem";
|
||||
public static string AtheOSFilesystem = "AtheOS Filesystem";
|
||||
public static string BeFilesystem = "Be Filesystem";
|
||||
public static string BSDFastFileSystem = "BSD Fast File System(aka UNIX File System, UFS)";
|
||||
public static string BTreeFileSystem = "B-tree file system";
|
||||
public static string CommodoreFileSystem = "Commodore file system";
|
||||
public static string CramFilesystem = "Cram filesystem";
|
||||
public static string DumpEightPlugin = "dump(8) Plugin";
|
||||
public static string ECMA67 = "ECMA-67";
|
||||
public static string ExtentFileSystemPlugin = "Extent File System Plugin";
|
||||
public static string F2FSPlugin = "F2FS Plugin";
|
||||
public static string Files11OnDiskStructure = "Files-11 On-Disk Structure";
|
||||
public static string FossilFilesystemPlugin = "Fossil Filesystem Plugin";
|
||||
public static string HAMMERFilesystem = "HAMMER Filesystem";
|
||||
public static string HighPerformanceOpticalFileSystem = "High Performance Optical File System";
|
||||
public static string HPLogicalInterchangeFormatPlugin = "HP Logical Interchange Format Plugin";
|
||||
public static string JFSPlugin = "JFS Plugin";
|
||||
public static string LinuxExtendedFilesystem = "Linux extended Filesystem";
|
||||
public static string LinuxExtendedFilesystem234 = "Linux extended Filesystem 2, 3 and 4";
|
||||
public static string LocusFilesystemPlugin = "Locus Filesystem Plugin";
|
||||
public static string MicroDOSFileSystem = "MicroDOS file system";
|
||||
public static string MicrosoftExtendedFileAllocationTable = "Microsoft Extended File Allocation Table";
|
||||
public static string MinixFilesystem = "Minix Filesystem";
|
||||
public static string NewTechnologyFileSystem = "New Technology File System(NTFS)";
|
||||
public static string NILFS2Plugin = "NILFS2 Plugin";
|
||||
public static string NintendoOpticalFilesystems = "Nintendo optical filesystems";
|
||||
public static string OS2HighPerformanceFileSystem = "OS/2 High Performance File System";
|
||||
public static string OS9RandomBlockFilePlugin = "OS-9 Random Block File Plugin";
|
||||
public static string PCEngineCDPlugin = "PC Engine CD Plugin";
|
||||
public static string PCFXPlugin = "PC-FX Plugin";
|
||||
public static string ProfessionalFileSystem = "Professional File System";
|
||||
public static string QNX4Plugin = "QNX4 Plugin";
|
||||
public static string QNX6Plugin = "QNX6 Plugin";
|
||||
public static string ReiserFilesystemPlugin = "Reiser Filesystem Plugin";
|
||||
public static string Reiser4FilesystemPlugin = "Reiser4 Filesystem Plugin";
|
||||
public static string ResilientFileSystemPlugin = "Resilient File System plugin";
|
||||
public static string RT11FileSystem = "RT-11 file system";
|
||||
public static string SmartFileSystem = "SmartFileSystem";
|
||||
public static string SolarOSFilesystem = "Solar_OS filesystem";
|
||||
public static string SquashFilesystem = "Squash filesystem";
|
||||
public static string UNICOSFilesystemPlugin = "UNICOS Filesystem Plugin";
|
||||
public static string UniversalDiskFormat = "Universal Disk Format";
|
||||
public static string UNIXBootFilesystem = "UNIX Boot filesystem";
|
||||
public static string UNIXSystemVFilesystem = "UNIX System V filesystem";
|
||||
public static string VeritasFilesystem = "Veritas filesystem";
|
||||
public static string VMwareFilesystem = "VMware filesystem";
|
||||
public static string XFSFilesystemPlugin = "XFS Filesystem Plugin";
|
||||
public static string XiaFilesystem = "Xia filesystem";
|
||||
public static string ZFSFilesystemPlugin = "ZFS Filesystem Plugin";
|
||||
|
||||
// Supported filesystems that can read their contents
|
||||
public static string AppleDOSFileSystem = "Apple DOS File System";
|
||||
public static string AppleLisaFileSystem = "Apple Lisa File System";
|
||||
public static string AppleMacintoshFileSystem = "Apple Macintosh File System";
|
||||
public static string CPMFileSystem = "CP/M File System";
|
||||
public static string FATXFilesystemPlugin = "FATX Filesystem Plugin";
|
||||
public static string ISO9660Filesystem = "ISO9660 Filesystem";
|
||||
public static string MicrosoftFileAllocationTable = "Microsoft File Allocation Table";
|
||||
public static string OperaFilesystemPlugin = "Opera Filesystem Plugin";
|
||||
public static string UCSDPascalFilesystem = "U.C.S.D.Pascal filesystem";
|
||||
|
||||
// Supported partitioning schemes
|
||||
public static string AcornFileCorePartitions = "Acorn FileCore partitions";
|
||||
public static string ACTApricotPartitions = "ACT Apricot partitions";
|
||||
public static string AmigaRigidDiskBlock = "Amiga Rigid Disk Block";
|
||||
public static string ApplePartitionMap = "Apple Partition Map";
|
||||
public static string AtariPartitions = "Atari partitions";
|
||||
public static string BSDDisklabel = "BSD disklabel";
|
||||
public static string DECDisklabel = "DEC disklabel";
|
||||
public static string DragonFlyBSD64bitDisklabel = "DragonFly BSD 64-bit disklabel";
|
||||
public static string GUIDPartitionTable = "GUID Partition Table";
|
||||
public static string Human68kPartitions = "Human 68k partitions";
|
||||
public static string MasterBootRecord = "Master Boot Record";
|
||||
public static string NECPC9800PartitionTable = "NEC PC-9800 partition table";
|
||||
public static string NeXTDisklabel = "NeXT Disklabel";
|
||||
public static string Plan9PartitionTable = "Plan9 partition table";
|
||||
public static string RioKarmaPartitioning = "Rio Karma partitioning";
|
||||
public static string SGIDiskVolumeHeader = "SGI Disk Volume Header";
|
||||
public static string SunDisklabel = "Sun Disklabel";
|
||||
public static string UNIXHardwired = "UNIX hardwired";
|
||||
public static string UNIXVTOC = "UNIX VTOC";
|
||||
public static string XboxPartitioning = "Xbox partitioning";
|
||||
public static string XENIX = "XENIX";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supported namespaces for Aaru
|
||||
/// </summary>
|
||||
public static class NamespaceStrings
|
||||
{
|
||||
// Namespaces for Apple Lisa File System
|
||||
public static string LisaOfficeSystem = "office";
|
||||
public static string LisaPascalWorkshop = "workshop";
|
||||
|
||||
// Namespaces for ISO9660 Filesystem
|
||||
public static string JolietVolumeDescriptor = "joliet";
|
||||
public static string PrimaryVolumeDescriptor = "normal";
|
||||
public static string PrimaryVolumeDescriptorwithEncoding = "romeo";
|
||||
public static string RockRidge = "rrip";
|
||||
public static string PrimaryVolumeDescriptorVersionSuffix = "vms";
|
||||
|
||||
// Namespaces for Microsoft File Allocation Table
|
||||
public static string DOS = "dos";
|
||||
public static string LFNWhenAvailable = "ecs";
|
||||
public static string LongFileNames = "lfn";
|
||||
public static string WindowsNT = "nt";
|
||||
public static string OS2Extended = "os2";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supported options for Aaru
|
||||
/// </summary>
|
||||
public static class OptionStrings
|
||||
{
|
||||
// ACT Apricot Disk Image
|
||||
public static string ACTApricotDiskImageCompress = "compress"; // boolean, default false
|
||||
|
||||
// Apple DiskCopy 4.2
|
||||
public static string AppleDiskCopyMacOSX = "macosx"; // boolean, default false
|
||||
|
||||
// CDRDAO tocfile
|
||||
public static string CDRDAOTocfileSeparate = "separate"; // boolean, default false
|
||||
|
||||
// CDRWin cuesheet
|
||||
public static string CDRWinCuesheetSeparate = "separate"; // boolean, default false
|
||||
|
||||
// Aaru format
|
||||
public static string AaruDeduplicate = "deduplicate"; // boolean, default true
|
||||
public static string AaruDictionary = "dictionary"; // number, default 33554432
|
||||
public static string AaruMaxDDTSize = "max_ddt_size"; // number, default 256
|
||||
public static string AaruMD5 = "md5"; // boolean, default false
|
||||
public static string AaruNoCompress = "nocompress"; // boolean, default false
|
||||
public static string AaruSectorsPerBlock = "sectors_per_block"; // number, default 4096
|
||||
public static string AaruSHA1 = "sha1"; // boolean, default false
|
||||
public static string AaruSHA256 = "sha256"; // boolean, default false
|
||||
public static string AaruSpamSum = "spamsum"; // boolean, default false
|
||||
|
||||
// VMware disk image
|
||||
public static string VMwareDiskImageAdapterType = "adapter_type"; // string, default ide
|
||||
public static string VMwareDiskImageHWVersion = "hwversion"; // number, default 4
|
||||
public static string VMwareDiskImageSparse = "sparse"; // boolean, default false
|
||||
public static string VMwareDiskImageSplit = "split"; // boolean, default false
|
||||
}
|
||||
}
|
||||
@@ -1,406 +0,0 @@
|
||||
using DICUI.Data;
|
||||
|
||||
namespace DICUI.Aaru
|
||||
{
|
||||
public static class Converters
|
||||
{
|
||||
#region Cross-enumeration conversions
|
||||
|
||||
/// <summary>
|
||||
/// Get the default extension for a given disc type
|
||||
/// </summary>
|
||||
/// <param name="type">MediaType value to check</param>
|
||||
/// <returns>Valid extension (with leading '.'), null on error</returns>
|
||||
public static string Extension(MediaType? type)
|
||||
{
|
||||
// Aaru has a single, unified output format by default
|
||||
return ".aif";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Convert to Long Name
|
||||
|
||||
/// <summary>
|
||||
/// Get the string representation of the Command enum values
|
||||
/// </summary>
|
||||
/// <param name="command">Command value to convert</param>
|
||||
/// <returns>String representing the value, if possible</returns>
|
||||
public static string LongName(Command command)
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
// Database Family
|
||||
case Command.DatabaseStats:
|
||||
return $"{CommandStrings.DatabasePrefixLong} {CommandStrings.DatabaseStats}";
|
||||
case Command.DatabaseUpdate:
|
||||
return $"{CommandStrings.DatabasePrefixLong} {CommandStrings.DatabaseUpdate}";
|
||||
|
||||
// Device Family
|
||||
case Command.DeviceInfo:
|
||||
return $"{CommandStrings.DevicePrefixLong} {CommandStrings.DeviceInfo}";
|
||||
case Command.DeviceList:
|
||||
return $"{CommandStrings.DevicePrefixLong} {CommandStrings.DeviceList}";
|
||||
case Command.DeviceReport:
|
||||
return $"{CommandStrings.DevicePrefixLong} {CommandStrings.DeviceReport}";
|
||||
|
||||
// Filesystem Family
|
||||
case Command.FilesystemExtract:
|
||||
return $"{CommandStrings.FilesystemPrefixLong} {CommandStrings.FilesystemExtract}";
|
||||
case Command.FilesystemList:
|
||||
return $"{CommandStrings.FilesystemPrefixLong} {CommandStrings.FilesystemListLong}";
|
||||
case Command.FilesystemOptions:
|
||||
return $"{CommandStrings.FilesystemPrefixLong} {CommandStrings.FilesystemOptions}";
|
||||
|
||||
// Image Family
|
||||
case Command.ImageAnalyze:
|
||||
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageAnalyze}";
|
||||
case Command.ImageChecksum:
|
||||
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageChecksumLong}";
|
||||
case Command.ImageCompare:
|
||||
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageCompareLong}";
|
||||
case Command.ImageConvert:
|
||||
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageConvert}";
|
||||
case Command.ImageCreateSidecar:
|
||||
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageCreateSidecar}";
|
||||
case Command.ImageDecode:
|
||||
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageDecode}";
|
||||
case Command.ImageEntropy:
|
||||
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageEntropy}";
|
||||
case Command.ImageInfo:
|
||||
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageInfo}";
|
||||
case Command.ImageOptions:
|
||||
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageOptions}";
|
||||
case Command.ImagePrint:
|
||||
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImagePrint}";
|
||||
case Command.ImageVerify:
|
||||
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageVerify}";
|
||||
|
||||
// Media Family
|
||||
case Command.MediaDump:
|
||||
return $"{CommandStrings.MediaPrefixLong} {CommandStrings.MediaDump}";
|
||||
case Command.MediaInfo:
|
||||
return $"{CommandStrings.MediaPrefixLong} {CommandStrings.MediaInfo}";
|
||||
case Command.MediaScan:
|
||||
return $"{CommandStrings.MediaPrefixLong} {CommandStrings.MediaScan}";
|
||||
|
||||
// Standalone Commands
|
||||
case Command.Configure:
|
||||
return CommandStrings.Configure;
|
||||
case Command.Formats:
|
||||
return CommandStrings.Formats;
|
||||
case Command.ListEncodings:
|
||||
return CommandStrings.ListEncodings;
|
||||
case Command.ListNamespaces:
|
||||
return CommandStrings.ListNamespaces;
|
||||
case Command.Remote:
|
||||
return CommandStrings.Remote;
|
||||
|
||||
case Command.NONE:
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string representation of the Flag enum values
|
||||
/// </summary>
|
||||
/// <param name="command">Flag value to convert</param>
|
||||
/// <returns>String representing the value, if possible</returns>
|
||||
public static string LongName(Flag flag)
|
||||
{
|
||||
switch (flag)
|
||||
{
|
||||
// Boolean flags
|
||||
case Flag.Adler32:
|
||||
return FlagStrings.Adler32Long;
|
||||
case Flag.Clear:
|
||||
return FlagStrings.ClearLong;
|
||||
case Flag.ClearAll:
|
||||
return FlagStrings.ClearAllLong;
|
||||
case Flag.CRC16:
|
||||
return FlagStrings.CRC16Long;
|
||||
case Flag.CRC32:
|
||||
return FlagStrings.CRC32Long;
|
||||
case Flag.CRC64:
|
||||
return FlagStrings.CRC64Long;
|
||||
case Flag.Debug:
|
||||
return FlagStrings.DebugLong;
|
||||
case Flag.DiskTags:
|
||||
return FlagStrings.DiskTagsLong;
|
||||
case Flag.DuplicatedSectors:
|
||||
return FlagStrings.DuplicatedSectorsLong;
|
||||
case Flag.ExtendedAttributes:
|
||||
return FlagStrings.ExtendedAttributesLong;
|
||||
case Flag.Filesystems:
|
||||
return FlagStrings.FilesystemsLong;
|
||||
case Flag.FirstPregap:
|
||||
return FlagStrings.FirstPregapLong;
|
||||
case Flag.FixOffset:
|
||||
return FlagStrings.FixOffsetLong;
|
||||
case Flag.Fletcher16:
|
||||
return FlagStrings.Fletcher16Long;
|
||||
case Flag.Fletcher32:
|
||||
return FlagStrings.Fletcher32Long;
|
||||
case Flag.Force:
|
||||
return FlagStrings.ForceLong;
|
||||
case Flag.LongFormat:
|
||||
return FlagStrings.LongFormatLong;
|
||||
case Flag.LongSectors:
|
||||
return FlagStrings.LongSectorsLong;
|
||||
case Flag.MD5:
|
||||
return FlagStrings.MD5Long;
|
||||
case Flag.Metadata:
|
||||
return FlagStrings.MetadataLong;
|
||||
case Flag.Partitions:
|
||||
return FlagStrings.PartitionsLong;
|
||||
case Flag.Persistent:
|
||||
return FlagStrings.PersistentLong;
|
||||
case Flag.Resume:
|
||||
return FlagStrings.ResumeLong;
|
||||
case Flag.SectorTags:
|
||||
return FlagStrings.SectorTagsLong;
|
||||
case Flag.SeparatedTracks:
|
||||
return FlagStrings.SeparatedTracksLong;
|
||||
case Flag.SHA1:
|
||||
return FlagStrings.SHA1Long;
|
||||
case Flag.SHA256:
|
||||
return FlagStrings.SHA256Long;
|
||||
case Flag.SHA384:
|
||||
return FlagStrings.SHA384Long;
|
||||
case Flag.SHA512:
|
||||
return FlagStrings.SHA512Long;
|
||||
case Flag.SpamSum:
|
||||
return FlagStrings.SpamSumLong;
|
||||
case Flag.StopOnError:
|
||||
return FlagStrings.StopOnErrorLong;
|
||||
case Flag.Tape:
|
||||
return FlagStrings.TapeLong;
|
||||
case Flag.Trim:
|
||||
return FlagStrings.TrimLong;
|
||||
case Flag.Verbose:
|
||||
return FlagStrings.VerboseLong;
|
||||
case Flag.VerifyDisc:
|
||||
return FlagStrings.VerifyDiscLong;
|
||||
case Flag.VerifySectors:
|
||||
return FlagStrings.VerifySectorsLong;
|
||||
case Flag.Version:
|
||||
return FlagStrings.VersionLong;
|
||||
case Flag.WholeDisc:
|
||||
return FlagStrings.WholeDiscLong;
|
||||
|
||||
// Int8 flags
|
||||
case Flag.Speed:
|
||||
return FlagStrings.SpeedLong;
|
||||
|
||||
// Int16 flags
|
||||
case Flag.RetryPasses:
|
||||
return FlagStrings.RetryPassesLong;
|
||||
case Flag.Width:
|
||||
return FlagStrings.WidthLong;
|
||||
|
||||
// Int32 flags
|
||||
case Flag.BlockSize:
|
||||
return FlagStrings.BlockSizeLong;
|
||||
case Flag.Count:
|
||||
return FlagStrings.CountLong;
|
||||
case Flag.MediaLastSequence:
|
||||
return FlagStrings.MediaLastSequenceLong;
|
||||
case Flag.MediaSequence:
|
||||
return FlagStrings.MediaSequenceLong;
|
||||
case Flag.Skip:
|
||||
return FlagStrings.SkipLong;
|
||||
|
||||
// Int64 flags
|
||||
case Flag.Length:
|
||||
return FlagStrings.LengthLong;
|
||||
case Flag.Start:
|
||||
return FlagStrings.StartLong;
|
||||
|
||||
// String flags
|
||||
case Flag.Comments:
|
||||
return FlagStrings.CommentsLong;
|
||||
case Flag.Creator:
|
||||
return FlagStrings.CreatorLong;
|
||||
case Flag.DriveManufacturer:
|
||||
return FlagStrings.DriveManufacturerLong;
|
||||
case Flag.DriveModel:
|
||||
return FlagStrings.DriveModelLong;
|
||||
case Flag.DriveRevision:
|
||||
return FlagStrings.DriveRevisionLong;
|
||||
case Flag.DriveSerial:
|
||||
return FlagStrings.DriveSerialLong;
|
||||
case Flag.Encoding:
|
||||
return FlagStrings.EncodingLong;
|
||||
case Flag.FormatConvert:
|
||||
return FlagStrings.FormatConvertLong;
|
||||
case Flag.FormatDump:
|
||||
return FlagStrings.FormatDumpLong;
|
||||
case Flag.ImgBurnLog:
|
||||
return FlagStrings.ImgBurnLogLong;
|
||||
case Flag.MediaBarcode:
|
||||
return FlagStrings.MediaBarcodeLong;
|
||||
case Flag.MediaManufacturer:
|
||||
return FlagStrings.MediaManufacturerLong;
|
||||
case Flag.MediaModel:
|
||||
return FlagStrings.MediaModelLong;
|
||||
case Flag.MediaPartNumber:
|
||||
return FlagStrings.MediaPartNumberLong;
|
||||
case Flag.MediaSerial:
|
||||
return FlagStrings.MediaSerialLong;
|
||||
case Flag.MediaTitle:
|
||||
return FlagStrings.MediaTitleLong;
|
||||
case Flag.MHDDLog:
|
||||
return FlagStrings.MHDDLogLong;
|
||||
case Flag.Namespace:
|
||||
return FlagStrings.NamespaceLong;
|
||||
case Flag.Options:
|
||||
return FlagStrings.OptionsLong;
|
||||
case Flag.OutputPrefix:
|
||||
return FlagStrings.OutputPrefixLong;
|
||||
case Flag.ResumeFile:
|
||||
return FlagStrings.ResumeFileLong;
|
||||
case Flag.Subchannel:
|
||||
return FlagStrings.SubchannelLong;
|
||||
case Flag.XMLSidecar:
|
||||
return FlagStrings.XMLSidecarLong;
|
||||
|
||||
case Flag.NONE:
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Convert From String
|
||||
|
||||
/// <summary>
|
||||
/// Get the Command enum value for a given string
|
||||
/// </summary>
|
||||
/// <param name="commandOne">First part of String value to convert</param>
|
||||
/// <param name="commandTwo">Second part of String value to convert</param>
|
||||
/// <param name="useSecond">Output bool if the second command was used</param>
|
||||
/// <returns>Command represented by the string(s), if possible</returns>
|
||||
public static Command StringToCommand(string commandOne, string commandTwo, out bool useSecond)
|
||||
{
|
||||
useSecond = false;
|
||||
switch (commandOne)
|
||||
{
|
||||
// Database Family
|
||||
case CommandStrings.DatabasePrefixShort:
|
||||
case CommandStrings.DatabasePrefixLong:
|
||||
useSecond = true;
|
||||
switch (commandTwo)
|
||||
{
|
||||
case CommandStrings.DatabaseStats:
|
||||
return Command.DatabaseStats;
|
||||
case CommandStrings.DatabaseUpdate:
|
||||
return Command.DatabaseUpdate;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Device Family
|
||||
case CommandStrings.DevicePrefixShort:
|
||||
case CommandStrings.DevicePrefixLong:
|
||||
useSecond = true;
|
||||
switch (commandTwo)
|
||||
{
|
||||
case CommandStrings.DeviceInfo:
|
||||
return Command.DeviceInfo;
|
||||
case CommandStrings.DeviceList:
|
||||
return Command.DeviceList;
|
||||
case CommandStrings.DeviceReport:
|
||||
return Command.DeviceReport;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Filesystem Family
|
||||
case CommandStrings.FilesystemPrefixShort:
|
||||
case CommandStrings.FilesystemPrefixShortAlt:
|
||||
case CommandStrings.FilesystemPrefixLong:
|
||||
useSecond = true;
|
||||
switch (commandTwo)
|
||||
{
|
||||
case CommandStrings.FilesystemExtract:
|
||||
return Command.FilesystemExtract;
|
||||
case CommandStrings.FilesystemListShort:
|
||||
case CommandStrings.FilesystemListLong:
|
||||
return Command.FilesystemList;
|
||||
case CommandStrings.DatabaseStats:
|
||||
return Command.FilesystemOptions;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Image Family
|
||||
case CommandStrings.ImagePrefixShort:
|
||||
case CommandStrings.ImagePrefixLong:
|
||||
useSecond = true;
|
||||
switch (commandTwo)
|
||||
{
|
||||
case CommandStrings.ImageAnalyze:
|
||||
return Command.ImageAnalyze;
|
||||
case CommandStrings.ImageChecksumShort:
|
||||
case CommandStrings.ImageChecksumLong:
|
||||
return Command.ImageChecksum;
|
||||
case CommandStrings.ImageCompareShort:
|
||||
case CommandStrings.ImageCompareLong:
|
||||
return Command.ImageCompare;
|
||||
case CommandStrings.ImageConvert:
|
||||
return Command.ImageConvert;
|
||||
case CommandStrings.ImageCreateSidecar:
|
||||
return Command.ImageCreateSidecar;
|
||||
case CommandStrings.ImageDecode:
|
||||
return Command.ImageDecode;
|
||||
case CommandStrings.ImageEntropy:
|
||||
return Command.ImageEntropy;
|
||||
case CommandStrings.ImageInfo:
|
||||
return Command.ImageInfo;
|
||||
case CommandStrings.ImageOptions:
|
||||
return Command.ImageOptions;
|
||||
case CommandStrings.ImagePrint:
|
||||
return Command.ImagePrint;
|
||||
case CommandStrings.ImageVerify:
|
||||
return Command.ImageVerify;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Media Family
|
||||
case CommandStrings.MediaPrefixShort:
|
||||
case CommandStrings.MediaPrefixLong:
|
||||
useSecond = true;
|
||||
switch (commandTwo)
|
||||
{
|
||||
case CommandStrings.MediaDump:
|
||||
return Command.MediaDump;
|
||||
case CommandStrings.MediaInfo:
|
||||
return Command.MediaInfo;
|
||||
case CommandStrings.MediaScan:
|
||||
return Command.MediaScan;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Standalone Commands
|
||||
case CommandStrings.Configure:
|
||||
return Command.Configure;
|
||||
case CommandStrings.Formats:
|
||||
return Command.Formats;
|
||||
case CommandStrings.ListEncodings:
|
||||
return Command.ListEncodings;
|
||||
case CommandStrings.ListNamespaces:
|
||||
return Command.ListNamespaces;
|
||||
case CommandStrings.Remote:
|
||||
return Command.Remote;
|
||||
}
|
||||
|
||||
return Command.NONE;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
namespace DICUI.Aaru
|
||||
{
|
||||
/// <summary>
|
||||
/// Supported Aaru commands
|
||||
/// </summary>
|
||||
public enum Command : int
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
// Database Family
|
||||
DatabaseStats,
|
||||
DatabaseUpdate,
|
||||
|
||||
// Device Family
|
||||
DeviceInfo,
|
||||
DeviceList,
|
||||
DeviceReport,
|
||||
|
||||
// Filesystem Family
|
||||
FilesystemExtract,
|
||||
FilesystemList,
|
||||
FilesystemOptions,
|
||||
|
||||
// Image Family
|
||||
ImageAnalyze,
|
||||
ImageChecksum,
|
||||
ImageCompare,
|
||||
ImageConvert,
|
||||
ImageCreateSidecar,
|
||||
ImageDecode,
|
||||
ImageEntropy,
|
||||
ImageInfo,
|
||||
ImageOptions,
|
||||
ImagePrint,
|
||||
ImageVerify,
|
||||
|
||||
// Media Family
|
||||
MediaDump,
|
||||
MediaInfo,
|
||||
MediaScan,
|
||||
|
||||
// Standalone Commands
|
||||
Configure,
|
||||
Formats,
|
||||
ListEncodings,
|
||||
ListNamespaces,
|
||||
Remote,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supported Aaru flags
|
||||
/// </summary>
|
||||
public enum Flag : int
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
// Boolean flags
|
||||
Adler32,
|
||||
Clear,
|
||||
ClearAll,
|
||||
CRC16,
|
||||
CRC32,
|
||||
CRC64,
|
||||
Debug,
|
||||
DiskTags,
|
||||
DuplicatedSectors,
|
||||
ExtendedAttributes,
|
||||
Filesystems,
|
||||
FirstPregap,
|
||||
FixOffset,
|
||||
Fletcher16,
|
||||
Fletcher32,
|
||||
Force,
|
||||
LongFormat,
|
||||
LongSectors,
|
||||
MD5,
|
||||
Metadata,
|
||||
Partitions,
|
||||
Persistent,
|
||||
Resume,
|
||||
SectorTags,
|
||||
SeparatedTracks,
|
||||
SHA1,
|
||||
SHA256,
|
||||
SHA384,
|
||||
SHA512,
|
||||
SpamSum,
|
||||
StopOnError,
|
||||
Tape,
|
||||
Trim,
|
||||
Verbose,
|
||||
VerifyDisc,
|
||||
VerifySectors,
|
||||
Version,
|
||||
WholeDisc,
|
||||
|
||||
// Int8 flags
|
||||
Speed,
|
||||
|
||||
// Int16 flags
|
||||
RetryPasses,
|
||||
Width,
|
||||
|
||||
// Int32 flags
|
||||
BlockSize,
|
||||
Count,
|
||||
MediaLastSequence,
|
||||
MediaSequence,
|
||||
Skip,
|
||||
|
||||
// Int64 flags
|
||||
Length,
|
||||
Start,
|
||||
|
||||
// String flags
|
||||
Comments,
|
||||
Creator,
|
||||
DriveManufacturer,
|
||||
DriveModel,
|
||||
DriveRevision,
|
||||
DriveSerial,
|
||||
Encoding,
|
||||
FormatConvert,
|
||||
FormatDump,
|
||||
ImgBurnLog,
|
||||
MediaBarcode,
|
||||
MediaManufacturer,
|
||||
MediaModel,
|
||||
MediaPartNumber,
|
||||
MediaSerial,
|
||||
MediaTitle,
|
||||
MHDDLog,
|
||||
Namespace,
|
||||
Options,
|
||||
OutputPrefix,
|
||||
ResumeFile,
|
||||
Subchannel,
|
||||
XMLSidecar,
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,44 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net462;net472;net48;netcoreapp3.1</TargetFrameworks>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)'!='netcoreapp2.1' AND '$(TargetFramework)'!='netcoreapp3.1'">
|
||||
<DefineConstants>NET_FRAMEWORK</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'!='netcoreapp2.1' AND '$(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>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BurnOutSharp" Version="1.3.9.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="System.Management" Version="4.7.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Management" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,255 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace DICUI.Data
|
||||
{
|
||||
public abstract class BaseParameters
|
||||
{
|
||||
/// <summary>
|
||||
/// Path to the executable
|
||||
/// </summary>
|
||||
public string Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Program that this set of parameters represents
|
||||
/// </summary>
|
||||
public InternalProgram InternalProgram { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Populate a Parameters object from a param string
|
||||
/// </summary>
|
||||
/// <param name="parameters">String possibly representing a set of parameters</param>
|
||||
public BaseParameters(string parameters)
|
||||
{
|
||||
// If any parameters are not valid, wipe out everything
|
||||
if (!ValidateAndSetParameters(parameters))
|
||||
{
|
||||
ResetValues();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate parameters based on a set of known inputs
|
||||
/// </summary>
|
||||
/// <param name="system">KnownSystem 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="paranoid">Enable paranoid mode (safer dumping)</param>
|
||||
/// <param name="quietMode">Enable quiet mode (no beeps)</param>
|
||||
/// <param name="retryCount">User-defined reread count</param>
|
||||
public BaseParameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, bool paranoid, bool quietMode, int retryCount)
|
||||
{
|
||||
SetDefaultParameters(system, type, driveLetter, filename, driveSpeed, paranoid, retryCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Blindly generate a parameter string based on the inputs
|
||||
/// </summary>
|
||||
/// <returns>Correctly formatted parameter string, null on error</returns>
|
||||
public abstract string GenerateParameters();
|
||||
|
||||
/// <summary>
|
||||
/// Get the input path from the implementation
|
||||
/// </summary>
|
||||
/// <returns>String representing the path, null on error</returns>
|
||||
public abstract string InputPath();
|
||||
|
||||
/// <summary>
|
||||
/// Get the output path from the implementation
|
||||
/// </summary>
|
||||
/// <returns>String representing the path, null on error</returns>
|
||||
public abstract string OutputPath();
|
||||
|
||||
/// <summary>
|
||||
/// Get the processing speed from the implementation
|
||||
/// </summary>
|
||||
/// <returns>int? representing the speed, null on error</returns>
|
||||
public abstract int? GetSpeed();
|
||||
|
||||
/// <summary>
|
||||
/// Set the processing speed int the implementation
|
||||
/// </summary>
|
||||
/// <param name="speed">int? representing the speed</param>
|
||||
public abstract void SetSpeed(int? speed);
|
||||
|
||||
/// <summary>
|
||||
/// Get the MediaType from the current set of parameters
|
||||
/// </summary>
|
||||
/// <returns>MediaType value if successful, null on error</returns>
|
||||
public abstract MediaType? GetMediaType();
|
||||
|
||||
/// <summary>
|
||||
/// Gets if the current command is considered a dumping command or not
|
||||
/// </summary>
|
||||
/// <returns>True if it's a dumping command, false otherwise</returns>
|
||||
public abstract bool IsDumpingCommand();
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the current Parameter object is valid
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsValid()
|
||||
{
|
||||
return GenerateParameters() != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset all special variables to have default values
|
||||
/// </summary>
|
||||
protected abstract void ResetValues();
|
||||
|
||||
/// <summary>
|
||||
/// Set default parameters for a given system and media type
|
||||
/// </summary>
|
||||
/// <param name="system">KnownSystem 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="paranoid">Enable paranoid mode (safer dumping)</param>
|
||||
/// <param name="retryCount">User-defined reread count</param>
|
||||
protected abstract void SetDefaultParameters(
|
||||
KnownSystem? system,
|
||||
MediaType? type,
|
||||
char driveLetter,
|
||||
string filename,
|
||||
int? driveSpeed,
|
||||
bool paranoid,
|
||||
int retryCount);
|
||||
|
||||
/// <summary>
|
||||
/// Scan a possible parameter string and populate whatever possible
|
||||
/// </summary>
|
||||
/// <param name="parameters">String possibly representing parameters</param>
|
||||
/// <returns></returns>
|
||||
protected abstract bool ValidateAndSetParameters(string parameters);
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether or not the selected item exists
|
||||
/// </summary>
|
||||
/// <param name="parameters">List of parameters to check against</param>
|
||||
/// <param name="index">Current index</param>
|
||||
/// <returns>True if the next item exists, false otherwise</returns>
|
||||
protected bool DoesExist(List<string> parameters, int index)
|
||||
{
|
||||
if (index >= parameters.Count)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether a string is a flag (starts with '/')
|
||||
/// </summary>
|
||||
/// <param name="parameter">String value to check</param>
|
||||
/// <returns>True if it's a flag, false otherwise</returns>
|
||||
protected bool IsFlag(string parameter)
|
||||
{
|
||||
if (parameter.Trim('\"').StartsWith("/"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <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>
|
||||
protected bool IsValidDriveLetter(string parameter)
|
||||
{
|
||||
if (!Regex.IsMatch(parameter, @"^[A-Z]:?\\?$"))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether a string is a valid bool
|
||||
/// </summary>
|
||||
/// <param name="parameter">String value to check</param>
|
||||
/// <returns>True if it's a valid bool, false otherwise</returns>
|
||||
protected bool IsValidBool(string parameter)
|
||||
{
|
||||
return bool.TryParse(parameter, out bool temp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether a string is a valid byte
|
||||
/// </summary>
|
||||
/// <param name="parameter">String value to check</param>
|
||||
/// <param name="lowerBound">Lower bound (>=)</param>
|
||||
/// <param name="upperBound">Upper bound (<=)</param>
|
||||
/// <returns>True if it's a valid byte, false otherwise</returns>
|
||||
protected bool IsValidInt8(string parameter, sbyte lowerBound = -1, sbyte upperBound = -1)
|
||||
{
|
||||
if (!sbyte.TryParse(parameter, out sbyte temp))
|
||||
return false;
|
||||
else if (lowerBound != -1 && temp < lowerBound)
|
||||
return false;
|
||||
else if (upperBound != -1 && temp > upperBound)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether a string is a valid Int16
|
||||
/// </summary>
|
||||
/// <param name="parameter">String value to check</param>
|
||||
/// <param name="lowerBound">Lower bound (>=)</param>
|
||||
/// <param name="upperBound">Upper bound (<=)</param>
|
||||
/// <returns>True if it's a valid Int16, false otherwise</returns>
|
||||
protected bool IsValidInt16(string parameter, short lowerBound = -1, short upperBound = -1)
|
||||
{
|
||||
if (!short.TryParse(parameter, out short temp))
|
||||
return false;
|
||||
else if (lowerBound != -1 && temp < lowerBound)
|
||||
return false;
|
||||
else if (upperBound != -1 && temp > upperBound)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether a string is a valid Int32
|
||||
/// </summary>
|
||||
/// <param name="parameter">String value to check</param>
|
||||
/// <param name="lowerBound">Lower bound (>=)</param>
|
||||
/// <param name="upperBound">Upper bound (<=)</param>
|
||||
/// <returns>True if it's a valid Int32, false otherwise</returns>
|
||||
protected bool IsValidInt32(string parameter, int lowerBound = -1, int upperBound = -1)
|
||||
{
|
||||
if (!int.TryParse(parameter, out int temp))
|
||||
return false;
|
||||
else if (lowerBound != -1 && temp < lowerBound)
|
||||
return false;
|
||||
else if (upperBound != -1 && temp > upperBound)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether a string is a valid Int64
|
||||
/// </summary>
|
||||
/// <param name="parameter">String value to check</param>
|
||||
/// <param name="lowerBound">Lower bound (>=)</param>
|
||||
/// <param name="upperBound">Upper bound (<=)</param>
|
||||
/// <returns>True if it's a valid Int64, false otherwise</returns>
|
||||
protected bool IsValidInt64(string parameter, long lowerBound = -1, long upperBound = -1)
|
||||
{
|
||||
if (!long.TryParse(parameter, out long temp))
|
||||
return false;
|
||||
else if (lowerBound != -1 && temp < lowerBound)
|
||||
return false;
|
||||
else if (upperBound != -1 && temp > upperBound)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,327 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using DICUI.Data;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace DICUI.DiscImageCreator
|
||||
{
|
||||
public static class Converters
|
||||
{
|
||||
#region Cross-enumeration conversions
|
||||
|
||||
/// <summary>
|
||||
/// Get the most common known system for a given MediaType
|
||||
/// </summary>
|
||||
/// <param name="baseCommand">Command value to check</param>
|
||||
/// <returns>KnownSystem if possible, null on error</returns>
|
||||
public static KnownSystem? ToKnownSystem(Command baseCommand)
|
||||
{
|
||||
switch (baseCommand)
|
||||
{
|
||||
case Command.Audio:
|
||||
return KnownSystem.AudioCD;
|
||||
case Command.CompactDisc:
|
||||
case Command.Data:
|
||||
case Command.DigitalVideoDisc:
|
||||
case Command.Disk:
|
||||
case Command.Floppy:
|
||||
return KnownSystem.IBMPCCompatible;
|
||||
case Command.GDROM:
|
||||
case Command.Swap:
|
||||
return KnownSystem.SegaDreamcast;
|
||||
case Command.BluRay:
|
||||
return KnownSystem.SonyPlayStation3;
|
||||
case Command.SACD:
|
||||
return KnownSystem.SuperAudioCD;
|
||||
case Command.XBOX:
|
||||
case Command.XBOXSwap:
|
||||
return KnownSystem.MicrosoftXBOX;
|
||||
case Command.XGD2Swap:
|
||||
case Command.XGD3Swap:
|
||||
return KnownSystem.MicrosoftXBOX360;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the MediaType associated with a given base command
|
||||
/// </summary>
|
||||
/// <param name="baseCommand">Command value to check</param>
|
||||
/// <returns>MediaType if possible, null on error</returns>
|
||||
/// <remarks>This takes the "safe" route by assuming the larger of any given format</remarks>
|
||||
public static MediaType? ToMediaType(Command baseCommand)
|
||||
{
|
||||
switch (baseCommand)
|
||||
{
|
||||
case Command.Audio:
|
||||
case Command.CompactDisc:
|
||||
case Command.Data:
|
||||
case Command.SACD:
|
||||
return MediaType.CDROM;
|
||||
case Command.GDROM:
|
||||
case Command.Swap:
|
||||
return MediaType.GDROM;
|
||||
case Command.DigitalVideoDisc:
|
||||
case Command.XBOX:
|
||||
case Command.XBOXSwap:
|
||||
case Command.XGD2Swap:
|
||||
case Command.XGD3Swap:
|
||||
return MediaType.DVD;
|
||||
case Command.BluRay:
|
||||
return MediaType.BluRay;
|
||||
|
||||
// Non-optical
|
||||
case Command.Floppy:
|
||||
return MediaType.FloppyDisk;
|
||||
case Command.Disk:
|
||||
return MediaType.HardDisk;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the default extension for a given disc type
|
||||
/// </summary>
|
||||
/// <param name="type">MediaType value to check</param>
|
||||
/// <returns>Valid extension (with leading '.'), null on error</returns>
|
||||
public static string Extension(MediaType? type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
case MediaType.GDROM:
|
||||
case MediaType.Cartridge:
|
||||
case MediaType.HardDisk:
|
||||
case MediaType.CompactFlash:
|
||||
case MediaType.MMC:
|
||||
case MediaType.SDCard:
|
||||
case MediaType.FlashDrive:
|
||||
return ".bin";
|
||||
case MediaType.DVD:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.BluRay:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
case MediaType.UMD:
|
||||
return ".iso";
|
||||
case MediaType.LaserDisc:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
return ".raw";
|
||||
case MediaType.NintendoWiiUOpticalDisc:
|
||||
return ".wud";
|
||||
case MediaType.FloppyDisk:
|
||||
return ".img";
|
||||
case MediaType.Cassette:
|
||||
return ".wav";
|
||||
case MediaType.NONE:
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Convert to Long Name
|
||||
|
||||
/// <summary>
|
||||
/// Get the string representation of the Command enum values
|
||||
/// </summary>
|
||||
/// <param name="command">Command value to convert</param>
|
||||
/// <returns>String representing the value, if possible</returns>
|
||||
public static string LongName(Command command)
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
case Command.Audio:
|
||||
return CommandStrings.Audio;
|
||||
case Command.BluRay:
|
||||
return CommandStrings.BluRay;
|
||||
case Command.Close:
|
||||
return CommandStrings.Close;
|
||||
case Command.CompactDisc:
|
||||
return CommandStrings.CompactDisc;
|
||||
case Command.Data:
|
||||
return CommandStrings.Data;
|
||||
case Command.DigitalVideoDisc:
|
||||
return CommandStrings.DigitalVideoDisc;
|
||||
case Command.Disk:
|
||||
return CommandStrings.Disk;
|
||||
case Command.DriveSpeed:
|
||||
return CommandStrings.DriveSpeed;
|
||||
case Command.Eject:
|
||||
return CommandStrings.Eject;
|
||||
case Command.Floppy:
|
||||
return CommandStrings.Floppy;
|
||||
case Command.GDROM:
|
||||
return CommandStrings.GDROM;
|
||||
case Command.MDS:
|
||||
return CommandStrings.MDS;
|
||||
case Command.Merge:
|
||||
return CommandStrings.Merge;
|
||||
case Command.Reset:
|
||||
return CommandStrings.Reset;
|
||||
case Command.SACD:
|
||||
return CommandStrings.SACD;
|
||||
case Command.Start:
|
||||
return CommandStrings.Start;
|
||||
case Command.Stop:
|
||||
return CommandStrings.Stop;
|
||||
case Command.Sub:
|
||||
return CommandStrings.Sub;
|
||||
case Command.Swap:
|
||||
return CommandStrings.Swap;
|
||||
case Command.XBOX:
|
||||
return CommandStrings.XBOX;
|
||||
case Command.XBOXSwap:
|
||||
return CommandStrings.XBOXSwap;
|
||||
case Command.XGD2Swap:
|
||||
return CommandStrings.XGD2Swap;
|
||||
case Command.XGD3Swap:
|
||||
return CommandStrings.XGD3Swap;
|
||||
|
||||
case Command.NONE:
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string representation of the Flag enum values
|
||||
/// </summary>
|
||||
/// <param name="command">Flag value to convert</param>
|
||||
/// <returns>String representing the value, if possible</returns>
|
||||
public static string LongName(Flag flag)
|
||||
{
|
||||
switch (flag)
|
||||
{
|
||||
case Flag.AddOffset:
|
||||
return FlagStrings.AddOffset;
|
||||
case Flag.AMSF:
|
||||
return FlagStrings.AMSF;
|
||||
case Flag.AtariJaguar:
|
||||
return FlagStrings.AtariJaguar;
|
||||
case Flag.BEOpcode:
|
||||
return FlagStrings.BEOpcode;
|
||||
case Flag.C2Opcode:
|
||||
return FlagStrings.C2Opcode;
|
||||
case Flag.CopyrightManagementInformation:
|
||||
return FlagStrings.CopyrightManagementInformation;
|
||||
case Flag.D8Opcode:
|
||||
return FlagStrings.D8Opcode;
|
||||
case Flag.DisableBeep:
|
||||
return FlagStrings.DisableBeep;
|
||||
case Flag.ForceUnitAccess:
|
||||
return FlagStrings.ForceUnitAccess;
|
||||
case Flag.MultiSession:
|
||||
return FlagStrings.MultiSession;
|
||||
case Flag.NoFixSubP:
|
||||
return FlagStrings.NoFixSubP;
|
||||
case Flag.NoFixSubQ:
|
||||
return FlagStrings.NoFixSubQ;
|
||||
case Flag.NoFixSubQLibCrypt:
|
||||
return FlagStrings.NoFixSubQLibCrypt;
|
||||
case Flag.NoFixSubRtoW:
|
||||
return FlagStrings.NoFixSubRtoW;
|
||||
case Flag.NoFixSubQSecuROM:
|
||||
return FlagStrings.NoFixSubQSecuROM;
|
||||
case Flag.NoSkipSS:
|
||||
return FlagStrings.NoSkipSS;
|
||||
case Flag.Raw:
|
||||
return FlagStrings.Raw;
|
||||
case Flag.Reverse:
|
||||
return FlagStrings.Reverse;
|
||||
case Flag.ScanAntiMod:
|
||||
return FlagStrings.ScanAntiMod;
|
||||
case Flag.ScanFileProtect:
|
||||
return FlagStrings.ScanFileProtect;
|
||||
case Flag.ScanSectorProtect:
|
||||
return FlagStrings.ScanSectorProtect;
|
||||
case Flag.SeventyFour:
|
||||
return FlagStrings.SeventyFour;
|
||||
case Flag.SkipSector:
|
||||
return FlagStrings.SkipSector;
|
||||
case Flag.SubchannelReadLevel:
|
||||
return FlagStrings.SubchannelReadLevel;
|
||||
case Flag.VideoNow:
|
||||
return FlagStrings.VideoNow;
|
||||
case Flag.VideoNowColor:
|
||||
return FlagStrings.VideoNowColor;
|
||||
case Flag.VideoNowXP:
|
||||
return FlagStrings.VideoNowXP;
|
||||
|
||||
case Flag.NONE:
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Convert From String
|
||||
|
||||
/// <summary>
|
||||
/// Get the Command enum value for a given string
|
||||
/// </summary>
|
||||
/// <param name="command">String value to convert</param>
|
||||
/// <returns>Command represented by the string(s), if possible</returns>
|
||||
public static Command StringToCommand(string command)
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
case CommandStrings.Audio:
|
||||
return Command.Audio;
|
||||
case CommandStrings.BluRay:
|
||||
return Command.BluRay;
|
||||
case CommandStrings.Close:
|
||||
return Command.Close;
|
||||
case CommandStrings.CompactDisc:
|
||||
return Command.CompactDisc;
|
||||
case CommandStrings.Data:
|
||||
return Command.Data;
|
||||
case CommandStrings.DigitalVideoDisc:
|
||||
return Command.DigitalVideoDisc;
|
||||
case CommandStrings.Disk:
|
||||
return Command.Disk;
|
||||
case CommandStrings.DriveSpeed:
|
||||
return Command.DriveSpeed;
|
||||
case CommandStrings.Eject:
|
||||
return Command.Eject;
|
||||
case CommandStrings.Floppy:
|
||||
return Command.Floppy;
|
||||
case CommandStrings.GDROM:
|
||||
return Command.GDROM;
|
||||
case CommandStrings.MDS:
|
||||
return Command.MDS;
|
||||
case CommandStrings.Merge:
|
||||
return Command.Merge;
|
||||
case CommandStrings.Reset:
|
||||
return Command.Reset;
|
||||
case CommandStrings.SACD:
|
||||
return Command.SACD;
|
||||
case CommandStrings.Start:
|
||||
return Command.Start;
|
||||
case CommandStrings.Stop:
|
||||
return Command.Stop;
|
||||
case CommandStrings.Sub:
|
||||
return Command.Sub;
|
||||
case CommandStrings.Swap:
|
||||
return Command.Swap;
|
||||
case CommandStrings.XBOX:
|
||||
return Command.XBOX;
|
||||
case CommandStrings.XBOXSwap:
|
||||
return Command.XBOXSwap;
|
||||
case CommandStrings.XGD2Swap:
|
||||
return Command.XGD2Swap;
|
||||
case CommandStrings.XGD3Swap:
|
||||
return Command.XGD3Swap;
|
||||
|
||||
default:
|
||||
return Command.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
namespace DICUI.DiscImageCreator
|
||||
{
|
||||
/// <summary>
|
||||
/// Supported DiscImageCreator commands
|
||||
/// </summary>
|
||||
public enum Command : int
|
||||
{
|
||||
NONE = 0,
|
||||
Audio,
|
||||
BluRay,
|
||||
Close,
|
||||
CompactDisc,
|
||||
Data,
|
||||
DigitalVideoDisc,
|
||||
Disk,
|
||||
DriveSpeed,
|
||||
Eject,
|
||||
Floppy,
|
||||
GDROM,
|
||||
MDS,
|
||||
Merge,
|
||||
Reset,
|
||||
SACD,
|
||||
Start,
|
||||
Stop,
|
||||
Sub,
|
||||
Swap,
|
||||
XBOX,
|
||||
XBOXSwap,
|
||||
XGD2Swap,
|
||||
XGD3Swap,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supported DiscImageCreator flags
|
||||
/// </summary>
|
||||
public enum Flag : int
|
||||
{
|
||||
NONE = 0,
|
||||
AddOffset,
|
||||
AMSF,
|
||||
AtariJaguar,
|
||||
BEOpcode,
|
||||
C2Opcode,
|
||||
CopyrightManagementInformation,
|
||||
D8Opcode,
|
||||
DisableBeep,
|
||||
ForceUnitAccess,
|
||||
MultiSession,
|
||||
NoFixSubP,
|
||||
NoFixSubQ,
|
||||
NoFixSubQLibCrypt,
|
||||
NoFixSubRtoW,
|
||||
NoFixSubQSecuROM,
|
||||
NoSkipSS,
|
||||
Raw,
|
||||
Reverse,
|
||||
ScanAntiMod,
|
||||
ScanFileProtect,
|
||||
ScanSectorProtect,
|
||||
SeventyFour,
|
||||
SkipSector,
|
||||
SubchannelReadLevel,
|
||||
VideoNow,
|
||||
VideoNowColor,
|
||||
VideoNowXP,
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,37 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("DICUI.Library")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("DICUI.Library")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2019")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("51ab0928-13f9-44bf-a407-b6957a43a056")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.16")]
|
||||
[assembly: AssemblyFileVersion("1.16.0.0")]
|
||||
[assembly: InternalsVisibleTo("DICUI.Test")]
|
||||
@@ -1,63 +0,0 @@
|
||||
using System.IO;
|
||||
using DICUI.Data;
|
||||
|
||||
namespace DICUI.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents information for a single drive
|
||||
/// </summary>
|
||||
public class Drive
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents drive type
|
||||
/// </summary>
|
||||
public InternalDriveType? InternalDriveType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// DriveInfo object representing the drive, if possible
|
||||
/// </summary>
|
||||
public DriveInfo DriveInfo { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Windows drive letter
|
||||
/// </summary>
|
||||
public char Letter { get { return DriveInfo?.Name[0] ?? '\0'; } }
|
||||
|
||||
/// <summary>
|
||||
/// Media label as read by Windows
|
||||
/// </summary>
|
||||
public string VolumeLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (DriveInfo.IsReady)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(DriveInfo.VolumeLabel))
|
||||
return "track";
|
||||
else
|
||||
return DriveInfo.VolumeLabel;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Template.DiscNotDetected;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drive partition format
|
||||
/// </summary>
|
||||
public string DriveFormat { get { return DriveInfo.DriveFormat; } }
|
||||
|
||||
/// <summary>
|
||||
/// Represents if Windows has marked the drive as active
|
||||
/// </summary>
|
||||
public bool MarkedActive { get { return DriveInfo.IsReady; } }
|
||||
|
||||
public Drive(InternalDriveType? driveType, DriveInfo driveInfo)
|
||||
{
|
||||
this.InternalDriveType = driveType;
|
||||
this.DriveInfo = driveInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,36 +0,0 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace DICUI.Web
|
||||
{
|
||||
// https://stackoverflow.com/questions/1777221/using-cookiecontainer-with-webclient-class
|
||||
public class CookieAwareWebClient : WebClient
|
||||
{
|
||||
private readonly CookieContainer m_container = new CookieContainer();
|
||||
|
||||
protected override WebRequest GetWebRequest(Uri address)
|
||||
{
|
||||
WebRequest request = base.GetWebRequest(address);
|
||||
HttpWebRequest webRequest = request as HttpWebRequest;
|
||||
if (webRequest != null)
|
||||
{
|
||||
webRequest.CookieContainer = m_container;
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the last downloaded filename, if possible
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string GetLastFilename()
|
||||
{
|
||||
// Try to extract the filename from the Content-Disposition header
|
||||
if (!string.IsNullOrEmpty(this.ResponseHeaders["Content-Disposition"]))
|
||||
return this.ResponseHeaders["Content-Disposition"].Substring(this.ResponseHeaders["Content-Disposition"].IndexOf("filename=") + 9).Replace("\"", "");
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,385 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
|
||||
namespace DICUI.Web
|
||||
{
|
||||
public class RedumpAccess
|
||||
{
|
||||
#region Base URLs
|
||||
|
||||
private const string loginUrl = "http://forum.redump.org/login/";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Disc URLs and Extensions
|
||||
|
||||
private const string discPageUrl = @"http://redump.org/disc/{0}/";
|
||||
private const string wipDiscPageUrl = @"http://redump.org/newdisc/{0}/";
|
||||
|
||||
private const string changesExt = "/changes/";
|
||||
private const string cueExt = "cue/";
|
||||
private const string gdiExt = "gdi/";
|
||||
private const string keyExt = "key/";
|
||||
private const string md5Ext = "md5/";
|
||||
private const string sbiExt = "sbi/";
|
||||
private const string sfvExt = "sfv/";
|
||||
private const string sha1Ext = "sha1/";
|
||||
|
||||
#endregion
|
||||
|
||||
#region List URLs
|
||||
|
||||
private const string lastModifiedUrl = @"http://redump.org/discs/sort/modified/dir/desc?page={0}";
|
||||
private const string quickSearchUrl = @"http://redump.org/discs/quicksearch/{0}/?page={1}";
|
||||
private const string userDumpsUrl = @"http://redump.org/discs/dumper/{0}/?page={1}";
|
||||
private const string wipDumpsUrl = @"http://redump.org/discs-wip/";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Pack URLs
|
||||
|
||||
private const string packCuesUrl = @"http://redump.org/cues/{0}/";
|
||||
private const string packDatfileUrl = @"http://redump.org/datfile/{0}/";
|
||||
private const string packDkeysUrl = @"http://redump.org/dkeys/{0}/";
|
||||
private const string packGdiUrl = @"http://redump.org/gdi/{0}/";
|
||||
private const string packKeysUrl = @"http://redump.org/keys/{0}/";
|
||||
private const string packSbiUrl = @"http://redump.org/sbi/{0}/";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Regexes
|
||||
|
||||
private readonly Regex discRegex = new Regex(@"<a href=""/disc/(\d+)/"">");
|
||||
private readonly Regex newDiscRegex = new Regex(@"<a href=""/newdisc/(\d+)/"">");
|
||||
private readonly Regex tokenRegex = new Regex(@"<input type=""hidden"" name=""csrf_token"" value=""(.*?)"" />");
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Login to Redump, if possible
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to hold the login state</param>
|
||||
/// <param name="username">Redump username to log in for protected systems</param>
|
||||
/// <param name="password">Redump password to log in for protected systems</param>
|
||||
/// <returns>True login was successful, false otherwise</returns>
|
||||
public bool RedumpLogin(CookieAwareWebClient wc, string username, string password)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
|
||||
return false;
|
||||
|
||||
var loginPage = wc.DownloadString(loginUrl);
|
||||
string token = this.tokenRegex.Match(loginPage).Groups[1].Value;
|
||||
|
||||
wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
|
||||
wc.Encoding = Encoding.UTF8;
|
||||
var response = wc.UploadString(loginUrl, $"form_sent=1&redirect_url=&csrf_token={token}&req_username={username}&req_password={password}&save_pass=0");
|
||||
|
||||
if (response.Contains("Incorrect username and/or password."))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Process IDs and Pages
|
||||
|
||||
/// <summary>
|
||||
/// Get the list of the last modified IDs, in order of appearance
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to hold the login state</param>
|
||||
/// <param name="pageCount">Number of pages to grab until stopping; -1 means continue until end</param>
|
||||
/// <returns>A list of IDs in order of last modified</returns>
|
||||
private List<int> ProcessLastModified(CookieAwareWebClient wc, int pageCount = -1)
|
||||
{
|
||||
List<int> ids = new List<int>();
|
||||
|
||||
// If we have a -1 page count, set the maximum page limit
|
||||
if (pageCount == -1)
|
||||
pageCount = Int32.MaxValue;
|
||||
|
||||
// Keep getting last modified pages until there are none left
|
||||
int pageNumber = 1;
|
||||
while (pageNumber < pageCount)
|
||||
{
|
||||
List<int> pageIds = CheckSingleSitePage(wc, string.Format(lastModifiedUrl, pageNumber++));
|
||||
ids.AddRange(pageIds);
|
||||
if (pageIds.Count < 2)
|
||||
break;
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve premade packs from Redump
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to hold the login state</param>
|
||||
private void ProcessAllPacks(CookieAwareWebClient wc)
|
||||
{
|
||||
var cuesPacks = this.DownloadPacks(wc, packCuesUrl, Extensions.HasCues, "CUEs");
|
||||
var datPacks = this.DownloadPacks(wc, packDatfileUrl, Extensions.HasDat, "DATs");
|
||||
var dkeyPacks = this.DownloadPacks(wc, packDkeysUrl, Extensions.HasDkeys, "Decrypted KEYS");
|
||||
var gdiPacks = this.DownloadPacks(wc, packGdiUrl, Extensions.HasGdi, "GDIs");
|
||||
var keysPacks = this.DownloadPacks(wc, packKeysUrl, Extensions.HasKeys, "KEYS");
|
||||
var sbiPacks = this.DownloadPacks(wc, packSbiUrl, Extensions.HasSbi, "SBIs");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve premade packs from Redump
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to hold the login state</param>
|
||||
/// <param name="system">RedumpSystem to get all possible packs for</param>
|
||||
private void ProcessPacksForSystem(CookieAwareWebClient wc, RedumpSystem system)
|
||||
{
|
||||
var packs = new Dictionary<string, byte[]>();
|
||||
|
||||
if (Extensions.HasCues.Contains(system))
|
||||
packs.Add("cues", this.DownloadPack(wc, packCuesUrl, system, "CUEs"));
|
||||
|
||||
if (Extensions.HasDat.Contains(system))
|
||||
packs.Add("dat", this.DownloadPack(wc, packDatfileUrl, system, "DATs"));
|
||||
|
||||
if (Extensions.HasDkeys.Contains(system))
|
||||
packs.Add("dkeys", this.DownloadPack(wc, packDkeysUrl, system, "Decrypted KEYS"));
|
||||
|
||||
if (Extensions.HasGdi.Contains(system))
|
||||
packs.Add("gdi", this.DownloadPack(wc, packGdiUrl, system, "GDIs"));
|
||||
|
||||
if (Extensions.HasKeys.Contains(system))
|
||||
packs.Add("keys", this.DownloadPack(wc, packKeysUrl, system, "KEYS"));
|
||||
|
||||
if (Extensions.HasSbi.Contains(system))
|
||||
packs.Add("sbi", this.DownloadPack(wc, packSbiUrl, system, "SBIs"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the list of IDs that associate with a given string
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to hold the login state</param>
|
||||
/// <param name="query">Value to search for in Redump</param>
|
||||
/// <returns>A list of IDs associated with that value</returns>
|
||||
public List<int> ProcessSearch(CookieAwareWebClient wc, string query)
|
||||
{
|
||||
List<int> ids = new List<int>();
|
||||
|
||||
// Keep getting quicksearch pages until there are none left
|
||||
int pageNumber = 1;
|
||||
while (true)
|
||||
{
|
||||
List<int> pageIds = CheckSingleSitePage(wc, string.Format(quickSearchUrl, query, pageNumber++));
|
||||
ids.AddRange(pageIds);
|
||||
if (pageIds.Count < 2)
|
||||
break;
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the list of IDs associated with the given user
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to hold the login state</param>
|
||||
/// <param name="username">Redump username to get the list of IDs for</param>
|
||||
/// <returns>A list of IDs associated with that user</returns>
|
||||
private List<int> ProcessUser(CookieAwareWebClient wc, string username)
|
||||
{
|
||||
List<int> ids = new List<int>();
|
||||
|
||||
// Keep getting user pages until there are none left
|
||||
int pageNumber = 1;
|
||||
while (true)
|
||||
{
|
||||
List<int> pageIds = CheckSingleSitePage(wc, string.Format(userDumpsUrl, username, pageNumber++));
|
||||
ids.AddRange(pageIds);
|
||||
if (pageIds.Count < 2)
|
||||
break;
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Single item processing
|
||||
|
||||
/// <summary>
|
||||
/// Process a Redump site page as a list of possible IDs or disc page
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to access the pages</param>
|
||||
/// <param name="url">Page URL to check and parse</param>
|
||||
/// <returns>List of matching IDs</returns>
|
||||
private List<int> CheckSingleSitePage(CookieAwareWebClient wc, string url)
|
||||
{
|
||||
List<int> ids = new List<int>();
|
||||
|
||||
var dumpsPage = wc.DownloadString(url);
|
||||
|
||||
// If we have no dumps left
|
||||
if (dumpsPage.Contains("No discs found."))
|
||||
return ids;
|
||||
|
||||
// If we have a single disc page already
|
||||
if (dumpsPage.Contains("<b>Download:</b>"))
|
||||
{
|
||||
var value = Regex.Match(dumpsPage, @"/disc/(\d+)/sfv/").Groups[1].Value;
|
||||
if (Int32.TryParse(value, out int id))
|
||||
ids.Add(id);
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
// Otherwise, traverse each dump on the page
|
||||
var matches = discRegex.Matches(dumpsPage);
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Int32.TryParse(match.Groups[1].Value, out int value))
|
||||
ids.Add(value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"An exception has occurred: {ex}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process a Redump WIP page as a list of possible IDs or disc page
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to access the pages</param>
|
||||
/// <param name="url">Page URL to check and parse</param>
|
||||
/// <returns>List of matching IDs</returns>
|
||||
private List<int> CheckSingleWIPPage(CookieAwareWebClient wc, string url)
|
||||
{
|
||||
List<int> ids = new List<int>();
|
||||
|
||||
var wipDumpsPage = wc.DownloadString(url);
|
||||
|
||||
// If we have no WIP dumps left
|
||||
if (wipDumpsPage.Contains("No WIP discs found."))
|
||||
return ids;
|
||||
|
||||
// Otherwise, traverse each dump on the page
|
||||
var matches = newDiscRegex.Matches(wipDumpsPage);
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Int32.TryParse(match.Groups[1].Value, out int value))
|
||||
ids.Add(value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"An exception has occurred: {ex}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Download an individual pack
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to access the packs</param>
|
||||
/// <param name="url">Base URL to download using</param>
|
||||
/// <param name="system">System to download packs for</param>
|
||||
/// <param name="title">Name of the pack that is downloading</param>
|
||||
private byte[] DownloadPack(CookieAwareWebClient wc, string url, RedumpSystem system, string title)
|
||||
{
|
||||
Console.WriteLine($"Downloading {title}");
|
||||
Console.Write($"\r{system.LongName()}{new string(' ', Console.BufferWidth - system.LongName().Length - 1)}");
|
||||
var pack = wc.DownloadData(string.Format(url, system.ShortName()));
|
||||
|
||||
Console.Write($"\rComplete!{new string(' ', Console.BufferWidth - 10)}");
|
||||
Console.WriteLine();
|
||||
|
||||
return pack;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Download a set of packs
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to access the packs</param>
|
||||
/// <param name="url">Base URL to download using</param>
|
||||
/// <param name="systems">List of systems to download packs for</param>
|
||||
/// <param name="title">Name of the pack that is downloading</param>
|
||||
private Dictionary<RedumpSystem, byte[]> DownloadPacks(CookieAwareWebClient wc, string url, RedumpSystem[] systems, string title)
|
||||
{
|
||||
var dict = new Dictionary<RedumpSystem, byte[]>();
|
||||
|
||||
Console.WriteLine($"Downloading {title}");
|
||||
foreach (var system in systems)
|
||||
{
|
||||
Console.Write($"\r{system.LongName()}{new string(' ', Console.BufferWidth - system.LongName().Length - 1)}");
|
||||
dict.Add(system, wc.DownloadData(string.Format(url, system.ShortName())));
|
||||
}
|
||||
|
||||
Console.Write($"\rComplete!{new string(' ', Console.BufferWidth - 10)}");
|
||||
Console.WriteLine();
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Download an individual site ID page as a string, if possible
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to access the pages</param>
|
||||
/// <param name="id">Redump disc ID to retrieve</param>
|
||||
/// <returns>Disc page as a string, null on error</returns>
|
||||
public string DownloadSingleSiteID(CookieAwareWebClient wc, int id)
|
||||
{
|
||||
string paddedId = id.ToString().PadLeft(5, '0');
|
||||
Console.WriteLine($"Processing ID: {paddedId}");
|
||||
try
|
||||
{
|
||||
string discPage = wc.DownloadString(string.Format(discPageUrl, +id));
|
||||
if (discPage.Contains($"Disc with ID \"{id}\" doesn't exist"))
|
||||
return null;
|
||||
else
|
||||
return discPage;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"An exception has occurred: {ex}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Download an individual WIP ID page as a string, if possible
|
||||
/// </summary>
|
||||
/// <param name="wc">CookieAwareWebClient to access the pages</param>
|
||||
/// <param name="id">Redump disc ID to retrieve</param>
|
||||
/// <returns>WIP disc page as a string, null on error</returns>
|
||||
private string DownloadSingleWIPID(CookieAwareWebClient wc, int id)
|
||||
{
|
||||
string paddedId = id.ToString().PadLeft(5, '0');
|
||||
Console.WriteLine($"Processing WIP ID: {paddedId}");
|
||||
try
|
||||
{
|
||||
string discPage = wc.DownloadString(string.Format(wipDiscPageUrl, +id));
|
||||
if (discPage.Contains($"WIP Disc with ID \"{id}\" doesn't exist"))
|
||||
return null;
|
||||
else
|
||||
return discPage;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"An exception has occurred: {ex}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
using System;
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace DICUI.Test.Utilities
|
||||
{
|
||||
public class ConvertersTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(DiscImageCreator.Command.Audio, MediaType.CDROM)]
|
||||
[InlineData(DiscImageCreator.Command.BluRay, MediaType.BluRay)]
|
||||
[InlineData(DiscImageCreator.Command.Close, null)]
|
||||
[InlineData(DiscImageCreator.Command.CompactDisc, MediaType.CDROM)]
|
||||
[InlineData(DiscImageCreator.Command.Data, MediaType.CDROM)]
|
||||
[InlineData(DiscImageCreator.Command.DigitalVideoDisc, MediaType.DVD)]
|
||||
[InlineData(DiscImageCreator.Command.Eject, null)]
|
||||
[InlineData(DiscImageCreator.Command.Floppy, MediaType.FloppyDisk)]
|
||||
[InlineData(DiscImageCreator.Command.GDROM, MediaType.GDROM)]
|
||||
[InlineData(DiscImageCreator.Command.MDS, null)]
|
||||
[InlineData(DiscImageCreator.Command.Reset, null)]
|
||||
[InlineData(DiscImageCreator.Command.SACD, MediaType.CDROM)]
|
||||
[InlineData(DiscImageCreator.Command.Start, null)]
|
||||
[InlineData(DiscImageCreator.Command.Stop, null)]
|
||||
[InlineData(DiscImageCreator.Command.Sub, null)]
|
||||
[InlineData(DiscImageCreator.Command.Swap, MediaType.GDROM)]
|
||||
[InlineData(DiscImageCreator.Command.XBOX, MediaType.DVD)]
|
||||
public void BaseCommandToMediaTypeTest(DiscImageCreator.Command command, MediaType? expected)
|
||||
{
|
||||
MediaType? actual = DiscImageCreator.Converters.ToMediaType(command);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(DiscImageCreator.Command.Audio, KnownSystem.AudioCD)]
|
||||
[InlineData(DiscImageCreator.Command.BluRay, KnownSystem.SonyPlayStation3)]
|
||||
[InlineData(DiscImageCreator.Command.Close, null)]
|
||||
[InlineData(DiscImageCreator.Command.CompactDisc, KnownSystem.IBMPCCompatible)]
|
||||
[InlineData(DiscImageCreator.Command.Data, KnownSystem.IBMPCCompatible)]
|
||||
[InlineData(DiscImageCreator.Command.DigitalVideoDisc, KnownSystem.IBMPCCompatible)]
|
||||
[InlineData(DiscImageCreator.Command.Eject, null)]
|
||||
[InlineData(DiscImageCreator.Command.Floppy, KnownSystem.IBMPCCompatible)]
|
||||
[InlineData(DiscImageCreator.Command.GDROM, KnownSystem.SegaDreamcast)]
|
||||
[InlineData(DiscImageCreator.Command.MDS, null)]
|
||||
[InlineData(DiscImageCreator.Command.Reset, null)]
|
||||
[InlineData(DiscImageCreator.Command.SACD, KnownSystem.SuperAudioCD)]
|
||||
[InlineData(DiscImageCreator.Command.Start, null)]
|
||||
[InlineData(DiscImageCreator.Command.Stop, null)]
|
||||
[InlineData(DiscImageCreator.Command.Sub, null)]
|
||||
[InlineData(DiscImageCreator.Command.Swap, KnownSystem.SegaDreamcast)]
|
||||
[InlineData(DiscImageCreator.Command.XBOX, KnownSystem.MicrosoftXBOX)]
|
||||
public void BaseCommandToKnownSystemTest(DiscImageCreator.Command 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);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void KnownSystemHasValidCategory()
|
||||
{
|
||||
var values = Validators.CreateListOfSystems();
|
||||
KnownSystem[] markers = { KnownSystem.MarkerArcadeEnd, KnownSystem.MarkerDiscBasedConsoleEnd, /* KnownSystem.MarkerOtherConsoleEnd, */ KnownSystem.MarkerComputerEnd, KnownSystem.MarkerOtherEnd };
|
||||
|
||||
values.ForEach(system => {
|
||||
if (system == KnownSystem.NONE)
|
||||
return;
|
||||
|
||||
// we check that the category is the first category value higher than the system
|
||||
KnownSystemCategory category = ((KnownSystem?)system).Category();
|
||||
KnownSystem marker = KnownSystem.NONE;
|
||||
|
||||
switch (category)
|
||||
{
|
||||
case KnownSystemCategory.Arcade: marker = KnownSystem.MarkerArcadeEnd; break;
|
||||
case KnownSystemCategory.DiscBasedConsole: marker = KnownSystem.MarkerDiscBasedConsoleEnd; break;
|
||||
/* case KnownSystemCategory.OtherConsole: marker = KnownSystem.MarkerOtherConsoleEnd; break; */
|
||||
case KnownSystemCategory.Computer: marker = KnownSystem.MarkerComputerEnd; break;
|
||||
case KnownSystemCategory.Other: marker = KnownSystem.MarkerOtherEnd; break;
|
||||
}
|
||||
|
||||
Assert.NotEqual(KnownSystem.NONE, marker);
|
||||
Assert.True(marker > system);
|
||||
|
||||
Array.ForEach(markers, mmarker =>
|
||||
{
|
||||
// a marker can be the same of the found one, or one of a category before or a category after but never in the middle between
|
||||
// the system and the mapped category
|
||||
Assert.True(mmarker == marker || mmarker < system || mmarker > marker);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="AaruPath" value="Programs\Aaru\Aaru.exe"/>
|
||||
<add key="CreatorPath" value="Programs\Creator\DiscImageCreator.exe"/>
|
||||
<add key="SubDumpPath" value="Programs\Subdump\subdump.exe"/>
|
||||
<add key="DefaultOutputPath" value="ISO"/>
|
||||
<add key="InternalProgram" value="DiscImageCreator"/>
|
||||
|
||||
<add key="PreferredDumpSpeedCD" value="48"/>
|
||||
<add key="PreferredDumpSpeedDVD" value="24"/>
|
||||
<add key="PreferredDumpSpeedBD" value="16"/>
|
||||
|
||||
<add key="QuietMode" value="false"/>
|
||||
<add key="ParanoidMode" value="false"/>
|
||||
<add key="ScanForProtection" value="true"/>
|
||||
<add key="SkipMediaTypeDetection" value="false"/>
|
||||
<add key="SkipSystemDetection" value="false"/>
|
||||
<add key="RereadAmountForC2" value="20"/>
|
||||
<add key="VerboseLogging" value="true"/>
|
||||
<add key="OpenLogWindowAtStartup" value="true"/>
|
||||
<add key="AddPlaceholders" value="true"/>
|
||||
<add key="PromptForDiscInformation" value="true"/>
|
||||
<add key="IgnoreFixedDrives" value="false"/>
|
||||
<add key="ResetDriveAfterDump" value="false"/>
|
||||
|
||||
<add key="Username" value=""/>
|
||||
<add key="Password" value=""/>
|
||||
</appSettings>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/></startup></configuration>
|
||||
@@ -1,9 +0,0 @@
|
||||
<Application x:Class="DICUI.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:DICUI"
|
||||
StartupUri="Windows\MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
@@ -1,29 +0,0 @@
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
|
||||
namespace DICUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single item in the Category combo box
|
||||
/// </summary>
|
||||
public class CategoryComboBoxItem
|
||||
{
|
||||
private object data;
|
||||
|
||||
public CategoryComboBoxItem(Category? category) => data = category;
|
||||
|
||||
public static implicit operator Category? (CategoryComboBoxItem item) => item.data as Category?;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return (data as Category?).LongName(); }
|
||||
}
|
||||
|
||||
public bool IsChecked { get; set; }
|
||||
|
||||
public Category? Value
|
||||
{
|
||||
get { return data as Category?; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System.Windows.Media;
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
|
||||
namespace DICUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single item in the System combo box
|
||||
/// </summary>
|
||||
public class KnownSystemComboBoxItem
|
||||
{
|
||||
private object data;
|
||||
|
||||
public KnownSystemComboBoxItem(KnownSystem? system) => data = system;
|
||||
public KnownSystemComboBoxItem(KnownSystemCategory? category) => data = category;
|
||||
|
||||
public Brush Foreground { get => IsHeader() ? Brushes.Gray : Brushes.Black; }
|
||||
|
||||
public bool IsHeader() => data is KnownSystemCategory?;
|
||||
public bool IsSystem() => data is KnownSystem?;
|
||||
|
||||
public static implicit operator KnownSystem? (KnownSystemComboBoxItem item) => item.data as KnownSystem?;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsHeader())
|
||||
return "---------- " + (data as KnownSystemCategory?).LongName() + " ----------";
|
||||
else
|
||||
return (data as KnownSystem?).LongName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
|
||||
namespace DICUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single item in the Language combo box
|
||||
/// </summary>
|
||||
public class LanguageComboBoxItem
|
||||
{
|
||||
private object data;
|
||||
|
||||
public LanguageComboBoxItem(Language? region) => data = region;
|
||||
|
||||
public static implicit operator Language? (LanguageComboBoxItem item) => item.data as Language?;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return (data as Language?).LongName(); }
|
||||
}
|
||||
|
||||
public bool IsChecked { get; set; }
|
||||
|
||||
public Language? Value
|
||||
{
|
||||
get { return data as Language?; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
|
||||
namespace DICUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single item in the MediaType combo box
|
||||
/// </summary>
|
||||
public class MediaTypeComboBoxItem
|
||||
{
|
||||
private MediaType? data;
|
||||
|
||||
public MediaTypeComboBoxItem(MediaType? mediaType) => data = mediaType;
|
||||
|
||||
public static implicit operator MediaType? (MediaTypeComboBoxItem item) => item.data;
|
||||
|
||||
public string Name { get { return data.LongName(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
|
||||
namespace DICUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single item in the Region combo box
|
||||
/// </summary>
|
||||
public class RegionComboBoxItem
|
||||
{
|
||||
private object data;
|
||||
|
||||
public RegionComboBoxItem(Region? region) => data = region;
|
||||
|
||||
public static implicit operator Region? (RegionComboBoxItem item) => item.data as Region?;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return (data as Region?).LongName();
|
||||
}
|
||||
}
|
||||
|
||||
public Region? Value
|
||||
{
|
||||
get { return data as Region?; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Media;
|
||||
using DICUI.Data;
|
||||
|
||||
namespace DICUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Variables for UI elements
|
||||
/// </summary>
|
||||
public static class Constants
|
||||
{
|
||||
public const string StartDumping = "Start Dumping";
|
||||
public const string StopDumping = "Stop Dumping";
|
||||
|
||||
public const int LogWindowMarginFromMainWindow = 10;
|
||||
|
||||
// Private lists of known drive speed ranges
|
||||
private static IReadOnlyList<int> cd { get; } = new List<int> { 1, 2, 3, 4, 6, 8, 12, 16, 20, 24, 32, 40, 44, 48, 52, 56, 72 };
|
||||
private static IReadOnlyList<int> dvd { get; } = cd.Where(s => s <= 24).ToList();
|
||||
private static IReadOnlyList<int> bd { get; } = cd.Where(s => s <= 16).ToList();
|
||||
private static IReadOnlyList<int> unknown { get; } = cd; // TODO: All or {1}? Maybe null?
|
||||
|
||||
/// <summary>
|
||||
/// Get list of all drive speeds for a given MediaType
|
||||
/// </summary>
|
||||
/// <param name="type">MediaType? that represents the current item</param>
|
||||
/// <returns>Read-only list of drive speeds</returns>
|
||||
public static IReadOnlyList<int> GetSpeedsForMediaType(MediaType? type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
case MediaType.GDROM:
|
||||
return cd;
|
||||
case MediaType.DVD:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return dvd;
|
||||
case MediaType.BluRay:
|
||||
return bd;
|
||||
default:
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
||||
// Create collections for UI based on known drive speeds
|
||||
public static DoubleCollection SpeedsForCDAsCollection { get; } = GetDoubleCollectionFromIntList(cd);
|
||||
public static DoubleCollection SpeedsForDVDAsCollection { get; } = GetDoubleCollectionFromIntList(dvd);
|
||||
public static DoubleCollection SpeedsForBDAsCollection { get; } = GetDoubleCollectionFromIntList(bd);
|
||||
private static DoubleCollection GetDoubleCollectionFromIntList(IReadOnlyList<int> list)
|
||||
=> new DoubleCollection(list.Select(i => Convert.ToDouble(i)).ToList());
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net462;net472;net48;netcoreapp3.1</TargetFrameworks>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<UseWPF>true</UseWPF>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<ApplicationIcon>Icon.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.6.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DICUI.Library\DICUI.Library.csproj">
|
||||
<Project>{51ab0928-13f9-44bf-a407-b6957a43a056}</Project>
|
||||
<Name>DICUI.Library</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,32 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
|
||||
namespace DICUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to provide a converter to XAML files to render comboboxes with enum values
|
||||
/// </summary>
|
||||
public class EnumDescriptionConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
// Common
|
||||
if (value is MediaType?)
|
||||
return ((MediaType?)value).LongName();
|
||||
else if (value is KnownSystem?)
|
||||
return ((KnownSystem?)value).LongName();
|
||||
|
||||
// Default
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
208
DICUI/Options.cs
208
DICUI/Options.cs
@@ -1,208 +0,0 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using DICUI.Data;
|
||||
|
||||
namespace DICUI
|
||||
{
|
||||
public class Options
|
||||
{
|
||||
public string DefaultOutputPath { get; private set; }
|
||||
public string AaruPath { get; private set; }
|
||||
public string CreatorPath { get; private set; }
|
||||
public string SubDumpPath { get; private set; }
|
||||
|
||||
public string InternalProgram { get; set; }
|
||||
|
||||
public int PreferredDumpSpeedCD { get; set; }
|
||||
public int PreferredDumpSpeedDVD { get; set; }
|
||||
public int PreferredDumpSpeedBD { get; set; }
|
||||
|
||||
public bool QuietMode { get; set; }
|
||||
public bool ParanoidMode { get; set; }
|
||||
public bool ScanForProtection { get; set; }
|
||||
public int RereadAmountForC2 { get; set; }
|
||||
public bool AddPlaceholders { get; set; }
|
||||
public bool PromptForDiscInformation { get; set; }
|
||||
public bool IgnoreFixedDrives { get; set; }
|
||||
public bool ResetDriveAfterDump { get; set; }
|
||||
|
||||
public bool SkipMediaTypeDetection { get; set; }
|
||||
public bool SkipSystemDetection { get; set; }
|
||||
|
||||
public bool VerboseLogging { get; set; }
|
||||
public bool OpenLogWindowAtStartup { get; set; }
|
||||
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
|
||||
public void Save()
|
||||
{
|
||||
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
|
||||
|
||||
//TODO: reflection is used
|
||||
//TODO: is remove needed, doesn't the value get directly overridden
|
||||
Array.ForEach(
|
||||
GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance),
|
||||
p => {
|
||||
configFile.AppSettings.Settings.Remove(p.Name);
|
||||
configFile.AppSettings.Settings.Add(p.Name, Convert.ToString(p.GetValue(this)));
|
||||
}
|
||||
);
|
||||
|
||||
configFile.Save(ConfigurationSaveMode.Modified);
|
||||
}
|
||||
|
||||
public void Load()
|
||||
{
|
||||
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
|
||||
|
||||
//TODO: hardcoded, we should find a better way
|
||||
this.AaruPath = GetStringSetting(configFile, "AaruPath", "Programs\\Aaru\\Aaru.exe");
|
||||
this.CreatorPath = GetStringSetting(configFile, "CreatorPath", "Programs\\Creator\\DiscImageCreator.exe");
|
||||
this.SubDumpPath = GetStringSetting(configFile, "SubDumpPath", "Programs\\Subdump\\subdump.exe");
|
||||
this.DefaultOutputPath = GetStringSetting(configFile, "DefaultOutputPath", "ISO");
|
||||
this.InternalProgram = GetStringSetting(configFile, "InternalProgram", Data.InternalProgram.DiscImageCreator.ToString());
|
||||
|
||||
this.PreferredDumpSpeedCD = GetInt32Setting(configFile, "PreferredDumpSpeedCD", 72);
|
||||
this.PreferredDumpSpeedDVD = GetInt32Setting(configFile, "PreferredDumpSpeedDVD", 24);
|
||||
this.PreferredDumpSpeedBD = GetInt32Setting(configFile, "PreferredDumpSpeedBD", 16);
|
||||
|
||||
this.QuietMode = GetBooleanSetting(configFile, "QuietMode", false);
|
||||
this.ParanoidMode = GetBooleanSetting(configFile, "ParanoidMode", false);
|
||||
this.ScanForProtection = GetBooleanSetting(configFile, "ScanForProtection", true);
|
||||
this.SkipMediaTypeDetection = GetBooleanSetting(configFile, "SkipMediaTypeDetection", false);
|
||||
this.SkipSystemDetection = GetBooleanSetting(configFile, "SkipSystemDetection", false);
|
||||
this.RereadAmountForC2 = GetInt32Setting(configFile, "RereadAmountForC2", 20);
|
||||
this.VerboseLogging = GetBooleanSetting(configFile, "VerboseLogging", true);
|
||||
this.OpenLogWindowAtStartup = GetBooleanSetting(configFile, "OpenLogWindowAtStartup", true);
|
||||
this.AddPlaceholders = GetBooleanSetting(configFile, "AddPlaceholders", true);
|
||||
this.PromptForDiscInformation = GetBooleanSetting(configFile, "PromptForDiscInformation", true);
|
||||
this.IgnoreFixedDrives = GetBooleanSetting(configFile, "IgnoreFixedDrives", false);
|
||||
this.ResetDriveAfterDump = GetBooleanSetting(configFile, "ResetDriveAfterDump", false);
|
||||
|
||||
this.Username = GetStringSetting(configFile, "Username", "");
|
||||
this.Password = GetStringSetting(configFile, "Password", "");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a boolean setting from a configuration
|
||||
/// </summary>
|
||||
/// <param name="configFile">Current configuration file</param>
|
||||
/// <param name="key">Setting key to get a value for</param>
|
||||
/// <param name="defaultValue">Default value to return if no value is found</param>
|
||||
/// <returns>Setting value if possible, default value otherwise</returns>
|
||||
public bool GetBooleanSetting(Configuration configFile, string key, bool defaultValue)
|
||||
{
|
||||
var settings = configFile.AppSettings.Settings;
|
||||
if (settings.AllKeys.Contains(key))
|
||||
{
|
||||
if (Boolean.TryParse(settings[key].Value, out bool value))
|
||||
return value;
|
||||
else
|
||||
return defaultValue;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a boolean setting from a configuration
|
||||
/// </summary>
|
||||
/// <param name="configFile">Current configuration file</param>
|
||||
/// <param name="key">Setting key to get a value for</param>
|
||||
/// <param name="defaultValue">Default value to return if no value is found</param>
|
||||
/// <returns>Setting value if possible, default value otherwise</returns>
|
||||
public int GetInt32Setting(Configuration configFile, string key, int defaultValue)
|
||||
{
|
||||
var settings = configFile.AppSettings.Settings;
|
||||
if (settings.AllKeys.Contains(key))
|
||||
{
|
||||
if (Int32.TryParse(settings[key].Value, out int value))
|
||||
return value;
|
||||
else
|
||||
return defaultValue;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a boolean setting from a configuration
|
||||
/// </summary>
|
||||
/// <param name="configFile">Current configuration file</param>
|
||||
/// <param name="key">Setting key to get a value for</param>
|
||||
/// <param name="defaultValue">Default value to return if no value is found</param>
|
||||
/// <returns>Setting value if possible, default value otherwise</returns>
|
||||
public long GetInt64Setting(Configuration configFile, string key, long defaultValue)
|
||||
{
|
||||
var settings = configFile.AppSettings.Settings;
|
||||
if (settings.AllKeys.Contains(key))
|
||||
{
|
||||
if (Int64.TryParse(settings[key].Value, out long value))
|
||||
return value;
|
||||
else
|
||||
return defaultValue;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a boolean setting from a configuration
|
||||
/// </summary>
|
||||
/// <param name="configFile">Current configuration file</param>
|
||||
/// <param name="key">Setting key to get a value for</param>
|
||||
/// <param name="defaultValue">Default value to return if no value is found</param>
|
||||
/// <returns>Setting value if possible, default value otherwise</returns>
|
||||
public string GetStringSetting(Configuration configFile, string key, string defaultValue)
|
||||
{
|
||||
var settings = configFile.AppSettings.Settings;
|
||||
if (settings.AllKeys.Contains(key))
|
||||
return settings[key].Value;
|
||||
else
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
//TODO: probably should be generic for non-string options
|
||||
//TODO: using reflection for Set and Get is orthodox but it works, should be changed to a key,value map probably
|
||||
public void Set(string key, string value)
|
||||
{
|
||||
GetType().GetProperty(key, BindingFlags.Public | BindingFlags.Instance).SetValue(this, value);
|
||||
}
|
||||
|
||||
public string Get(string key)
|
||||
{
|
||||
return GetType().GetProperty(key, BindingFlags.Public | BindingFlags.Instance).GetValue(this) as string;
|
||||
}
|
||||
|
||||
public int GetPreferredDumpSpeedForMediaType(MediaType? type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
case MediaType.GDROM:
|
||||
return PreferredDumpSpeedCD;
|
||||
case MediaType.DVD:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return PreferredDumpSpeedDVD;
|
||||
case MediaType.BluRay:
|
||||
return PreferredDumpSpeedBD;
|
||||
default:
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("DICUI")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("DICUI")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2020")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//In order to begin building localizable applications, set
|
||||
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||
//inside a <PropertyGroup>. For example, if you are using US english
|
||||
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||
//the line below to match the UICulture setting in the project file.
|
||||
|
||||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
||||
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.16")]
|
||||
[assembly: AssemblyFileVersion("1.16.0.0")]
|
||||
|
||||
// Anything marked as internal can be used by the test methods
|
||||
[assembly: InternalsVisibleTo("DICUI.Test")]
|
||||
@@ -1,155 +0,0 @@
|
||||
using System;
|
||||
using System.Windows.Media;
|
||||
using DICUI.Windows;
|
||||
|
||||
namespace DICUI
|
||||
{
|
||||
public class OptionsViewModel
|
||||
{
|
||||
private Options _options;
|
||||
|
||||
public OptionsViewModel(Options options)
|
||||
{
|
||||
this._options = options;
|
||||
}
|
||||
|
||||
public string InternalProgram
|
||||
{
|
||||
get { return _options.InternalProgram; }
|
||||
set { _options.InternalProgram = value; }
|
||||
}
|
||||
|
||||
public bool QuietMode
|
||||
{
|
||||
get { return _options.QuietMode; }
|
||||
set { _options.QuietMode = value; }
|
||||
}
|
||||
|
||||
public bool ParanoidMode
|
||||
{
|
||||
get { return _options.ParanoidMode; }
|
||||
set { _options.ParanoidMode = value; }
|
||||
}
|
||||
|
||||
public bool ScanForProtection
|
||||
{
|
||||
get { return _options.ScanForProtection; }
|
||||
set { _options.ScanForProtection = value; }
|
||||
}
|
||||
|
||||
public string RereadAmountForC2
|
||||
{
|
||||
get { return Convert.ToString(_options.RereadAmountForC2); }
|
||||
set
|
||||
{
|
||||
if (Int32.TryParse(value, out int result))
|
||||
_options.RereadAmountForC2 = result;
|
||||
}
|
||||
}
|
||||
|
||||
public bool AddPlaceholders
|
||||
{
|
||||
get { return _options.AddPlaceholders; }
|
||||
set { _options.AddPlaceholders = value; }
|
||||
}
|
||||
|
||||
public bool PromptForDiscInformation
|
||||
{
|
||||
get { return _options.PromptForDiscInformation; }
|
||||
set { _options.PromptForDiscInformation = value; }
|
||||
}
|
||||
|
||||
public bool IgnoreFixedDrives
|
||||
{
|
||||
get { return _options.IgnoreFixedDrives; }
|
||||
set { _options.IgnoreFixedDrives = value; }
|
||||
}
|
||||
|
||||
public bool ResetDriveAfterDump
|
||||
{
|
||||
get { return _options.ResetDriveAfterDump; }
|
||||
set { _options.ResetDriveAfterDump = value; }
|
||||
}
|
||||
|
||||
public bool SkipMediaTypeDetection
|
||||
{
|
||||
get { return _options.SkipMediaTypeDetection; }
|
||||
set { _options.SkipMediaTypeDetection = value; }
|
||||
}
|
||||
|
||||
public bool SkipSystemDetection
|
||||
{
|
||||
get { return _options.SkipSystemDetection; }
|
||||
set { _options.SkipSystemDetection = value; }
|
||||
}
|
||||
|
||||
public bool VerboseLogging
|
||||
{
|
||||
get { return _options.VerboseLogging; }
|
||||
set
|
||||
{
|
||||
_options.VerboseLogging = value;
|
||||
_options.Save();
|
||||
}
|
||||
}
|
||||
|
||||
public bool OpenLogWindowAtStartup
|
||||
{
|
||||
get { return _options.OpenLogWindowAtStartup; }
|
||||
set
|
||||
{
|
||||
_options.OpenLogWindowAtStartup = value;
|
||||
_options.Save();
|
||||
}
|
||||
}
|
||||
|
||||
public string Username
|
||||
{
|
||||
get { return _options.Username; }
|
||||
set { _options.Username = value; }
|
||||
}
|
||||
|
||||
public string Password
|
||||
{
|
||||
get { return _options.Password; }
|
||||
set { _options.Password = value; }
|
||||
}
|
||||
}
|
||||
|
||||
public class LoggerViewModel
|
||||
{
|
||||
private LogWindow _logWindow;
|
||||
|
||||
public void SetWindow(LogWindow logWindow) => _logWindow = logWindow;
|
||||
|
||||
public bool WindowVisible
|
||||
{
|
||||
get => _logWindow != null ? _logWindow.IsVisible : false;
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
_logWindow.AdjustPositionToMainWindow();
|
||||
_logWindow.Show();
|
||||
}
|
||||
else
|
||||
_logWindow.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
public void VerboseLog(string text)
|
||||
{
|
||||
if (ViewModels.OptionsViewModel.VerboseLogging)
|
||||
_logWindow.AppendToTextBox(text, Brushes.Yellow);
|
||||
}
|
||||
|
||||
public void VerboseLog(string format, params object[] args) => VerboseLog(string.Format(format, args));
|
||||
public void VerboseLogLn(string format, params object[] args) => VerboseLog(string.Format(format, args) + "\n");
|
||||
}
|
||||
|
||||
public static class ViewModels
|
||||
{
|
||||
public static OptionsViewModel OptionsViewModel { get; set; }
|
||||
public static LoggerViewModel LoggerViewModel { get; set; } = new LoggerViewModel();
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
<Window x:Class="DICUI.Windows.DiscInformationWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:DICUI"
|
||||
mc:Ignorable="d"
|
||||
Title="Disc Information" Height="705" Width="515.132" ResizeMode="NoResize"
|
||||
Closed="OnClosed">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="585"/>
|
||||
<RowDefinition Height="80"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<GroupBox Grid.Row="0" Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Common Disc Information">
|
||||
<Grid Margin="10,15,10,10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
<RowDefinition Height="25"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Title" />
|
||||
<TextBox x:Name="TitleTextBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Foreign Title (Non-Latin)" />
|
||||
<TextBox x:Name="ForeignTitleTextBox" Grid.Row="1" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Disc Number / Letter" />
|
||||
<TextBox x:Name="DiscNumberLetterTextBox" Grid.Row="2" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
|
||||
<Label Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Disc Title" />
|
||||
<TextBox x:Name="DiscTitleTextBox" Grid.Row="3" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
|
||||
<Label Grid.Row="4" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Category" />
|
||||
<ComboBox x:Name="CategoryComboBox" Grid.Row="4" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" >
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Path=Name}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<Label Grid.Row="5" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Region" />
|
||||
<ComboBox x:Name="RegionComboBox" Grid.Row="5" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" >
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Path=Name}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<Label Grid.Row="6" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Languages" />
|
||||
<ComboBox x:Name="LanguagesComboBox" Grid.Row="6" Grid.Column="1" Height="24" HorizontalAlignment="Stretch" >
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Path=Name}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<Label Grid.Row="7" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Serial" />
|
||||
<TextBox x:Name="SerialTextBox" Grid.Row="7" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
|
||||
<!-- Layer 0 / Data Side -->
|
||||
<Label Grid.Row="8" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Data/L0 Mastering Ring" />
|
||||
<TextBox x:Name="L0MasteringRingTextBox" Grid.Row="8" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" AcceptsTab="True" />
|
||||
|
||||
<Label Grid.Row="9" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Data/L0 Mastering SID" />
|
||||
<TextBox x:Name="L0MasteringSIDTextBox" Grid.Row="9" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
|
||||
<Label Grid.Row="10" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Data/L0 Toolstamp/Mastering Code" />
|
||||
<TextBox x:Name="L0ToolstampTextBox" Grid.Row="10" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
|
||||
<Label Grid.Row="11" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Data/L0 Mould SID" />
|
||||
<TextBox x:Name="L0MouldSIDTextBox" Grid.Row="11" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
|
||||
<Label Grid.Row="12" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Data/L0 Additional Mould" />
|
||||
<TextBox x:Name="L0AdditionalMouldTextBox" Grid.Row="12" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
|
||||
<!-- Layer 1 / Label Side -->
|
||||
<Label Grid.Row="13" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Label/L1 Mastering Ring" />
|
||||
<TextBox x:Name="L1MasteringRingTextBox" Grid.Row="13" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" AcceptsTab="True" />
|
||||
|
||||
<Label Grid.Row="14" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Label/L1 Mastering SID" />
|
||||
<TextBox x:Name="L1MasteringSIDTextBox" Grid.Row="14" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
|
||||
<Label Grid.Row="15" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Label/L1 Toolstamp/Mastering Code" />
|
||||
<TextBox x:Name="L1ToolstampTextBox" Grid.Row="15" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
|
||||
<Label Grid.Row="16" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Label/L1 Mould SID" />
|
||||
<TextBox x:Name="L1MouldSIDTextBox" Grid.Row="16" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
|
||||
<Label Grid.Row="17" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Label/L1 Additional Mould" />
|
||||
<TextBox x:Name="L1AdditionalMouldTextBox" Grid.Row="17" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
|
||||
<Label Grid.Row="18" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Barcode" />
|
||||
<TextBox x:Name="BarcodeTextBox" Grid.Row="18" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
|
||||
<!-- This needs to be a multiline textbox -->
|
||||
<Label Grid.Row="19" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Comments" />
|
||||
<TextBox x:Name="CommentsTextBox" Grid.Row="19" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" AcceptsReturn="True" AcceptsTab="True" />
|
||||
|
||||
<!-- This needs to be a multiline textbox -->
|
||||
<Label Grid.Row="20" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Contents" />
|
||||
<TextBox x:Name="ContentsTextBox" Grid.Row="20" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" AcceptsReturn="True" AcceptsTab="True"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="1" Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Version and Editions">
|
||||
<Grid Height="60">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="24"/>
|
||||
<RowDefinition Height="24"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Version" />
|
||||
<TextBox x:Name="VersionTextBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Edition" />
|
||||
<TextBox x:Name="EditionTextBox" Grid.Row="1" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,190 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using DICUI.Data;
|
||||
|
||||
namespace DICUI.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for DiscInformationWindow.xaml
|
||||
/// </summary>
|
||||
public partial class DiscInformationWindow : Window
|
||||
{
|
||||
private readonly MainWindow _mainWindow;
|
||||
private readonly SubmissionInfo _submissionInfo;
|
||||
|
||||
private List<CategoryComboBoxItem> _categories;
|
||||
private List<RegionComboBoxItem> _regions;
|
||||
private List<LanguageComboBoxItem> _languages;
|
||||
|
||||
public DiscInformationWindow(MainWindow mainWindow, SubmissionInfo submissionInfo)
|
||||
{
|
||||
InitializeComponent();
|
||||
_mainWindow = mainWindow;
|
||||
_submissionInfo = submissionInfo;
|
||||
|
||||
PopulateCategories();
|
||||
PopulateRegions();
|
||||
PopulateLanguages();
|
||||
DisableFieldsIfNeeded();
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
TitleTextBox.Text = _submissionInfo.CommonDiscInfo.Title ?? "";
|
||||
ForeignTitleTextBox.Text = _submissionInfo.CommonDiscInfo.ForeignTitleNonLatin ?? "";
|
||||
DiscNumberLetterTextBox.Text = _submissionInfo.CommonDiscInfo.DiscNumberLetter ?? "";
|
||||
DiscTitleTextBox.Text = _submissionInfo.CommonDiscInfo.DiscTitle ?? "";
|
||||
CategoryComboBox.SelectedIndex = _categories.FindIndex(r => r == _submissionInfo.CommonDiscInfo.Category);
|
||||
RegionComboBox.SelectedIndex = _regions.FindIndex(r => r == _submissionInfo.CommonDiscInfo.Region);
|
||||
if (_submissionInfo.CommonDiscInfo.Languages != null)
|
||||
{
|
||||
foreach (var language in _submissionInfo.CommonDiscInfo.Languages)
|
||||
_languages.Find(l => l == language).IsChecked = true;
|
||||
}
|
||||
SerialTextBox.Text = _submissionInfo.CommonDiscInfo.Serial ?? "";
|
||||
L0MasteringRingTextBox.Text = _submissionInfo.CommonDiscInfo.MasteringRingFirstLayerDataSide ?? "";
|
||||
L0MasteringSIDTextBox.Text = _submissionInfo.CommonDiscInfo.MasteringSIDCodeFirstLayerDataSide ?? "";
|
||||
L0ToolstampTextBox.Text = _submissionInfo.CommonDiscInfo.ToolstampMasteringCodeFirstLayerDataSide ?? "";
|
||||
L0MouldSIDTextBox.Text = _submissionInfo.CommonDiscInfo.MouldSIDCodeFirstLayerDataSide ?? "";
|
||||
L0AdditionalMouldTextBox.Text = _submissionInfo.CommonDiscInfo.AdditionalMouldFirstLayerDataSide ?? "";
|
||||
L1MasteringRingTextBox.Text = _submissionInfo.CommonDiscInfo.MasteringRingSecondLayerLabelSide ?? "";
|
||||
L1MasteringSIDTextBox.Text = _submissionInfo.CommonDiscInfo.MasteringSIDCodeSecondLayerLabelSide ?? "";
|
||||
L1ToolstampTextBox.Text = _submissionInfo.CommonDiscInfo.ToolstampMasteringCodeSecondLayerLabelSide ?? "";
|
||||
L1MouldSIDTextBox.Text = _submissionInfo.CommonDiscInfo.MouldSIDCodeSecondLayerLabelSide ?? "";
|
||||
L1AdditionalMouldTextBox.Text = _submissionInfo.CommonDiscInfo.AdditionalMouldSecondLayerLabelSide ?? "";
|
||||
BarcodeTextBox.Text = _submissionInfo.CommonDiscInfo.Barcode ?? "";
|
||||
CommentsTextBox.Text = _submissionInfo.CommonDiscInfo.Comments ?? "";
|
||||
ContentsTextBox.Text = _submissionInfo.CommonDiscInfo.Contents ?? "";
|
||||
|
||||
VersionTextBox.Text = _submissionInfo.VersionAndEditions.Version ?? "";
|
||||
EditionTextBox.Text = _submissionInfo.VersionAndEditions.OtherEditions ?? "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a complete list of categories and fill the combo box
|
||||
/// </summary>
|
||||
private void PopulateCategories()
|
||||
{
|
||||
var categories = Enum.GetValues(typeof(Category)).OfType<Category?>().ToList();
|
||||
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Populating categories, {0} categories found.", categories.Count);
|
||||
|
||||
_categories = new List<CategoryComboBoxItem>();
|
||||
foreach (var category in categories)
|
||||
{
|
||||
_categories.Add(new CategoryComboBoxItem(category));
|
||||
}
|
||||
|
||||
CategoryComboBox.ItemsSource = _categories;
|
||||
CategoryComboBox.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a complete list of regions and fill the combo box
|
||||
/// </summary>
|
||||
private void PopulateRegions()
|
||||
{
|
||||
var regions = Enum.GetValues(typeof(Region)).OfType<Region?>().ToList();
|
||||
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Populating regions, {0} regions found.", regions.Count);
|
||||
|
||||
_regions = new List<RegionComboBoxItem>();
|
||||
foreach (var region in regions)
|
||||
{
|
||||
_regions.Add(new RegionComboBoxItem(region));
|
||||
}
|
||||
|
||||
RegionComboBox.ItemsSource = _regions;
|
||||
RegionComboBox.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a complete list of languages and fill the combo box
|
||||
/// </summary>
|
||||
private void PopulateLanguages()
|
||||
{
|
||||
var languages = Enum.GetValues(typeof(Language)).OfType<Language?>().ToList();
|
||||
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Populating languages, {0} languages found.", languages.Count);
|
||||
|
||||
_languages = new List<LanguageComboBoxItem>();
|
||||
foreach (var language in languages)
|
||||
{
|
||||
_languages.Add(new LanguageComboBoxItem(language));
|
||||
}
|
||||
|
||||
LanguagesComboBox.ItemsSource = _languages;
|
||||
LanguagesComboBox.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disable fields that aren't applicable to the current disc
|
||||
/// </summary>
|
||||
private void DisableFieldsIfNeeded()
|
||||
{
|
||||
// Only disable for single-layer discs
|
||||
if (_submissionInfo.SizeAndChecksums.Layerbreak == default(long))
|
||||
{
|
||||
L1MasteringRingTextBox.IsEnabled = false;
|
||||
L1MasteringRingTextBox.Background = Brushes.Gray;
|
||||
|
||||
L1MasteringSIDTextBox.IsEnabled = false;
|
||||
L1MasteringSIDTextBox.Background = Brushes.Gray;
|
||||
|
||||
L1ToolstampTextBox.IsEnabled = false;
|
||||
L1ToolstampTextBox.Background = Brushes.Gray;
|
||||
|
||||
L1MouldSIDTextBox.IsEnabled = false;
|
||||
L1MouldSIDTextBox.Background = Brushes.Gray;
|
||||
|
||||
L1AdditionalMouldTextBox.IsEnabled = false;
|
||||
L1AdditionalMouldTextBox.Background = Brushes.Gray;
|
||||
}
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
private void OnClosed(object sender, EventArgs e)
|
||||
{
|
||||
_submissionInfo.CommonDiscInfo.Title = TitleTextBox.Text ?? "";
|
||||
_submissionInfo.CommonDiscInfo.ForeignTitleNonLatin = ForeignTitleTextBox.Text ?? "";
|
||||
_submissionInfo.CommonDiscInfo.DiscNumberLetter = DiscNumberLetterTextBox.Text ?? "";
|
||||
_submissionInfo.CommonDiscInfo.DiscTitle = DiscTitleTextBox.Text ?? "";
|
||||
_submissionInfo.CommonDiscInfo.Category = (CategoryComboBox.SelectedItem as CategoryComboBoxItem)?.Value ?? Category.Games;
|
||||
_submissionInfo.CommonDiscInfo.Region = (RegionComboBox.SelectedItem as RegionComboBoxItem)?.Value ?? Region.World;
|
||||
var languages = new List<Language?>();
|
||||
foreach (var language in _languages)
|
||||
{
|
||||
if (language.IsChecked)
|
||||
languages.Add(language.Value);
|
||||
}
|
||||
if (languages.Count == 0)
|
||||
languages.Add(null);
|
||||
_submissionInfo.CommonDiscInfo.Languages = languages.ToArray();
|
||||
_submissionInfo.CommonDiscInfo.Serial = SerialTextBox.Text ?? "";
|
||||
_submissionInfo.CommonDiscInfo.MasteringRingFirstLayerDataSide = L0MasteringRingTextBox.Text ?? "";
|
||||
_submissionInfo.CommonDiscInfo.MasteringSIDCodeFirstLayerDataSide = L0MasteringSIDTextBox.Text ?? "";
|
||||
_submissionInfo.CommonDiscInfo.ToolstampMasteringCodeFirstLayerDataSide = L0ToolstampTextBox.Text ?? "";
|
||||
_submissionInfo.CommonDiscInfo.MouldSIDCodeFirstLayerDataSide = L0MouldSIDTextBox.Text ?? "";
|
||||
_submissionInfo.CommonDiscInfo.AdditionalMouldFirstLayerDataSide = L0AdditionalMouldTextBox.Text ?? "";
|
||||
_submissionInfo.CommonDiscInfo.MasteringRingSecondLayerLabelSide = L1MasteringRingTextBox.Text ?? "";
|
||||
_submissionInfo.CommonDiscInfo.MasteringSIDCodeSecondLayerLabelSide = L1MasteringSIDTextBox.Text ?? "";
|
||||
_submissionInfo.CommonDiscInfo.ToolstampMasteringCodeSecondLayerLabelSide = L1ToolstampTextBox.Text ?? "";
|
||||
_submissionInfo.CommonDiscInfo.MouldSIDCodeSecondLayerLabelSide = L1MouldSIDTextBox.Text ?? "";
|
||||
_submissionInfo.CommonDiscInfo.AdditionalMouldSecondLayerLabelSide = L1AdditionalMouldTextBox.Text ?? "";
|
||||
_submissionInfo.CommonDiscInfo.Barcode = BarcodeTextBox.Text ?? "";
|
||||
_submissionInfo.CommonDiscInfo.Comments = CommentsTextBox.Text ?? "";
|
||||
_submissionInfo.CommonDiscInfo.Contents = ContentsTextBox.Text ?? "";
|
||||
|
||||
_submissionInfo.VersionAndEditions.Version = VersionTextBox.Text ?? "";
|
||||
_submissionInfo.VersionAndEditions.OtherEditions = EditionTextBox.Text ?? "";
|
||||
|
||||
Hide();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
<Window x:Class="DICUI.Windows.LogWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:DICUI"
|
||||
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
|
||||
Title="Log Window" Height="350" Width="600" Closed="OnWindowClosed" Loaded="OnWindowLoaded"
|
||||
>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="40" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="40" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0" Height="22" Margin="10 10 10 0">
|
||||
<ProgressBar x:Name="progressBar" />
|
||||
<TextBlock x:Name="progressLabel" Grid.Row="0" Height="22" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="0 2 0 0" />
|
||||
</Grid>
|
||||
<Border Grid.Row="1" Background="White" BorderBrush="Gainsboro" BorderThickness="1" Margin="10">
|
||||
<ScrollViewer Name="outputViewer" SizeChanged="ScrollViewer_SizeChanged">
|
||||
<RichTextBox Name="output" FontFamily="Consolas" Background="#202020" IsReadOnly="true" TextChanged="OnTextChanged" />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
|
||||
<Grid Grid.Row="2">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="3*"/>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<CheckBox Content="Verbose" Margin="10 0 0 10" Grid.Column="0" VerticalAlignment="Center"
|
||||
ToolTip="Enable verbose logging of tasks"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
|
||||
IsChecked="{Binding Path=VerboseLogging}"
|
||||
/>
|
||||
<CheckBox Content="Open at startup" Margin="10 0 0 10" Grid.Column="1" Grid.ColumnSpan="2" VerticalAlignment="Center"
|
||||
ToolTip="Open this window at startup"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
|
||||
IsChecked="{Binding Path=OpenLogWindowAtStartup}"
|
||||
/>
|
||||
<Button Margin="0 0 10 10" Grid.Column="3" Height="22" Width="60" Content="Clear" HorizontalAlignment="Right" Click="OnClearButton" />
|
||||
<Button Margin="0 0 10 10" Grid.Column="4" Height="22" Width="60" Content="Hide" HorizontalAlignment="Right" Click="OnHideButton" />
|
||||
<Button Margin="0 0 10 10" Grid.Column="5" Height="22" Width="60" Content="Save" HorizontalAlignment="Right" Click="OnSaveButton" />
|
||||
<Button Visibility="Hidden" Name="AbortButton" Margin="0 0 10 10" Grid.Column="2" Height="22" Width="80" Content="Abort" HorizontalAlignment="Right" Click="OnAbortButton" />
|
||||
</Grid>
|
||||
|
||||
|
||||
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,399 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace DICUI.Windows
|
||||
{
|
||||
public partial class LogWindow : Window
|
||||
{
|
||||
private const int GWL_STYLE = -16;
|
||||
private const int WS_SYSMENU = 0x80000;
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
|
||||
[DllImport("user32.dll")]
|
||||
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
|
||||
|
||||
private MainWindow _mainWindow;
|
||||
|
||||
private FlowDocument _document;
|
||||
private Paragraph _paragraph;
|
||||
private List<Matcher> _matchers;
|
||||
|
||||
volatile Process _process;
|
||||
|
||||
public LogWindow(MainWindow mainWindow)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
this._mainWindow = mainWindow;
|
||||
|
||||
_document = new FlowDocument();
|
||||
_paragraph = new Paragraph();
|
||||
_document.Blocks.Add(_paragraph);
|
||||
output.Document = _document;
|
||||
|
||||
_matchers = new List<Matcher>();
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Descrambling data sector of img (LBA)",
|
||||
@"\s*(\d+)\/\s*(\d+)$",
|
||||
match => {
|
||||
if (UInt32.TryParse(match.Groups[1].Value, out uint current) && UInt32.TryParse(match.Groups[2].Value, out uint total))
|
||||
{
|
||||
float percentProgress = (current / (float)total) * 100;
|
||||
progressBar.Value = percentProgress;
|
||||
progressLabel.Text = string.Format("Descrambling image.. ({0:##.##}%)", percentProgress);
|
||||
}
|
||||
}));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
@"Creating .scm (LBA)",
|
||||
@"\s*(\d+)\/\s*(\d+)$",
|
||||
match => {
|
||||
if (UInt32.TryParse(match.Groups[1].Value, out uint current) && UInt32.TryParse(match.Groups[2].Value, out uint total))
|
||||
{
|
||||
float percentProgress = (current / (float)total) * 100;
|
||||
progressBar.Value = percentProgress;
|
||||
progressLabel.Text = string.Format("Creating scrambled image.. ({0:##.##}%)", percentProgress);
|
||||
}
|
||||
}));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Checking sectors (LBA)",
|
||||
@"\s*(\d+)\/\s*(\d+)$",
|
||||
match => {
|
||||
if (UInt32.TryParse(match.Groups[1].Value, out uint current) && UInt32.TryParse(match.Groups[2].Value, out uint total))
|
||||
{
|
||||
float percentProgress = (current / (float)total) * 100;
|
||||
progressBar.Value = percentProgress;
|
||||
progressLabel.Text = string.Format("Checking for errors.. ({0:##.##}%)", percentProgress);
|
||||
}
|
||||
}));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Scanning sector (LBA)",
|
||||
@"\s*(\d+)\/\s*(\d+)$",
|
||||
match => {
|
||||
if (UInt32.TryParse(match.Groups[1].Value, out uint current) && UInt32.TryParse(match.Groups[2].Value, out uint total))
|
||||
{
|
||||
float percentProgress = (current / (float)total) * 100;
|
||||
progressBar.Value = percentProgress;
|
||||
progressLabel.Text = string.Format("Scanning sectors for protection.. ({0:##.##}%)", percentProgress);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public void StartDump(string args)
|
||||
{
|
||||
AppendToTextBox(string.Format("Launching DIC with args: {0}\r\n", args), Brushes.Orange);
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
_process = new Process()
|
||||
{
|
||||
StartInfo = new ProcessStartInfo()
|
||||
{
|
||||
FileName = @"Programs/DiscImageCreator.exe",
|
||||
Arguments = args,
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
},
|
||||
};
|
||||
|
||||
StreamState stdoutState = new StreamState(false);
|
||||
StreamState stderrState = new StreamState(true);
|
||||
|
||||
//_cmd.ErrorDataReceived += (process, text) => Dispatcher.Invoke(() => UpdateConsole(text.Data, Brushes.Red));
|
||||
_process.Start();
|
||||
|
||||
var _1 = ConsumeOutput(_process.StandardOutput, s => Dispatcher.Invoke(() => UpdateConsole(s, stdoutState)));
|
||||
var _2 = ConsumeOutput(_process.StandardError, s => Dispatcher.Invoke(() => UpdateConsole(s, stderrState)));
|
||||
|
||||
_process.EnableRaisingEvents = true;
|
||||
_process.Exited += OnProcessExit;
|
||||
});
|
||||
}
|
||||
|
||||
public void AdjustPositionToMainWindow()
|
||||
{
|
||||
this.Left = _mainWindow.Left;
|
||||
this.Top = _mainWindow.Top + _mainWindow.Height + Constants.LogWindowMarginFromMainWindow;
|
||||
}
|
||||
|
||||
private void GracefullyTerminateProcess()
|
||||
{
|
||||
if (_process != null)
|
||||
{
|
||||
_process.Exited -= OnProcessExit;
|
||||
bool isForced = !_process.HasExited;
|
||||
|
||||
if (isForced)
|
||||
{
|
||||
AppendToTextBox("\r\nForcefully Killing the process\r\n", Brushes.Red);
|
||||
_process.Kill();
|
||||
_process.WaitForExit();
|
||||
}
|
||||
|
||||
AppendToTextBox(string.Format("\r\nExit Code: {0}\r\n", _process.ExitCode), _process.ExitCode == 0 ? Brushes.Green : Brushes.Red);
|
||||
|
||||
if (_process.ExitCode == 0)
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
progressLabel.Text = "Done!";
|
||||
progressBar.Value = 100;
|
||||
progressBar.Foreground = Brushes.Green;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
progressLabel.Text = isForced ? "Aborted by user" : "Error, please check log!";
|
||||
progressBar.Value = 100;
|
||||
progressBar.Foreground = Brushes.Red;
|
||||
});
|
||||
}
|
||||
|
||||
_process.Close();
|
||||
}
|
||||
|
||||
_process = null;
|
||||
}
|
||||
|
||||
private void ScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
outputViewer.ScrollToBottom();
|
||||
}
|
||||
|
||||
async Task ConsumeOutput(TextReader reader, Action<string> callback)
|
||||
{
|
||||
char[] buffer = new char[256];
|
||||
int cch;
|
||||
|
||||
while ((cch = await reader.ReadAsync(buffer, 0, buffer.Length)) > 0)
|
||||
{
|
||||
callback(new string(buffer, 0, cch));
|
||||
}
|
||||
}
|
||||
|
||||
// this is used to optimize the work since we need to process A LOT of text
|
||||
struct Matcher
|
||||
{
|
||||
private readonly string prefix;
|
||||
private readonly Regex regex;
|
||||
private readonly int start;
|
||||
private readonly Action<Match> lambda;
|
||||
|
||||
public Matcher(string prefix, string regex, Action<Match> lambda)
|
||||
{
|
||||
this.prefix = prefix;
|
||||
this.regex = new Regex(regex);
|
||||
this.start = prefix.Length;
|
||||
this.lambda = lambda;
|
||||
}
|
||||
|
||||
public bool Matches(ref string text) => text.StartsWith(prefix);
|
||||
|
||||
public void Apply(ref string text)
|
||||
{
|
||||
Match match = regex.Match(text, start);
|
||||
lambda.Invoke(match);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessStringForProgressBar(string text)
|
||||
{
|
||||
foreach (Matcher matcher in _matchers)
|
||||
{
|
||||
if (matcher.Matches(ref text))
|
||||
{
|
||||
matcher.Apply(ref text);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class StreamState
|
||||
{
|
||||
public enum State
|
||||
{
|
||||
BEGIN,
|
||||
READ_CARRIAGE,
|
||||
};
|
||||
|
||||
public State state;
|
||||
public readonly StringBuilder buffer;
|
||||
public readonly bool isError;
|
||||
|
||||
public StreamState(bool isError)
|
||||
{
|
||||
this.state = State.BEGIN;
|
||||
this.buffer = new StringBuilder();
|
||||
this.isError = isError;
|
||||
}
|
||||
|
||||
public bool HasData() => buffer.Length > 0;
|
||||
public string Fetch() => buffer.ToString();
|
||||
public void Clear() => buffer.Clear();
|
||||
public void Append(char c) => buffer.Append(c);
|
||||
|
||||
public bool Is(State state) => this.state == state;
|
||||
public void Set(State state) => this.state = state;
|
||||
}
|
||||
|
||||
public void AppendToTextBox(string text, Brush color)
|
||||
{
|
||||
if (Application.Current.Dispatcher.CheckAccess())
|
||||
{
|
||||
Run run = new Run(text) { Foreground = color };
|
||||
_paragraph.Inlines.Add(run);
|
||||
}
|
||||
else
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
Run run = new Run(text) { Foreground = color };
|
||||
_paragraph.Inlines.Add(run);
|
||||
});
|
||||
}
|
||||
|
||||
private void UpdateConsole(string text, StreamState state)
|
||||
{
|
||||
/*if (c == '\r') { output.Inlines.Add(@"\r"); file.Write("\\r"); }
|
||||
else if (c == '\n') { output.Inlines.Add(@"\n"); file.Write("\\n\n"); }
|
||||
output.Inlines.Add(""+c);
|
||||
file.Write(c);
|
||||
file.Flush();
|
||||
continue;*/
|
||||
|
||||
if (text != null)
|
||||
{
|
||||
foreach (char c in text)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '\r' when (state.Is(StreamState.State.BEGIN)):
|
||||
{
|
||||
state.Set(StreamState.State.READ_CARRIAGE);
|
||||
break;
|
||||
}
|
||||
|
||||
case '\n' when (state.Is(StreamState.State.READ_CARRIAGE)):
|
||||
{
|
||||
if (state.buffer.Length > 0)
|
||||
{
|
||||
string buffer = state.Fetch();
|
||||
|
||||
AppendToTextBox(buffer, state.isError ? Brushes.Red : Brushes.White);
|
||||
|
||||
if (!state.isError)
|
||||
ProcessStringForProgressBar(buffer);
|
||||
}
|
||||
_paragraph.Inlines.Add(new LineBreak());
|
||||
state.Clear();
|
||||
state.Set(StreamState.State.BEGIN);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (state.Is(StreamState.State.READ_CARRIAGE) && state.HasData())
|
||||
{
|
||||
if (!(_paragraph.Inlines.LastInline is LineBreak))
|
||||
_paragraph.Inlines.Remove(_paragraph.Inlines.LastInline);
|
||||
|
||||
string buffer = state.Fetch();
|
||||
|
||||
AppendToTextBox(buffer, state.isError ? Brushes.Red : Brushes.White);
|
||||
|
||||
if (!state.isError)
|
||||
ProcessStringForProgressBar(buffer);
|
||||
|
||||
state.Clear();
|
||||
}
|
||||
|
||||
state.Set(StreamState.State.BEGIN);
|
||||
state.Append(c);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region EventHandlers
|
||||
|
||||
private void OnWindowClosed(object sender, EventArgs e)
|
||||
{
|
||||
GracefullyTerminateProcess();
|
||||
}
|
||||
|
||||
private void OnWindowLoaded(object sender, EventArgs e)
|
||||
{
|
||||
var hwnd = new WindowInteropHelper(this).Handle;
|
||||
SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
|
||||
}
|
||||
|
||||
void OnProcessExit(object sender, EventArgs e)
|
||||
{
|
||||
Dispatcher.Invoke(() => AbortButton.IsEnabled = false);
|
||||
GracefullyTerminateProcess();
|
||||
}
|
||||
|
||||
private void OnHideButton(object sender, EventArgs e)
|
||||
{
|
||||
ViewModels.LoggerViewModel.WindowVisible = false;
|
||||
//TODO: this should be bound directly to WindowVisible property in two way fashion
|
||||
// we need to study how to properly do it in XAML
|
||||
_mainWindow.ShowLogMenuItem.IsChecked = false;
|
||||
}
|
||||
|
||||
private void OnClearButton(object sender, EventArgs e)
|
||||
{
|
||||
output.Document.Blocks.Clear();
|
||||
}
|
||||
|
||||
private void OnSaveButton(object sender, EventArgs e)
|
||||
{
|
||||
using (StreamWriter tw = new StreamWriter(File.OpenWrite("console.log")))
|
||||
{
|
||||
foreach (var inline in _paragraph.Inlines)
|
||||
{
|
||||
if (inline is Run)
|
||||
{
|
||||
tw.Write(((Run)(inline)).Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAbortButton(object sender, EventArgs args)
|
||||
{
|
||||
GracefullyTerminateProcess();
|
||||
}
|
||||
|
||||
private void OnStartButton(object sender, EventArgs args)
|
||||
{
|
||||
StartDump("cd e Gam.iso 16");
|
||||
}
|
||||
|
||||
private void OnTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
outputViewer.ScrollToBottom();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
<Window x:Class="DICUI.Windows.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:DICUI"
|
||||
mc:Ignorable="d"
|
||||
Title="DICUI" Height="450" Width="600" WindowStartupLocation="CenterScreen" ResizeMode="CanMinimize"
|
||||
LocationChanged="MainWindowLocationChanged" Activated="MainWindowActivated" Closing="MainWindowClosing">
|
||||
|
||||
<Window.Resources>
|
||||
<local:EnumDescriptionConverter x:Key="enumConverter" />
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="4*"/>
|
||||
<ColumnDefinition Width="13*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="4*"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel VerticalAlignment="Top" Grid.ColumnSpan="4">
|
||||
<Menu Width="Auto" Height="20" >
|
||||
<MenuItem Header="_File">
|
||||
<MenuItem x:Name="AppExit" Header="E_xit" HorizontalAlignment="Left" Width="185" Click="AppExitClick" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="_Tools">
|
||||
<MenuItem x:Name="OptionsMenuItem" Header="_Options" HorizontalAlignment="Left" Width="185" Click="OptionsClick" />
|
||||
<MenuItem x:Name="ShowLogMenuItem" Header="Show _Log Window" IsCheckable="true" Width="185" HorizontalAlignment="Left"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.LoggerViewModel}}"
|
||||
IsChecked="{Binding Path=WindowVisible}"
|
||||
/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="_Help">
|
||||
<MenuItem x:Name="About" Header="_About" HorizontalAlignment="Left" Width="185" Click="AboutClick" />
|
||||
<MenuItem x:Name="CheckForUpdatesMenuItem" Header="_Check for Updates" HorizontalAlignment="Left" Width="185" Click="CheckForUpdatesClick" />
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</StackPanel>
|
||||
<GroupBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="5,5,5.2,5.4" HorizontalAlignment="Stretch" Header="Settings"/>
|
||||
<GroupBox Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="5,4.6,5.2,4.8" HorizontalAlignment="Stretch" Header="Controls"/>
|
||||
<GroupBox Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Margin="5,5.2,5.2,4.8" HorizontalAlignment="Stretch" Header="Status"/>
|
||||
|
||||
<Grid Grid.Row="1" Grid.Column="0" Margin="15,25,15.2,10.4" Grid.ColumnSpan="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="2.5*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Content="System/Media Type" />
|
||||
<ComboBox x:Name="SystemTypeComboBox" Grid.Row="0" Grid.Column="1" Height="22" Width="250" HorizontalAlignment="Left" SelectionChanged="SystemTypeComboBoxSelectionChanged">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Path=Name}" Foreground="{Binding Path=Foreground}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
<ComboBox x:Name="MediaTypeComboBox" Grid.Row="0" Grid.Column="1" Height="22" Width="140" HorizontalAlignment="Right" SelectionChanged="MediaTypeComboBoxSelectionChanged">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Converter={StaticResource enumConverter}}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" VerticalAlignment="Center">Output Filename</Label>
|
||||
<TextBox x:Name="OutputFilenameTextBox" Grid.Row="1" Grid.Column="1" Height="22" TextChanged="OutputFilenameTextBoxTextChanged" />
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" VerticalAlignment="Center">Output Directory</Label>
|
||||
<TextBox x:Name="OutputDirectoryTextBox" Grid.Row="2" Grid.Column="1" Height="22" Width="345" HorizontalAlignment="Left" TextChanged="OutputDirectoryTextBoxTextChanged" />
|
||||
<Button x:Name="OutputDirectoryBrowseButton" Grid.Row="2" Grid.Column="1" Height="22" Width="50" HorizontalAlignment="Right" Content="Browse" Click="OutputDirectoryBrowseButtonClick"/>
|
||||
|
||||
<Label Grid.Row="3" Grid.Column="0" VerticalAlignment="Center">Drive Letter</Label>
|
||||
<ComboBox x:Name="DriveLetterComboBox" Grid.Row="3" Grid.Column="1" Height="22" Width="60" HorizontalAlignment="Left" SelectionChanged="DriveLetterComboBoxSelectionChanged">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Path=Letter}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<Label Grid.Row="4" Grid.Column="0" VerticalAlignment="Center">Drive Speed</Label>
|
||||
<ComboBox x:Name="DriveSpeedComboBox" Grid.Row="4" Grid.Column="1" Height="22" Width="60" HorizontalAlignment="Left" SelectionChanged="DriveSpeedComboBoxSelectionChanged" />
|
||||
|
||||
<Label Grid.Row="5" Grid.Column="0" VerticalAlignment="Center">Parameters</Label>
|
||||
<TextBox x:Name="ParametersTextBox" Grid.Row="5" Grid.Column="1" Height="22" Width="370" HorizontalAlignment="Left" IsEnabled="False" />
|
||||
<CheckBox x:Name="EnableParametersCheckBox" Grid.Row="5" Grid.Column="1" Height="22" HorizontalAlignment="Right" IsChecked="False" Click="EnableParametersCheckBoxClick" />
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="2" Grid.Column="0" Margin="15,19.6,15.2,9.8" Grid.ColumnSpan="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Button x:Name="StartStopButton" Grid.Row="0" Grid.Column="0" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Start Dumping" Click="StartStopButtonClick" IsEnabled="False" />
|
||||
<Button x:Name="DiskScanButton" Grid.Row="0" Grid.Column="1" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Scan for disks" Click="DiskScanButtonClick" />
|
||||
<Button x:Name="CopyProtectScanButton" Grid.Row="0" Grid.Column="2" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Scan for protection" Click="CopyProtectScanButtonClick" />
|
||||
<CheckBox x:Name="EjectWhenDoneCheckBox" Grid.Row="0" Grid.Column="3" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Eject When Done" IsChecked="False" />
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="3" Grid.Column="0" Margin="15,20.2,15.2,9.8" Grid.ColumnSpan="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label x:Name="StatusLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Waiting for media..." />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,874 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using WinForms = System.Windows.Forms;
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
using DICUI.Web;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace DICUI.Windows
|
||||
{
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
// Private UI-related variables
|
||||
private List<Drive> _drives;
|
||||
private MediaType? _currentMediaType;
|
||||
private List<KnownSystemComboBoxItem> _systems;
|
||||
private List<MediaType?> _mediaTypes;
|
||||
private bool _alreadyShown;
|
||||
|
||||
private DumpEnvironment _env;
|
||||
|
||||
// Option related
|
||||
private Options _options;
|
||||
private OptionsWindow _optionsWindow;
|
||||
|
||||
// User input related
|
||||
private DiscInformationWindow _discInformationWindow;
|
||||
|
||||
private LogWindow _logWindow;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// Initializes and load Options object
|
||||
_options = new Options();
|
||||
_options.Load();
|
||||
ViewModels.OptionsViewModel = new OptionsViewModel(_options);
|
||||
|
||||
_logWindow = new LogWindow(this);
|
||||
ViewModels.LoggerViewModel.SetWindow(_logWindow);
|
||||
|
||||
// Disable buttons until we load fully
|
||||
StartStopButton.IsEnabled = false;
|
||||
DiskScanButton.IsEnabled = false;
|
||||
CopyProtectScanButton.IsEnabled = false;
|
||||
|
||||
if (_options.OpenLogWindowAtStartup)
|
||||
{
|
||||
this.WindowStartupLocation = WindowStartupLocation.Manual;
|
||||
double combinedHeight = this.Height + _logWindow.Height + Constants.LogWindowMarginFromMainWindow;
|
||||
Rectangle bounds = GetScaledCoordinates(WinForms.Screen.PrimaryScreen.WorkingArea);
|
||||
|
||||
this.Left = bounds.Left + (bounds.Width - this.Width) / 2;
|
||||
this.Top = bounds.Top + (bounds.Height - combinedHeight) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
#region Events
|
||||
|
||||
protected override void OnContentRendered(EventArgs e)
|
||||
{
|
||||
base.OnContentRendered(e);
|
||||
|
||||
if (_alreadyShown)
|
||||
return;
|
||||
|
||||
_alreadyShown = true;
|
||||
|
||||
if (_options.OpenLogWindowAtStartup)
|
||||
{
|
||||
//TODO: this should be bound directly to WindowVisible property in two way fashion
|
||||
// we need to study how to properly do it in XAML
|
||||
ShowLogMenuItem.IsChecked = true;
|
||||
ViewModels.LoggerViewModel.WindowVisible = true;
|
||||
}
|
||||
|
||||
// Populate the list of systems
|
||||
StatusLabel.Content = "Creating system list, please wait!";
|
||||
PopulateSystems();
|
||||
|
||||
// Populate the list of drives
|
||||
StatusLabel.Content = "Creating drive list, please wait!";
|
||||
PopulateDrives();
|
||||
}
|
||||
|
||||
private void StartStopButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Dump or stop the dump
|
||||
if ((string)StartStopButton.Content == Constants.StartDumping)
|
||||
{
|
||||
StartDumping();
|
||||
}
|
||||
else if ((string)StartStopButton.Content == Constants.StopDumping)
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Canceling dumping process...");
|
||||
_env.CancelDumping();
|
||||
CopyProtectScanButton.IsEnabled = true;
|
||||
|
||||
if (EjectWhenDoneCheckBox.IsChecked == true)
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLogLn($"Ejecting disc in drive {_env.Drive.Letter}");
|
||||
_env.EjectDisc();
|
||||
}
|
||||
|
||||
if (_options.ResetDriveAfterDump)
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLogLn($"Resetting drive {_env.Drive.Letter}");
|
||||
_env.ResetDrive();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OutputDirectoryBrowseButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
BrowseFolder();
|
||||
EnsureDiscInformation();
|
||||
}
|
||||
|
||||
private void DiskScanButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
PopulateDrives();
|
||||
}
|
||||
|
||||
private void CopyProtectScanButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ScanAndShowProtection();
|
||||
}
|
||||
|
||||
private void SystemTypeComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
// If we're on a separator, go to the next item and return
|
||||
if ((SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem).IsHeader())
|
||||
{
|
||||
SystemTypeComboBox.SelectedIndex++;
|
||||
return;
|
||||
}
|
||||
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Changed system to: {0}", (SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem).Name);
|
||||
PopulateMediaType();
|
||||
GetOutputNames(false);
|
||||
EnsureDiscInformation();
|
||||
}
|
||||
|
||||
private void MediaTypeComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
// Only change the media type if the selection and not the list has changed
|
||||
if (e.RemovedItems.Count == 1 && e.AddedItems.Count == 1)
|
||||
{
|
||||
_currentMediaType = MediaTypeComboBox.SelectedItem as MediaType?;
|
||||
SetSupportedDriveSpeed();
|
||||
}
|
||||
|
||||
GetOutputNames(false);
|
||||
EnsureDiscInformation();
|
||||
}
|
||||
|
||||
private void DriveLetterComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
CacheCurrentDiscType();
|
||||
SetCurrentDiscType();
|
||||
GetOutputNames(true);
|
||||
SetSupportedDriveSpeed();
|
||||
}
|
||||
|
||||
private void DriveSpeedComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
EnsureDiscInformation();
|
||||
}
|
||||
|
||||
private void OutputFilenameTextBoxTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
EnsureDiscInformation();
|
||||
}
|
||||
|
||||
private void OutputDirectoryTextBoxTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
EnsureDiscInformation();
|
||||
}
|
||||
|
||||
private void ProgressUpdated(object sender, Result value)
|
||||
{
|
||||
StatusLabel.Content = value.Message;
|
||||
ViewModels.LoggerViewModel.VerboseLogLn(value.Message);
|
||||
}
|
||||
|
||||
private void MainWindowLocationChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (_logWindow.IsVisible)
|
||||
_logWindow.AdjustPositionToMainWindow();
|
||||
}
|
||||
|
||||
private void MainWindowActivated(object sender, EventArgs e)
|
||||
{
|
||||
if (_logWindow.IsVisible && !this.Topmost)
|
||||
{
|
||||
_logWindow.Topmost = true;
|
||||
_logWindow.Topmost = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void MainWindowClosing(object sender, System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
if (_logWindow.IsVisible)
|
||||
_logWindow.Close();
|
||||
}
|
||||
|
||||
private void EnableParametersCheckBoxClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (EnableParametersCheckBox.IsChecked == true)
|
||||
ParametersTextBox.IsEnabled = true;
|
||||
else
|
||||
{
|
||||
ParametersTextBox.IsEnabled = false;
|
||||
ProcessCustomParameters();
|
||||
}
|
||||
}
|
||||
|
||||
// Toolbar Events
|
||||
|
||||
private void AppExitClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
|
||||
private void AboutClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
MessageBox.Show($"darksabre76 - Project Lead / Backend Design"
|
||||
+ $"{Environment.NewLine}ReignStumble - Former Project Lead / UI Design"
|
||||
+ $"{Environment.NewLine}Jakz - Primary Feature Contributor"
|
||||
+ $"{Environment.NewLine}NHellFire - Feature Contributor", "About", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
|
||||
private void OptionsClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// lazy initialization
|
||||
if (_optionsWindow == null)
|
||||
{
|
||||
_optionsWindow = new OptionsWindow(this, _options);
|
||||
_optionsWindow.Closed += delegate
|
||||
{
|
||||
_optionsWindow = null;
|
||||
};
|
||||
}
|
||||
|
||||
_optionsWindow.Owner = this;
|
||||
_optionsWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||
_optionsWindow.Refresh();
|
||||
_optionsWindow.Show();
|
||||
}
|
||||
|
||||
private void CheckForUpdatesClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Get the current internal version
|
||||
var assemblyVersion = Assembly.GetEntryAssembly().GetName().Version;
|
||||
string version = $"{assemblyVersion.Major}.{assemblyVersion.Minor}" + (assemblyVersion.MajorRevision != 0 ? $".{assemblyVersion.MajorRevision}" : string.Empty);
|
||||
|
||||
// Get the latest tag from GitHub
|
||||
using (var client = new CookieAwareWebClient())
|
||||
{
|
||||
client.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/DICUI/releases/latest";
|
||||
string latestReleaseJsonString = client.DownloadString(url);
|
||||
var latestReleaseJson = JObject.Parse(latestReleaseJsonString);
|
||||
string latestTag = latestReleaseJson["tag_name"].ToString();
|
||||
string releaseUrl = latestReleaseJson["html_url"].ToString();
|
||||
|
||||
bool different = version != latestTag;
|
||||
|
||||
string message = $"Local version: {version}"
|
||||
+ $"{Environment.NewLine}Remote version: {latestTag}"
|
||||
+ (different
|
||||
? $"{Environment.NewLine}The update URL has been added copied to your clipboard"
|
||||
: $"{Environment.NewLine}You have the newest version!");
|
||||
|
||||
// If we have a new version, put it in the clipboard
|
||||
if (different)
|
||||
Clipboard.SetText(releaseUrl);
|
||||
|
||||
MessageBox.Show(message, "Version Update Check", MessageBoxButton.OK, different ? MessageBoxImage.Exclamation : MessageBoxImage.Information);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnOptionsUpdated()
|
||||
{
|
||||
PopulateDrives();
|
||||
GetOutputNames(false);
|
||||
SetSupportedDriveSpeed();
|
||||
EnsureDiscInformation();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Populate media type according to system type
|
||||
/// </summary>
|
||||
private void PopulateMediaType()
|
||||
{
|
||||
KnownSystem? currentSystem = SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem;
|
||||
|
||||
if (currentSystem != null)
|
||||
{
|
||||
_mediaTypes = Validators.GetValidMediaTypes(currentSystem);
|
||||
MediaTypeComboBox.ItemsSource = _mediaTypes;
|
||||
|
||||
MediaTypeComboBox.IsEnabled = _mediaTypes.Count > 1;
|
||||
MediaTypeComboBox.SelectedIndex = (_mediaTypes.IndexOf(_currentMediaType) >= 0 ? _mediaTypes.IndexOf(_currentMediaType) : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
MediaTypeComboBox.IsEnabled = false;
|
||||
MediaTypeComboBox.ItemsSource = null;
|
||||
MediaTypeComboBox.SelectedIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a complete list of supported systems and fill the combo box
|
||||
/// </summary>
|
||||
private void PopulateSystems()
|
||||
{
|
||||
var knownSystems = Validators.CreateListOfSystems();
|
||||
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Populating systems, {0} systems found.", knownSystems.Count);
|
||||
|
||||
Dictionary<KnownSystemCategory, List<KnownSystem?>> mapping = knownSystems
|
||||
.GroupBy(s => s.Category())
|
||||
.ToDictionary(
|
||||
k => k.Key,
|
||||
v => v
|
||||
.OrderBy(s => s.LongName())
|
||||
.ToList()
|
||||
);
|
||||
|
||||
_systems = new List<KnownSystemComboBoxItem>();
|
||||
_systems.Add(new KnownSystemComboBoxItem(KnownSystem.NONE));
|
||||
|
||||
foreach (var group in mapping)
|
||||
{
|
||||
_systems.Add(new KnownSystemComboBoxItem(group.Key));
|
||||
group.Value.ForEach(system => _systems.Add(new KnownSystemComboBoxItem(system)));
|
||||
}
|
||||
|
||||
SystemTypeComboBox.ItemsSource = _systems;
|
||||
SystemTypeComboBox.SelectedIndex = 0;
|
||||
|
||||
StartStopButton.IsEnabled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a complete list of active disc drives and fill the combo box
|
||||
/// </summary>
|
||||
/// <remarks>TODO: Find a way for this to periodically run, or have it hook to a "drive change" event</remarks>
|
||||
private void PopulateDrives()
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Scanning for drives..");
|
||||
|
||||
// Always enable the disk scan
|
||||
DiskScanButton.IsEnabled = true;
|
||||
|
||||
// Populate the list of drives and add it to the combo box
|
||||
_drives = Validators.CreateListOfDrives(_options.IgnoreFixedDrives);
|
||||
DriveLetterComboBox.ItemsSource = _drives;
|
||||
|
||||
if (DriveLetterComboBox.Items.Count > 0)
|
||||
{
|
||||
// Check for active optical drives first
|
||||
int index = _drives.FindIndex(d => d.MarkedActive && d.InternalDriveType == InternalDriveType.Optical);
|
||||
|
||||
// Then we check for floppy drives
|
||||
if (index == -1)
|
||||
index = _drives.FindIndex(d => d.MarkedActive && d.InternalDriveType == InternalDriveType.Floppy);
|
||||
|
||||
// Then we try all other drive types
|
||||
if (index == -1)
|
||||
index = _drives.FindIndex(d => d.MarkedActive);
|
||||
|
||||
// Set the selected index
|
||||
DriveLetterComboBox.SelectedIndex = (index != -1 ? index : 0);
|
||||
StatusLabel.Content = "Valid drive found! Choose your Media Type";
|
||||
CopyProtectScanButton.IsEnabled = true;
|
||||
|
||||
// Get the current media type
|
||||
if (!_options.SkipSystemDetection && index != -1)
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLog("Trying to detect system for drive {0}.. ", _drives[index].Letter);
|
||||
var currentSystem = Validators.GetKnownSystem(_drives[index]);
|
||||
ViewModels.LoggerViewModel.VerboseLogLn(currentSystem == null || currentSystem == KnownSystem.NONE ? "unable to detect." : ("detected " + currentSystem.LongName() + "."));
|
||||
|
||||
if (currentSystem != null && currentSystem != KnownSystem.NONE)
|
||||
{
|
||||
int sysIndex = _systems.FindIndex(s => s == currentSystem);
|
||||
SystemTypeComboBox.SelectedIndex = sysIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// Only enable the start/stop if we don't have the default selected
|
||||
StartStopButton.IsEnabled = (SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem) != KnownSystem.NONE;
|
||||
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Found {0} drives: {1}", _drives.Count, string.Join(", ", _drives.Select(d => d.Letter)));
|
||||
}
|
||||
else
|
||||
{
|
||||
DriveLetterComboBox.SelectedIndex = -1;
|
||||
StatusLabel.Content = "No valid drive found!";
|
||||
StartStopButton.IsEnabled = false;
|
||||
CopyProtectScanButton.IsEnabled = false;
|
||||
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Found no drives");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Browse for an output folder
|
||||
/// </summary>
|
||||
private void BrowseFolder()
|
||||
{
|
||||
WinForms.FolderBrowserDialog folderDialog = new WinForms.FolderBrowserDialog { ShowNewFolderButton = false, SelectedPath = System.AppDomain.CurrentDomain.BaseDirectory };
|
||||
WinForms.DialogResult result = folderDialog.ShowDialog();
|
||||
|
||||
if (result == WinForms.DialogResult.OK)
|
||||
{
|
||||
OutputDirectoryTextBox.Text = folderDialog.SelectedPath;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a DumpEnvironment with all current settings
|
||||
/// </summary>
|
||||
/// <returns>Filled DumpEnvironment instance</returns>
|
||||
private DumpEnvironment DetermineEnvironment()
|
||||
{
|
||||
// Populate the new environment
|
||||
var env = new DumpEnvironment()
|
||||
{
|
||||
// Paths to tools
|
||||
SubdumpPath = _options.SubDumpPath,
|
||||
InternalProgram = Converters.ToInternalProgram(_options.InternalProgram),
|
||||
|
||||
OutputDirectory = OutputDirectoryTextBox.Text,
|
||||
OutputFilename = OutputFilenameTextBox.Text,
|
||||
|
||||
// Get the currently selected options
|
||||
Drive = DriveLetterComboBox.SelectedItem as Drive,
|
||||
|
||||
QuietMode = _options.QuietMode,
|
||||
ParanoidMode = _options.ParanoidMode,
|
||||
ScanForProtection = _options.ScanForProtection,
|
||||
RereadAmountC2 = _options.RereadAmountForC2,
|
||||
AddPlaceholders = _options.AddPlaceholders,
|
||||
PromptForDiscInformation = _options.PromptForDiscInformation,
|
||||
|
||||
Username = _options.Username,
|
||||
Password = _options.Password,
|
||||
|
||||
System = SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem,
|
||||
Type = MediaTypeComboBox.SelectedItem as MediaType?,
|
||||
};
|
||||
|
||||
// Set parameters and path accordingly
|
||||
env.SetParameters(ParametersTextBox.Text);
|
||||
switch (env.InternalProgram)
|
||||
{
|
||||
case InternalProgram.Aaru:
|
||||
env.Parameters.Path = _options.AaruPath;
|
||||
break;
|
||||
|
||||
case InternalProgram.DiscImageCreator:
|
||||
env.Parameters.Path = _options.CreatorPath;
|
||||
break;
|
||||
}
|
||||
|
||||
// Disable automatic reprocessing of the textboxes until we're done
|
||||
OutputDirectoryTextBox.TextChanged -= OutputDirectoryTextBoxTextChanged;
|
||||
OutputFilenameTextBox.TextChanged -= OutputFilenameTextBoxTextChanged;
|
||||
|
||||
OutputDirectoryTextBox.Text = env.OutputDirectory;
|
||||
OutputFilenameTextBox.Text = env.OutputFilename;
|
||||
|
||||
OutputDirectoryTextBox.TextChanged += OutputDirectoryTextBoxTextChanged;
|
||||
OutputFilenameTextBox.TextChanged += OutputFilenameTextBoxTextChanged;
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Begin the dumping process using the given inputs
|
||||
/// </summary>
|
||||
private async void StartDumping()
|
||||
{
|
||||
if (_env == null)
|
||||
_env = DetermineEnvironment();
|
||||
|
||||
// If still in custom parameter mode, check that users meant to continue or not
|
||||
if (EnableParametersCheckBox.IsChecked == true)
|
||||
{
|
||||
MessageBoxResult result = MessageBox.Show("It looks like you have custom parameters that have not been saved. Would you like to apply those changes before starting to dump?", "Custom Changes", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
EnableParametersCheckBox.IsChecked = false;
|
||||
ParametersTextBox.IsEnabled = false;
|
||||
ProcessCustomParameters();
|
||||
}
|
||||
else if (result == MessageBoxResult.Cancel)
|
||||
return;
|
||||
// If "No", then we continue with the current known environment
|
||||
}
|
||||
|
||||
// Fix the output paths
|
||||
_env.FixOutputPaths();
|
||||
|
||||
try
|
||||
{
|
||||
// Check for the firmware first for DiscImageCreator
|
||||
// TODO: Remove this (and method) once DIC end-to-end logging becomes a thing
|
||||
if (_env.InternalProgram == InternalProgram.DiscImageCreator && !await _env.DriveHasLatestFimrware())
|
||||
{
|
||||
MessageBox.Show($"DiscImageCreator has reported that drive {_env.Drive.Letter} is not updated to the most recent firmware. Please update the firmware for your drive and try again.", "Outdated Firmware", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate that the user explicitly wants an inactive drive to be considered for dumping
|
||||
if (!_env.Drive.MarkedActive)
|
||||
{
|
||||
MessageBoxResult mbresult = MessageBox.Show("The currently selected drive does not appear to contain a disc! Are you sure you want to continue?", "Missing Disc", MessageBoxButton.YesNo, MessageBoxImage.Exclamation);
|
||||
if (mbresult == MessageBoxResult.No || mbresult == MessageBoxResult.Cancel || mbresult == MessageBoxResult.None)
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Dumping aborted!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If a complete dump already exists
|
||||
if (_env.FoundAllFiles())
|
||||
{
|
||||
MessageBoxResult mbresult = MessageBox.Show("A complete dump already exists! Are you sure you want to overwrite?", "Overwrite?", MessageBoxButton.YesNo, MessageBoxImage.Exclamation);
|
||||
if (mbresult == MessageBoxResult.No || mbresult == MessageBoxResult.Cancel || mbresult == MessageBoxResult.None)
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Dumping aborted!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
StartStopButton.Content = Constants.StopDumping;
|
||||
CopyProtectScanButton.IsEnabled = false;
|
||||
StatusLabel.Content = "Beginning dumping process";
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Starting dumping process..");
|
||||
|
||||
var progress = new Progress<Result>();
|
||||
progress.ProgressChanged += ProgressUpdated;
|
||||
Result result = await _env.Run(progress);
|
||||
|
||||
// If we didn't execute a dumping command we cannot get submission output
|
||||
if (!_env.Parameters.IsDumpingCommand())
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("No dumping command was run, submission information will not be gathered.");
|
||||
StatusLabel.Content = "Execution complete!";
|
||||
StartStopButton.Content = Constants.StartDumping;
|
||||
CopyProtectScanButton.IsEnabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
// TODO: Remove Aaru handling when irrelevant
|
||||
if (_env.InternalProgram == InternalProgram.Aaru)
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Aaru does not support split tracks or DiscImageCreator-compatible outputs");
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("No automatic submission information will be gathered for this disc");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Verify dump output and save it
|
||||
result = _env.VerifyAndSaveDumpOutput(progress,
|
||||
EjectWhenDoneCheckBox.IsChecked,
|
||||
_options.ResetDriveAfterDump,
|
||||
(si) =>
|
||||
{
|
||||
// lazy initialization
|
||||
if (_discInformationWindow == null)
|
||||
{
|
||||
_discInformationWindow = new DiscInformationWindow(this, si);
|
||||
_discInformationWindow.Closed += delegate
|
||||
{
|
||||
_discInformationWindow = null;
|
||||
};
|
||||
}
|
||||
|
||||
_discInformationWindow.Owner = this;
|
||||
_discInformationWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||
_discInformationWindow.Refresh();
|
||||
return _discInformationWindow.ShowDialog();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
StatusLabel.Content = result ? "Dumping complete!" : result.Message;
|
||||
ViewModels.LoggerViewModel.VerboseLogLn(result ? "Dumping complete!" : result.Message);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// No-op, we don't care what it was
|
||||
}
|
||||
finally
|
||||
{
|
||||
StartStopButton.Content = Constants.StartDumping;
|
||||
CopyProtectScanButton.IsEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure information is consistent with the currently selected disc type
|
||||
/// </summary>
|
||||
private void EnsureDiscInformation()
|
||||
{
|
||||
// Get the current environment information
|
||||
_env = DetermineEnvironment();
|
||||
|
||||
// Take care of null cases
|
||||
if (_env.System == null)
|
||||
_env.System = KnownSystem.NONE;
|
||||
if (_env.Type == null)
|
||||
_env.Type = MediaType.NONE;
|
||||
|
||||
// Get the status to write out
|
||||
Result result = Validators.GetSupportStatus(_env.System, _env.Type);
|
||||
StatusLabel.Content = result.Message;
|
||||
|
||||
// Set the index for the current disc type
|
||||
SetCurrentDiscType();
|
||||
|
||||
StartStopButton.IsEnabled = result && (_drives != null && _drives.Count > 0 ? true : false);
|
||||
|
||||
// If we're in a type that doesn't support drive speeds
|
||||
DriveSpeedComboBox.IsEnabled = _env.Type.DoesSupportDriveSpeed();
|
||||
|
||||
// If input params are not enabled, generate the full parameters from the environment
|
||||
if (!ParametersTextBox.IsEnabled)
|
||||
{
|
||||
string generated = _env.GetFullParameters((int?)DriveSpeedComboBox.SelectedItem);
|
||||
if (generated != null)
|
||||
ParametersTextBox.Text = generated;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the default output directory name from the currently selected drive
|
||||
/// </summary>
|
||||
/// <param name="driveChanged">Force an updated name if the drive letter changes</param>
|
||||
private void GetOutputNames(bool driveChanged)
|
||||
{
|
||||
Drive drive = DriveLetterComboBox.SelectedItem as Drive;
|
||||
KnownSystem? systemType = SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem;
|
||||
MediaType? mediaType = MediaTypeComboBox.SelectedItem as MediaType?;
|
||||
|
||||
// Set the output directory, if we changed drives or it's not already
|
||||
if (driveChanged || string.IsNullOrEmpty(OutputDirectoryTextBox.Text))
|
||||
OutputDirectoryTextBox.Text = Path.Combine(_options.DefaultOutputPath, drive?.VolumeLabel ?? string.Empty);
|
||||
|
||||
// Get the extension for the file for the next two statements
|
||||
string extension = null;
|
||||
switch (_env.InternalProgram)
|
||||
{
|
||||
case InternalProgram.Aaru:
|
||||
extension = Aaru.Converters.Extension(mediaType);
|
||||
break;
|
||||
case InternalProgram.DiscImageCreator:
|
||||
extension = DiscImageCreator.Converters.Extension(mediaType);
|
||||
break;
|
||||
}
|
||||
|
||||
// Set the output filename, if we changed drives or it's not already
|
||||
if (driveChanged || string.IsNullOrEmpty(OutputFilenameTextBox.Text))
|
||||
OutputFilenameTextBox.Text = (drive?.VolumeLabel ?? systemType.LongName()) + (extension ?? ".bin");
|
||||
|
||||
// If the extension for the file changed, update that automatically
|
||||
else if (Path.GetExtension(OutputFilenameTextBox.Text) != extension)
|
||||
OutputFilenameTextBox.Text = Path.GetFileNameWithoutExtension(OutputFilenameTextBox.Text) + (extension ?? ".bin");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scan and show copy protection for the current disc
|
||||
/// </summary>
|
||||
private async void ScanAndShowProtection()
|
||||
{
|
||||
if (_env == null)
|
||||
_env = DetermineEnvironment();
|
||||
|
||||
if (_env.Drive.Letter != default(char))
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Scanning for copy protection in {0}", _env.Drive.Letter);
|
||||
|
||||
var tempContent = StatusLabel.Content;
|
||||
StatusLabel.Content = "Scanning for copy protection... this might take a while!";
|
||||
StartStopButton.IsEnabled = false;
|
||||
DiskScanButton.IsEnabled = false;
|
||||
CopyProtectScanButton.IsEnabled = false;
|
||||
|
||||
string protections = await Validators.RunProtectionScanOnPath(_env.Drive.Letter + ":\\");
|
||||
|
||||
// If SmartE is detected on the current disc, remove `/sf` from the flags for DIC only
|
||||
if (_env.InternalProgram == InternalProgram.DiscImageCreator && protections.Contains("SmartE"))
|
||||
{
|
||||
((DiscImageCreator.Parameters)_env.Parameters)[DiscImageCreator.Flag.ScanFileProtect] = false;
|
||||
ViewModels.LoggerViewModel.VerboseLogLn($"SmartE detected, removing {DiscImageCreator.FlagStrings.ScanFileProtect} from parameters");
|
||||
}
|
||||
|
||||
if (!ViewModels.LoggerViewModel.WindowVisible)
|
||||
MessageBox.Show(protections, "Detected Protection", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
ViewModels.LoggerViewModel.VerboseLog("Detected the following protections in {0}:\r\n\r\n{1}", _env.Drive.Letter, protections);
|
||||
|
||||
StatusLabel.Content = tempContent;
|
||||
StartStopButton.IsEnabled = true;
|
||||
DiskScanButton.IsEnabled = true;
|
||||
CopyProtectScanButton.IsEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the drive speed based on reported maximum and user-defined option
|
||||
/// </summary>
|
||||
private void SetSupportedDriveSpeed()
|
||||
{
|
||||
// Set the drive speed list that's appropriate
|
||||
var values = Constants.GetSpeedsForMediaType(_currentMediaType);
|
||||
DriveSpeedComboBox.ItemsSource = values;
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Supported media speeds: {0}", string.Join(",", values));
|
||||
|
||||
// Find the minimum set to compare against
|
||||
int preferred = 100;
|
||||
switch (_currentMediaType)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
case MediaType.GDROM:
|
||||
preferred = _options.PreferredDumpSpeedCD;
|
||||
break;
|
||||
case MediaType.DVD:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
preferred = _options.PreferredDumpSpeedDVD;
|
||||
break;
|
||||
case MediaType.BluRay:
|
||||
preferred = _options.PreferredDumpSpeedBD;
|
||||
break;
|
||||
default:
|
||||
preferred = _options.PreferredDumpSpeedCD;
|
||||
break;
|
||||
}
|
||||
|
||||
// Set the selected speed
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Setting drive speed to: {0}", preferred);
|
||||
DriveSpeedComboBox.SelectedValue = preferred;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cache the current disc type to internal variable
|
||||
/// </summary>
|
||||
private void CacheCurrentDiscType()
|
||||
{
|
||||
// Get the drive letter from the selected item
|
||||
var drive = DriveLetterComboBox.SelectedItem as Drive;
|
||||
if (drive == null)
|
||||
return;
|
||||
|
||||
// Get the current media type
|
||||
if (!_options.SkipMediaTypeDetection)
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLog("Trying to detect media type for drive {0}.. ", drive.Letter);
|
||||
_currentMediaType = Validators.GetMediaType(drive);
|
||||
ViewModels.LoggerViewModel.VerboseLogLn(_currentMediaType == null ? "unable to detect." : ("detected " + _currentMediaType.LongName() + "."));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the current disc type in the combo box
|
||||
/// </summary>
|
||||
private void SetCurrentDiscType()
|
||||
{
|
||||
// If we have an invalid current type, we don't care and return
|
||||
if (_currentMediaType == null || _currentMediaType == MediaType.NONE)
|
||||
return;
|
||||
|
||||
// Now set the selected item, if possible
|
||||
int index = _mediaTypes.FindIndex(kvp => kvp.Value == _currentMediaType);
|
||||
if (index != -1)
|
||||
MediaTypeComboBox.SelectedIndex = index;
|
||||
else
|
||||
StatusLabel.Content = $"Disc of type '{Converters.LongName(_currentMediaType)}' found, but the current system does not support it!";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process the current custom parameters back into UI values
|
||||
/// </summary>
|
||||
private void ProcessCustomParameters()
|
||||
{
|
||||
_env.SetParameters(ParametersTextBox.Text);
|
||||
if (_env.Parameters == null)
|
||||
return;
|
||||
|
||||
int driveIndex = _drives.Select(d => d.Letter).ToList().IndexOf(_env.Parameters.InputPath()[0]);
|
||||
if (driveIndex > -1)
|
||||
DriveLetterComboBox.SelectedIndex = driveIndex;
|
||||
|
||||
int driveSpeed = _env.Parameters.GetSpeed() ?? -1;
|
||||
if (driveSpeed > 0)
|
||||
DriveSpeedComboBox.SelectedValue = driveSpeed;
|
||||
else
|
||||
_env.Parameters.SetSpeed((int?)DriveSpeedComboBox.SelectedValue);
|
||||
|
||||
string trimmedPath = _env.Parameters.OutputPath()?.Trim('"') ?? string.Empty;
|
||||
string outputDirectory = Path.GetDirectoryName(trimmedPath);
|
||||
string outputFilename = Path.GetFileName(trimmedPath);
|
||||
if (!string.IsNullOrWhiteSpace(outputDirectory))
|
||||
OutputDirectoryTextBox.Text = outputDirectory;
|
||||
else
|
||||
outputDirectory = OutputDirectoryTextBox.Text;
|
||||
if (!string.IsNullOrWhiteSpace(outputFilename))
|
||||
OutputFilenameTextBox.Text = outputFilename;
|
||||
else
|
||||
outputFilename = OutputFilenameTextBox.Text;
|
||||
|
||||
MediaType? mediaType = _env.Parameters.GetMediaType();
|
||||
int mediaTypeIndex = _mediaTypes.IndexOf(mediaType);
|
||||
if (mediaTypeIndex > -1)
|
||||
MediaTypeComboBox.SelectedIndex = mediaTypeIndex;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Get pixel coordinates based on DPI scaling
|
||||
/// </summary>
|
||||
/// <param name="bounds">Rectangle representing the bounds to transform</param>
|
||||
/// <returns>Rectangle representing the scaled bounds</returns>
|
||||
private Rectangle GetScaledCoordinates(Rectangle bounds)
|
||||
{
|
||||
using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
|
||||
{
|
||||
return new Rectangle(
|
||||
TransformCoordinate(bounds.Left, g.DpiX),
|
||||
TransformCoordinate(bounds.Top, g.DpiY),
|
||||
TransformCoordinate(bounds.Width, g.DpiX),
|
||||
TransformCoordinate(bounds.Height, g.DpiY));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transform an individual coordinate using DPI scaling
|
||||
/// </summary>
|
||||
/// <param name="coord">Current integer coordinate</param>
|
||||
/// <param name="dpi">DPI scaling factor</param>
|
||||
/// <returns>Scaled integer coordinate</returns>
|
||||
private int TransformCoordinate(int coord, float dpi)
|
||||
{
|
||||
return (int)(coord / ((double)dpi / 96));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
<Window x:Class="DICUI.Windows.OptionsWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:DICUI"
|
||||
mc:Ignorable="d"
|
||||
Title="Options" Width="515.132" Height="605">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="150"/>
|
||||
<RowDefinition Height="150"/>
|
||||
<RowDefinition Height="150"/>
|
||||
<RowDefinition Height="80"/>
|
||||
<RowDefinition Height="40"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<GroupBox Grid.Column="0" Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Paths" />
|
||||
|
||||
<Grid Margin="10,15,10,10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="2.0*" />
|
||||
<ColumnDefinition Width="0.2*" />
|
||||
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Aaru Path" />
|
||||
<TextBox x:Name="AaruPathTextBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
<Button x:Name="AaruPathButton" Grid.Row="0" Grid.Column="2" Height="22" Width="22" Content="..." Click="BrowseForPathClick" />
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="DiscImageCreator Path" />
|
||||
<TextBox x:Name="CreatorPathTextBox" Grid.Row="1" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
<Button x:Name="CreatorPathButton" Grid.Row="1" Grid.Column="2" Height="22" Width="22" Content="..." Click="BrowseForPathClick" />
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="subdump Path" />
|
||||
<TextBox x:Name="SubDumpPathTextBox" Grid.Row="2" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
<Button x:Name="SubDumpPathButton" Grid.Row="2" Grid.Column="2" Height="22" Width="22" Content="..." Click="BrowseForPathClick"/>
|
||||
|
||||
<Label Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Default Output Path" />
|
||||
<TextBox x:Name="DefaultOutputPathTextBox" Grid.Row="3" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
<Button x:Name="DefaultOutputPathButton" Grid.Row="3" Grid.Column="2" Height="22" Width="22" Content="..." Click="BrowseForPathClick" />
|
||||
</Grid>
|
||||
|
||||
<GroupBox Grid.Row="1" Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Preferred Dump Speed">
|
||||
<Grid Height="100">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="80"/>
|
||||
<ColumnDefinition Width="2.0*"/>
|
||||
<ColumnDefinition Width="40"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" Content="CD-ROM" />
|
||||
<Slider x:Name="DumpSpeedCDSlider" Grid.Row="0" Grid.Column="1" Minimum="1" Maximum="72" IsSnapToTickEnabled="True" TickPlacement="BottomRight" Ticks="{Binding Source={x:Static local:Constants.SpeedsForCDAsCollection}}" />
|
||||
<TextBox x:Name="DumpSpeedCDTextBox" Grid.Row="0" Grid.Column="2" Width="22" Height="22" TextAlignment="Center" IsReadOnly="True" IsReadOnlyCaretVisible="False" VerticalAlignment="Center" Text="{Binding ElementName=DumpSpeedCDSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}" Background="LightGray" Foreground="Gray"/>
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="DVD-ROM" />
|
||||
<Slider x:Name="DumpSpeedDVDSlider" Grid.Row="1" Grid.Column="1" Minimum="1" Maximum="24" IsSnapToTickEnabled="True" TickPlacement="BottomRight" Ticks="{Binding Source={x:Static local:Constants.SpeedsForDVDAsCollection}}" />
|
||||
<TextBox x:Name="DumpSpeedDVDTextBox" Grid.Row="1" Grid.Column="2" Width="22" Height="22" TextAlignment="Center" IsReadOnly="True" IsReadOnlyCaretVisible="False" VerticalAlignment="Center" Text="{Binding ElementName=DumpSpeedDVDSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}" Background="LightGray" Foreground="Gray"/>
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" Content="BD-ROM" />
|
||||
<Slider x:Name="DumpSpeedBDSlider" Grid.Row="2" Grid.Column="1" Minimum="1" Maximum="16" IsSnapToTickEnabled="True" TickPlacement="BottomRight" Ticks="{Binding Source={x:Static local:Constants.SpeedsForBDAsCollection}}" />
|
||||
<TextBox x:Name="DumpSpeedBDTextBox" Grid.Row="2" Grid.Column="2" Width="22" Height="22" TextAlignment="Center" IsReadOnly="True" IsReadOnlyCaretVisible="False" VerticalAlignment="Center" Text="{Binding ElementName=DumpSpeedBDSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}" Background="LightGray" Foreground="Gray"/>
|
||||
|
||||
</Grid>
|
||||
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="2" Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Options" Padding="10">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<CheckBox Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Content="Quiet Mode"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
|
||||
IsChecked="{Binding Path=QuietMode}"
|
||||
ToolTip="Disable DiscImageCreator sounds" Margin="0,4"
|
||||
/>
|
||||
|
||||
<CheckBox Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" Content="Paranoid Mode"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
|
||||
IsChecked="{Binding Path=ParanoidMode}"
|
||||
ToolTip="Enable pedantic and super-safe flags" Margin="0,4"
|
||||
/>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="2" Content="Reread Tries:" VerticalAlignment="Center" HorizontalAlignment="Right"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="3" VerticalAlignment="Center"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
|
||||
Text="{Binding Path=RereadAmountForC2}"
|
||||
ToolTip="Specifies how many rereads are attempted on C2 error"
|
||||
/>
|
||||
|
||||
<CheckBox Grid.Column="0" Grid.Row="1" VerticalAlignment="Center" Content="Protection Scan"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
|
||||
IsChecked="{Binding Path=ScanForProtection}"
|
||||
ToolTip="Enable automatic checking for copy protection on dumped media" Margin="0,4,0,0"
|
||||
/>
|
||||
|
||||
<CheckBox Grid.Column="1" Grid.Row="1" VerticalAlignment="Center" Content="Skip Type Detect"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
|
||||
IsChecked="{Binding Path=SkipMediaTypeDetection}"
|
||||
ToolTip="Disable trying to guess media type inserted (may improve performance at startup)" Margin="0,4"
|
||||
/>
|
||||
|
||||
<CheckBox Grid.Row="1" Grid.Column="2" VerticalAlignment="Center" Content="Add Placeholders"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
|
||||
IsChecked="{Binding Path=AddPlaceholders}"
|
||||
ToolTip="Enable adding placeholder text in the submissioninfo output for required and optional fields" Margin="0,4"
|
||||
/>
|
||||
|
||||
<CheckBox Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Content="Show Disc Info"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
|
||||
IsChecked="{Binding Path=PromptForDiscInformation}"
|
||||
ToolTip="Enable showing the disc information output after dumping" Margin="0,4"
|
||||
/>
|
||||
|
||||
<CheckBox Grid.Row="2" Grid.Column="1" VerticalAlignment="Center" Content="No Fixed Drives"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
|
||||
IsChecked="{Binding Path=IgnoreFixedDrives}"
|
||||
ToolTip="Ignore hard drives and other fixed drives" Margin="0,4"
|
||||
/>
|
||||
|
||||
<CheckBox Grid.Row="2" Grid.Column="2" VerticalAlignment="Center" Content="Reset After Dump"
|
||||
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
|
||||
IsChecked="{Binding Path=ResetDriveAfterDump}"
|
||||
ToolTip="Reset disc drives after dumping; useful for some older machines" Margin="0,4"
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="3" Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Redump Login" Padding="10">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1.2*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Username" />
|
||||
<TextBox x:Name="RedumpUsernameTextBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Password" />
|
||||
<PasswordBox x:Name="RedumpPasswordBox" Grid.Row="0" Grid.Column="3" Height="22" HorizontalAlignment="Stretch" PasswordChar="*" />
|
||||
|
||||
<Button x:Name="RedumpLoginTestButton" Grid.Row="0" Grid.Column="5" Height="22" Width="80" Content="Test Login" Click="OnRedumpTestClick" />
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<Grid Height="22" Grid.Row="4" Grid.Column="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button x:Name="AcceptButton" Grid.Row="0" Grid.Column="1" Height="22" Width="80" Content="Accept" Click="OnAcceptClick" />
|
||||
<Button x:Name="CancelButton" Grid.Row="0" Grid.Column="2" Height="22" Width="80" Content="Cancel" Click="OnCancelClick" />
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,151 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using DICUI.Web;
|
||||
using Button = System.Windows.Controls.Button;
|
||||
using TextBox = System.Windows.Controls.TextBox;
|
||||
|
||||
namespace DICUI.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for OptionsWindow.xaml
|
||||
/// </summary>
|
||||
public partial class OptionsWindow : Window
|
||||
{
|
||||
private readonly MainWindow _mainWindow;
|
||||
private readonly Options _options;
|
||||
|
||||
public OptionsWindow(MainWindow mainWindow, Options options)
|
||||
{
|
||||
InitializeComponent();
|
||||
_mainWindow = mainWindow;
|
||||
_options = options;
|
||||
}
|
||||
|
||||
private OpenFileDialog CreateOpenFileDialog()
|
||||
{
|
||||
OpenFileDialog dialog = new OpenFileDialog();
|
||||
|
||||
dialog.InitialDirectory = AppDomain.CurrentDomain.BaseDirectory;
|
||||
dialog.Filter = "Executables (*.exe)|*.exe";
|
||||
dialog.FilterIndex = 0;
|
||||
dialog.RestoreDirectory = true;
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private FolderBrowserDialog CreateFolderBrowserDialog()
|
||||
{
|
||||
FolderBrowserDialog dialog = new FolderBrowserDialog();
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private string[] PathSettings()
|
||||
{
|
||||
string[] pathSettings = { "AaruPath", "CreatorPath", "DefaultOutputPath", "SubDumpPath" };
|
||||
return pathSettings;
|
||||
}
|
||||
|
||||
private TextBox TextBoxForPathSetting(string name)
|
||||
{
|
||||
return FindName(name + "TextBox") as TextBox;
|
||||
}
|
||||
|
||||
private void BrowseForPathClick(object sender, EventArgs e)
|
||||
{
|
||||
Button button = sender as Button;
|
||||
// strips button prefix to obtain the setting name
|
||||
string pathSettingName = button.Name.Substring(0, button.Name.IndexOf("Button"));
|
||||
|
||||
// TODO: hack for now, then we'll see
|
||||
bool shouldBrowseForPath = pathSettingName == "DefaultOutputPath";
|
||||
|
||||
CommonDialog dialog = shouldBrowseForPath ? (CommonDialog)CreateFolderBrowserDialog() : CreateOpenFileDialog();
|
||||
using (dialog)
|
||||
{
|
||||
DialogResult result = dialog.ShowDialog();
|
||||
|
||||
if (result == System.Windows.Forms.DialogResult.OK)
|
||||
{
|
||||
string path;
|
||||
bool exists;
|
||||
|
||||
if (shouldBrowseForPath)
|
||||
{
|
||||
path = (dialog as FolderBrowserDialog).SelectedPath;
|
||||
exists = Directory.Exists(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
path = (dialog as OpenFileDialog).FileName;
|
||||
exists = File.Exists(path);
|
||||
}
|
||||
|
||||
if (exists)
|
||||
TextBoxForPathSetting(pathSettingName).Text = path;
|
||||
else
|
||||
{
|
||||
System.Windows.MessageBox.Show(
|
||||
"Specified path doesn't exists!",
|
||||
"Error",
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Error
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
Array.ForEach(PathSettings(), setting => TextBoxForPathSetting(setting).Text = _options.Get(setting));
|
||||
|
||||
DumpSpeedCDSlider.Value = _options.PreferredDumpSpeedCD;
|
||||
DumpSpeedDVDSlider.Value = _options.PreferredDumpSpeedDVD;
|
||||
DumpSpeedBDSlider.Value = _options.PreferredDumpSpeedBD;
|
||||
|
||||
RedumpUsernameTextBox.Text = _options.Username;
|
||||
RedumpPasswordBox.Password = _options.Password;
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
private void OnAcceptClick(object sender, EventArgs e)
|
||||
{
|
||||
Array.ForEach(PathSettings(), setting => _options.Set(setting, TextBoxForPathSetting(setting).Text));
|
||||
|
||||
_options.PreferredDumpSpeedCD = Convert.ToInt32(DumpSpeedCDSlider.Value);
|
||||
_options.PreferredDumpSpeedDVD = Convert.ToInt32(DumpSpeedDVDSlider.Value);
|
||||
_options.PreferredDumpSpeedBD = Convert.ToInt32(DumpSpeedBDSlider.Value);
|
||||
|
||||
_options.Username = RedumpUsernameTextBox.Text;
|
||||
_options.Password = RedumpPasswordBox.Password;
|
||||
|
||||
_options.Save();
|
||||
Hide();
|
||||
|
||||
_mainWindow.OnOptionsUpdated();
|
||||
}
|
||||
|
||||
private void OnCancelClick(object sender, EventArgs e)
|
||||
{
|
||||
// just hide the window and don't care
|
||||
Hide();
|
||||
}
|
||||
|
||||
private void OnRedumpTestClick(object sender, EventArgs e)
|
||||
{
|
||||
using (CookieAwareWebClient wc = new CookieAwareWebClient())
|
||||
{
|
||||
RedumpAccess access = new RedumpAccess();
|
||||
if (access.RedumpLogin(wc, RedumpUsernameTextBox.Text, RedumpPasswordBox.Password))
|
||||
System.Windows.MessageBox.Show("Redump login credentials accepted!", "Success", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
else
|
||||
System.Windows.MessageBox.Show("Redump login credentials denied!", "Failure", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
2
LICENSE
2
LICENSE
@@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
DICUI Copyright (C) 2018 ReignStumble
|
||||
MPF Copyright (C) 2018 ReignStumble
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
51
MPF.Check/MPF.Check.csproj
Normal file
51
MPF.Check/MPF.Check.csproj
Normal file
@@ -0,0 +1,51 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net48;netcoreapp3.1</TargetFrameworks>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<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>
|
||||
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
|
||||
<Version>2.1</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>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="1.7.0" GeneratePathProperty="true">
|
||||
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="$(PkgBurnOutSharp)\content\**" PackagePath="contentFiles\any\any;content" CopyToOutputDirectory="Always" PackageCopyToOutput="true" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj">
|
||||
<Project>{51ab0928-13f9-44bf-a407-b6957a43a056}</Project>
|
||||
<Name>MPF.Library</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
275
MPF.Check/Program.cs
Normal file
275
MPF.Check/Program.cs
Normal file
@@ -0,0 +1,275 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp;
|
||||
using MPF.Data;
|
||||
using MPF.Redump;
|
||||
using MPF.Utilities;
|
||||
|
||||
namespace MPF.Check
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// Help options
|
||||
if (args.Length == 0 || args[0] == "-h" || args[0] == "-?")
|
||||
{
|
||||
DisplayHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
// List options
|
||||
if (args[0] == "-lm" || args[0] == "--listmedia")
|
||||
{
|
||||
ListMediaTypes();
|
||||
Console.ReadLine();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// Make new Progress objects
|
||||
var resultProgress = new Progress<Result>();
|
||||
resultProgress.ProgressChanged += ProgressUpdated;
|
||||
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!");
|
||||
}
|
||||
}
|
||||
|
||||
// Loop through all the rest of the args
|
||||
for (int i = startIndex; i < args.Length; i++)
|
||||
{
|
||||
// Check for a file
|
||||
if (!File.Exists(args[i].Trim('"')))
|
||||
{
|
||||
DisplayHelp($"{args[i].Trim('"')} does not exist");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the full file path
|
||||
string filepath = Path.GetFullPath(args[i].Trim('"'));
|
||||
|
||||
// Now populate an environment
|
||||
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));
|
||||
|
||||
var env = new DumpEnvironment(options, "", filepath, drive, knownSystem, mediaType, null);
|
||||
|
||||
// Finally, attempt to do the output dance
|
||||
var result = env.VerifyAndSaveDumpOutput(resultProgress, protectionProgress).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
Console.WriteLine(result.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display help for MPF.Check
|
||||
/// </summary>
|
||||
/// <param name="error">Error string to prefix the help text with</param>
|
||||
private static void DisplayHelp(string error = null)
|
||||
{
|
||||
if (error != null)
|
||||
Console.WriteLine(error);
|
||||
|
||||
Console.WriteLine("Usage:");
|
||||
Console.WriteLine("MPF.Check.exe <mediatype> <system> [options] </path/to/output.bin> ...");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Standalone Options:");
|
||||
Console.WriteLine("-h, -? Show this help text");
|
||||
Console.WriteLine("-lm, --listmedia List supported media types");
|
||||
Console.WriteLine("-ls, --listsystems List supported system types");
|
||||
Console.WriteLine("-lp, --listprograms List supported dumping program outputs");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Check Options:");
|
||||
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");
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List all media types with their short usable names
|
||||
/// </summary>
|
||||
private static void ListMediaTypes()
|
||||
{
|
||||
Console.WriteLine("Supported Media Types:");
|
||||
foreach (var val in Enum.GetValues(typeof(MediaType)))
|
||||
{
|
||||
if (((MediaType)val) == MediaType.NONE)
|
||||
continue;
|
||||
|
||||
Console.WriteLine($"{((MediaType?)val).ShortName()} - {((MediaType?)val).LongName()}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List all programs with their short usable names
|
||||
/// </summary>
|
||||
private static void ListPrograms()
|
||||
{
|
||||
Console.WriteLine("Supported Programs:");
|
||||
foreach (var val in Enum.GetValues(typeof(InternalProgram)))
|
||||
{
|
||||
if (((InternalProgram)val) == InternalProgram.NONE)
|
||||
continue;
|
||||
|
||||
Console.WriteLine($"{((InternalProgram?)val).LongName()}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List all known systems with their short usable names
|
||||
/// </summary>
|
||||
private static void ListKnownSystems()
|
||||
{
|
||||
Console.WriteLine("Supported Known Systems:");
|
||||
foreach (var val in Enum.GetValues(typeof(KnownSystem)))
|
||||
{
|
||||
if (((KnownSystem)val) == KnownSystem.NONE)
|
||||
continue;
|
||||
|
||||
Console.WriteLine($"{((KnownSystem?)val).ShortName()} - {((KnownSystem?)val).LongName()}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple process counter to write to console
|
||||
/// </summary>
|
||||
private static void ProgressUpdated(object sender, Result value)
|
||||
{
|
||||
Console.WriteLine(value.Message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple process counter to write to console
|
||||
/// </summary>
|
||||
private static void ProgressUpdated(object sender, ProtectionProgress value)
|
||||
{
|
||||
Console.WriteLine($"{value.Percentage * 100:N2}%: {value.Filename} - {value.Protection}");
|
||||
}
|
||||
}
|
||||
}
|
||||
7
MPF.Check/launchSettings.json
Normal file
7
MPF.Check/launchSettings.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"profiles": {
|
||||
"MPF.Check": {
|
||||
"commandName": "Project"
|
||||
}
|
||||
}
|
||||
}
|
||||
1
MPF.Library/Aaru/CICMMetadata
Submodule
1
MPF.Library/Aaru/CICMMetadata
Submodule
Submodule MPF.Library/Aaru/CICMMetadata added at 7944bca8e6
477
MPF.Library/Aaru/Constants.cs
Normal file
477
MPF.Library/Aaru/Constants.cs
Normal file
@@ -0,0 +1,477 @@
|
||||
namespace MPF.Aaru
|
||||
{
|
||||
/// <summary>
|
||||
/// Top-level commands for Aaru
|
||||
/// </summary>
|
||||
public static class CommandStrings
|
||||
{
|
||||
public const string NONE = "";
|
||||
|
||||
// Database Family
|
||||
public const string DatabasePrefixShort = "db";
|
||||
public const string DatabasePrefixLong = "database";
|
||||
public const string DatabaseStats = "stats";
|
||||
public const string DatabaseUpdate = "update";
|
||||
|
||||
// Device Family
|
||||
public const string DevicePrefixShort = "dev";
|
||||
public const string DevicePrefixLong = "device";
|
||||
public const string DeviceInfo = "info";
|
||||
public const string DeviceList = "list";
|
||||
public const string DeviceReport = "report";
|
||||
|
||||
// Filesystem Family
|
||||
public const string FilesystemPrefixShort = "fi";
|
||||
public const string FilesystemPrefixShortAlt = "fs";
|
||||
public const string FilesystemPrefixLong = "filesystem";
|
||||
public const string FilesystemExtract = "extract";
|
||||
public const string FilesystemListShort = "ls";
|
||||
public const string FilesystemListLong = "list";
|
||||
public const string FilesystemOptions = "options";
|
||||
|
||||
// Image Family
|
||||
public const string ImagePrefixShort = "i";
|
||||
public const string ImagePrefixLong = "image";
|
||||
public const string ImageAnalyze = "analyze";
|
||||
public const string ImageChecksumShort = "chk";
|
||||
public const string ImageChecksumLong = "checksum";
|
||||
public const string ImageCompareShort = "cmp";
|
||||
public const string ImageCompareLong = "compare";
|
||||
public const string ImageConvert = "convert";
|
||||
public const string ImageCreateSidecar = "create-sidecar";
|
||||
public const string ImageDecode = "decode";
|
||||
public const string ImageEntropy = "entropy";
|
||||
public const string ImageInfo = "info";
|
||||
public const string ImageOptions = "options";
|
||||
public const string ImagePrint = "print";
|
||||
public const string ImageVerify = "verify";
|
||||
|
||||
// Media Family
|
||||
public const string MediaPrefixShort = "m";
|
||||
public const string MediaPrefixLong = "media";
|
||||
public const string MediaDump = "dump";
|
||||
public const string MediaInfo = "info";
|
||||
public const string MediaScan = "scan";
|
||||
|
||||
// Standalone Commands
|
||||
public const string Configure = "configure";
|
||||
public const string Formats = "formats";
|
||||
public const string ListEncodings = "list-encodings";
|
||||
public const string ListNamespaces = "list-namespaces";
|
||||
public const string Remote = "remote";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supported encodings for Aaru
|
||||
/// </summary>
|
||||
/// TODO: Use to verify encoding settings
|
||||
public static class EncodingStrings
|
||||
{
|
||||
public const string ArabicMac = "x-mac-arabic";
|
||||
public const string AtariASCII = "atascii";
|
||||
public const string CentralEuropeanMac = "x-mac-ce";
|
||||
public const string CommodorePETSCII = "petscii";
|
||||
public const string CroatianMac = "x-mac-croatian";
|
||||
public const string CyrillicMac = "x-mac-cryillic";
|
||||
public const string FarsiMac = "x-mac-farsi";
|
||||
public const string GreekMac = "x-mac-greek";
|
||||
public const string HebrewMac = "x-mac-hebrew";
|
||||
public const string RomanianMac = "x-mac-romanian";
|
||||
public const string SinclairZXSpectrum = "spectrum";
|
||||
public const string SinclairZX80 = "zx80";
|
||||
public const string SinclairZX81 = "zx81";
|
||||
public const string TurkishMac = "x-mac-turkish";
|
||||
public const string UkrainianMac = "x-mac-ukrainian";
|
||||
public const string Unicode = "utf-16";
|
||||
public const string UnicodeBigEndian = "utf-16BE";
|
||||
public const string UnicodeUTF32BigEndian = "utf-32BE";
|
||||
public const string UnicodeUTF32 = "utf-32";
|
||||
public const string UnicodeUTF7 = "utf-7";
|
||||
public const string UnicodeUTF8 = "utf-8";
|
||||
public const string USASCII = "us-ascii";
|
||||
public const string WesternEuropeanAppleII = "apple2";
|
||||
public const string WesternEuropeanAppleIIc = "apple2c";
|
||||
public const string WesternEuropeanAppleIIe = "apple2e";
|
||||
public const string WesternEuropeanAppleIIgs = "apple2gs";
|
||||
public const string WesternEuropeanAppleLisa = "lisa";
|
||||
public const string WesternEuropeanAtariST = "atarist";
|
||||
public const string WesternEuropeanGEM = "gem";
|
||||
public const string WesternEuropeanGEOS = "geos";
|
||||
public const string WesternEuropeanISO = "iso-8859-1";
|
||||
public const string WesternEuropeanMac = "macintosh";
|
||||
public const string WesternEuropeanRadix50 = "radix50";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dumping flags for Aaru
|
||||
/// </summary>
|
||||
public static class FlagStrings
|
||||
{
|
||||
// Boolean flags
|
||||
public const string Adler32Short = "-a";
|
||||
public const string Adler32Long = "--adler32";
|
||||
public const string ClearLong = "--clear";
|
||||
public const string ClearAllLong = "--clear-all";
|
||||
public const string CRC16Long = "--crc16";
|
||||
public const string CRC32Short = "-c";
|
||||
public const string CRC32Long = "--crc32";
|
||||
public const string CRC64Long = "--crc64";
|
||||
public const string DebugShort = "-d";
|
||||
public const string DebugLong = "--debug";
|
||||
public const string DiskTagsShort = "-f";
|
||||
public const string DiskTagsLong = "--disk-tags";
|
||||
public const string DuplicatedSectorsShort = "-p";
|
||||
public const string DuplicatedSectorsLong = "--duplicated-sectors";
|
||||
public const string EjectLong = "--eject";
|
||||
public const string ExtendedAttributesShort = "-x";
|
||||
public const string ExtendedAttributesLong = "--xattrs";
|
||||
public const string FilesystemsShort = "-f";
|
||||
public const string FilesystemsLong = "--filesystems";
|
||||
public const string FirstPregapLong = "--first-pregap";
|
||||
public const string FixOffsetLong = "--fix-offset";
|
||||
public const string FixSubchannelLong = "--fix-subchannel";
|
||||
public const string FixSubchannelCrcLong = "--fix-subchannel-crc";
|
||||
public const string FixSubchannelPositionLong = "--fix-subchannel-position";
|
||||
public const string Fletcher16Long = "--fletcher16";
|
||||
public const string Fletcher32Long = "--fletcher32";
|
||||
public const string ForceShort = "-f";
|
||||
public const string ForceLong = "--force";
|
||||
public const string GenerateSubchannelsLong = "--generate-subchannels";
|
||||
public const string HelpShort = "-h";
|
||||
public const string HelpShortAlt = "-?";
|
||||
public const string HelpLong = "--help";
|
||||
public const string LongFormatShort = "-l";
|
||||
public const string LongFormatLong = "--long-format";
|
||||
public const string LongSectorsShort = "-r";
|
||||
public const string LongSectorsLong = "--long-sectors";
|
||||
public const string MD5Short = "-m";
|
||||
public const string MD5Long = "--md5";
|
||||
public const string MetadataLong = "--metadata";
|
||||
public const string PartitionsShort = "-p";
|
||||
public const string PartitionsLong = "--partitions";
|
||||
public const string PersistentLong = "--persistent";
|
||||
public const string PrivateLong = "--private";
|
||||
public const string ResumeShort = "-r";
|
||||
public const string ResumeLong = "--resume";
|
||||
public const string RetrySubchannelLong = "--retry-subchannel";
|
||||
public const string SectorTagsShort = "-p";
|
||||
public const string SectorTagsLong = "--sector-tags";
|
||||
public const string SeparatedTracksShort = "-t";
|
||||
public const string SeparatedTracksLong = "--separated-tracks";
|
||||
public const string SHA1Short = "-s";
|
||||
public const string SHA1Long = "--sha1";
|
||||
public const string SHA256Long = "--sha256";
|
||||
public const string SHA384Long = "--sha384";
|
||||
public const string SHA512Long = "--sha512";
|
||||
public const string SkipCdiReadyHoleLong = "--skip-cdiready-hole";
|
||||
public const string SpamSumShort = "-f";
|
||||
public const string SpamSumLong = "--spamsum";
|
||||
public const string StopOnErrorShort = "-s";
|
||||
public const string StopOnErrorLong = "--stop-on-error";
|
||||
public const string TapeShort = "-t";
|
||||
public const string TapeLong = "--tape";
|
||||
public const string TrimLong = "--trim";
|
||||
public const string VerboseShort = "-v";
|
||||
public const string VerboseLong = "--verbose";
|
||||
public const string VerifyDiscShort = "-w";
|
||||
public const string VerifyDiscLong = "--verify-disc";
|
||||
public const string VerifySectorsShort = "-s";
|
||||
public const string VerifySectorsLong = "--verify-sectors";
|
||||
public const string VersionLong = "--version";
|
||||
public const string WholeDiscShort = "-w";
|
||||
public const string WholeDiscLong = "--whole-disc";
|
||||
|
||||
// Int8 flags
|
||||
public const string SpeedLong = "--speed";
|
||||
|
||||
// Int16 flags
|
||||
public const string RetryPassesShort = "-p";
|
||||
public const string RetryPassesLong = "--retry-passes";
|
||||
public const string WidthShort = "-w";
|
||||
public const string WidthLong = "--width";
|
||||
|
||||
// Int32 flags
|
||||
public const string BlockSizeShort = "-b";
|
||||
public const string BlockSizeLong = "--block-size";
|
||||
public const string CountShort = "-c";
|
||||
public const string CountLong = "--count";
|
||||
public const string MediaLastSequenceLong = "--media-lastsequence";
|
||||
public const string MediaSequenceLong = "--media-sequence";
|
||||
public const string SkipShort = "-k";
|
||||
public const string SkipLong = "--skip";
|
||||
|
||||
// Int64 flags
|
||||
public const string LengthShort = "-l"; // or "all"
|
||||
public const string LengthLong = "--length"; // or "all"
|
||||
public const string StartShort = "-s";
|
||||
public const string StartLong = "--start";
|
||||
|
||||
// String flags
|
||||
public const string CommentsLong = "--comments";
|
||||
public const string CreatorLong = "--creator";
|
||||
public const string DriveManufacturerLong = "--drive-manufacturer";
|
||||
public const string DriveModelLong = "--drive-model";
|
||||
public const string DriveRevisionLong = "--drive-revision";
|
||||
public const string DriveSerialLong = "--drive-serial";
|
||||
public const string EncodingShort = "-e";
|
||||
public const string EncodingLong = "--encoding";
|
||||
public const string FormatConvertShort = "-p";
|
||||
public const string FormatConvertLong = "--format";
|
||||
public const string FormatDumpShort = "-t";
|
||||
public const string FormatDumpLong = "--format";
|
||||
public const string ImgBurnLogShort = "-b";
|
||||
public const string ImgBurnLogLong = "--ibg-log";
|
||||
public const string MediaBarcodeLong = "--media-barcode";
|
||||
public const string MediaManufacturerLong = "--media-manufacturer";
|
||||
public const string MediaModelLong = "--media-model";
|
||||
public const string MediaPartNumberLong = "--media-partnumber";
|
||||
public const string MediaSerialLong = "--media-serial";
|
||||
public const string MediaTitleLong = "--media-title";
|
||||
public const string MHDDLogShort = "-m";
|
||||
public const string MHDDLogLong = "--mhdd-log";
|
||||
public const string NamespaceShort = "-n";
|
||||
public const string NamespaceLong = "--namespace";
|
||||
public const string OptionsShort = "-O";
|
||||
public const string OptionsLong = "--options";
|
||||
public const string OutputPrefixShort = "-w";
|
||||
public const string OutputPrefixLong = "--output-prefix";
|
||||
public const string ResumeFileShort = "-r";
|
||||
public const string ResumeFileLong = "--resume-file";
|
||||
public const string SubchannelLong = "--subchannel";
|
||||
public const string XMLSidecarShort = "-x";
|
||||
public const string XMLSidecarLong = "--cicm-xml";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supported formats for Aaru
|
||||
/// </summary>
|
||||
/// TODO: Use to verify format settings
|
||||
public static class FormatStrings
|
||||
{
|
||||
// Supported filters
|
||||
public const string AppleDouble = "AppleDouble";
|
||||
public const string AppleSingle = "AppleSingle";
|
||||
public const string BZip2 = "BZip2";
|
||||
public const string GZip = "GZip";
|
||||
public const string LZip = "LZip";
|
||||
public const string MacBinary = "MacBinary";
|
||||
public const string NoFilter = "No filter";
|
||||
public const string PCExchange = "PCExchange";
|
||||
public const string XZ = "XZ";
|
||||
|
||||
// Read-only media image formats
|
||||
public const string AppleDiskArchivalRetrievalTool = "Apple Disk Archival/Retrieval Tool";
|
||||
public const string AppleNewDiskImageFormat = "Apple New Disk Image Format";
|
||||
public const string AppleNIB = "Apple NIB";
|
||||
public const string BlindWrite4 = "BlindWrite 4";
|
||||
public const string BlindWrite5 = "BlindWrite 5";
|
||||
public const string CPCEMUDiskFileAndExtendedCPCDiskFile = "CPCEMU Disk-File and Extended CPC Disk-File";
|
||||
public const string D2FDiskImage = "d2f disk image";
|
||||
public const string D88DiskImage = "D88 Disk Image";
|
||||
public const string DIMDiskImage = "DIM Disk Image";
|
||||
public const string DiscFerret = "DiscFerret";
|
||||
public const string DiscJuggler = "DiscJuggler";
|
||||
public const string DreamcastGDIImage = "Dreamcast GDI image";
|
||||
public const string DunfieldsIMD = "Dunfield's IMD";
|
||||
public const string HDCopyDiskImage = "HD-Copy disk image";
|
||||
public const string KryoFluxSTREAM = "KryoFlux STREAM";
|
||||
public const string MAMECompressedHunksOfData = "MAME Compressed Hunks of Data";
|
||||
public const string MicrosoftVHDX = "Microsoft VHDX";
|
||||
public const string NeroBurningROMImage = "Nero Burning ROM image";
|
||||
public const string PartCloneDiskImage = "PartClone disk image";
|
||||
public const string PartimageDiskImage = "Partimage disk image";
|
||||
public const string SpectrumFloppyDiskImage = "Spectrum Floppy Disk Image";
|
||||
public const string SuperCardPro = "SuperCardPro";
|
||||
public const string SydexCopyQM = "Sydex CopyQM";
|
||||
public const string SydexTeleDisk = "Sydex TeleDisk";
|
||||
|
||||
// Read/write media image formats
|
||||
public const string AaruFormat = "Aaru Format";
|
||||
public const string ACTApricotDiskImage = "ACT Apricot Disk Image";
|
||||
public const string Alcohol120MediaDescriptorStructure = "Alcohol 120% Media Descriptor Structure";
|
||||
public const string Anex86DiskImage = "Anex86 Disk Image";
|
||||
public const string Apple2InterleavedDiskImage = "Apple ][Interleaved Disk Image";
|
||||
public const string Apple2IMG = "Apple 2IMG";
|
||||
public const string AppleDiskCopy42 = "Apple DiskCopy 4.2";
|
||||
public const string AppleUniversalDiskImageFormat = "Apple Universal Disk Image Format";
|
||||
public const string BasicLisaUtility = "Basic Lisa Utility";
|
||||
public const string CDRDAOTocfile = "CDRDAO tocfile";
|
||||
public const string CDRWinCuesheet = "CDRWin cuesheet";
|
||||
public const string CisCopyDiskImageDCFile = "CisCopy Disk Image(DC-File)";
|
||||
public const string CloneCD = "CloneCD";
|
||||
public const string CopyTape = "CopyTape";
|
||||
public const string DigitalResearchDiskCopy = "Digital Research DiskCopy";
|
||||
public const string IBMSaveDskF = "IBM SaveDskF";
|
||||
public const string MAXIDiskImage = "MAXI Disk image";
|
||||
public const string ParallelsDiskImage = "Parallels disk image";
|
||||
public const string QEMUCopyOnWriteDiskImage = "QEMU Copy-On-Write disk image";
|
||||
public const string QEMUCopyOnWriteDiskImageV2 = "QEMU Copy-On-Write disk image v2";
|
||||
public const string QEMUEnhancedDiskImage = "QEMU Enhanced Disk image";
|
||||
public const string RawDiskImage = "Raw Disk Image";
|
||||
public const string RayAracheliansDiskIMage = "Ray Arachelian's Disk IMage";
|
||||
public const string RSIDEHardDiskImage = "RS-IDE Hard Disk Image";
|
||||
public const string T98HardDiskImage = "T98 Hard Disk Image";
|
||||
public const string T98NextNHDr0DiskImage = "T98-Next NHD r0 Disk Image";
|
||||
public const string Virtual98DiskImage = "Virtual98 Disk Image";
|
||||
public const string VirtualBoxDiskImage = "VirtualBox Disk Image";
|
||||
public const string VirtualPC = "VirtualPC";
|
||||
public const string VMwareDiskImage = "VMware disk image";
|
||||
|
||||
// Supported filesystems for identification and information only
|
||||
public const string AcornAdvancedDiscFilingSystem = "Acorn Advanced Disc Filing System";
|
||||
public const string AlexanderOsipovDOSFileSystem = "Alexander Osipov DOS file system";
|
||||
public const string AmigaDOSFilesystem = "Amiga DOS filesystem";
|
||||
public const string AppleFileSystem = "Apple File System";
|
||||
public const string AppleHFSPlusFilesystem = "Apple HFS+ filesystem";
|
||||
public const string AppleHierarchicalFileSystem = "Apple Hierarchical File System";
|
||||
public const string AppleProDOSFilesystem = "Apple ProDOS filesystem";
|
||||
public const string AtheOSFilesystem = "AtheOS Filesystem";
|
||||
public const string BeFilesystem = "Be Filesystem";
|
||||
public const string BSDFastFileSystem = "BSD Fast File System(aka UNIX File System, UFS)";
|
||||
public const string BTreeFileSystem = "B-tree file system";
|
||||
public const string CommodoreFileSystem = "Commodore file system";
|
||||
public const string CramFilesystem = "Cram filesystem";
|
||||
public const string DumpEightPlugin = "dump(8) Plugin";
|
||||
public const string ECMA67 = "ECMA-67";
|
||||
public const string ExtentFileSystemPlugin = "Extent File System Plugin";
|
||||
public const string F2FSPlugin = "F2FS Plugin";
|
||||
public const string Files11OnDiskStructure = "Files-11 On-Disk Structure";
|
||||
public const string FossilFilesystemPlugin = "Fossil Filesystem Plugin";
|
||||
public const string HAMMERFilesystem = "HAMMER Filesystem";
|
||||
public const string HighPerformanceOpticalFileSystem = "High Performance Optical File System";
|
||||
public const string HPLogicalInterchangeFormatPlugin = "HP Logical Interchange Format Plugin";
|
||||
public const string JFSPlugin = "JFS Plugin";
|
||||
public const string LinuxExtendedFilesystem = "Linux extended Filesystem";
|
||||
public const string LinuxExtendedFilesystem234 = "Linux extended Filesystem 2, 3 and 4";
|
||||
public const string LocusFilesystemPlugin = "Locus Filesystem Plugin";
|
||||
public const string MicroDOSFileSystem = "MicroDOS file system";
|
||||
public const string MicrosoftExtendedFileAllocationTable = "Microsoft Extended File Allocation Table";
|
||||
public const string MinixFilesystem = "Minix Filesystem";
|
||||
public const string NewTechnologyFileSystem = "New Technology File System(NTFS)";
|
||||
public const string NILFS2Plugin = "NILFS2 Plugin";
|
||||
public const string NintendoOpticalFilesystems = "Nintendo optical filesystems";
|
||||
public const string OS2HighPerformanceFileSystem = "OS/2 High Performance File System";
|
||||
public const string OS9RandomBlockFilePlugin = "OS-9 Random Block File Plugin";
|
||||
public const string PCEngineCDPlugin = "PC Engine CD Plugin";
|
||||
public const string PCFXPlugin = "PC-FX Plugin";
|
||||
public const string ProfessionalFileSystem = "Professional File System";
|
||||
public const string QNX4Plugin = "QNX4 Plugin";
|
||||
public const string QNX6Plugin = "QNX6 Plugin";
|
||||
public const string ReiserFilesystemPlugin = "Reiser Filesystem Plugin";
|
||||
public const string Reiser4FilesystemPlugin = "Reiser4 Filesystem Plugin";
|
||||
public const string ResilientFileSystemPlugin = "Resilient File System plugin";
|
||||
public const string RT11FileSystem = "RT-11 file system";
|
||||
public const string SmartFileSystem = "SmartFileSystem";
|
||||
public const string SolarOSFilesystem = "Solar_OS filesystem";
|
||||
public const string SquashFilesystem = "Squash filesystem";
|
||||
public const string UNICOSFilesystemPlugin = "UNICOS Filesystem Plugin";
|
||||
public const string UniversalDiskFormat = "Universal Disk Format";
|
||||
public const string UNIXBootFilesystem = "UNIX Boot filesystem";
|
||||
public const string UNIXSystemVFilesystem = "UNIX System V filesystem";
|
||||
public const string VeritasFilesystem = "Veritas filesystem";
|
||||
public const string VMwareFilesystem = "VMware filesystem";
|
||||
public const string XFSFilesystemPlugin = "XFS Filesystem Plugin";
|
||||
public const string XiaFilesystem = "Xia filesystem";
|
||||
public const string ZFSFilesystemPlugin = "ZFS Filesystem Plugin";
|
||||
|
||||
// Supported filesystems that can read their contents
|
||||
public const string AppleDOSFileSystem = "Apple DOS File System";
|
||||
public const string AppleLisaFileSystem = "Apple Lisa File System";
|
||||
public const string AppleMacintoshFileSystem = "Apple Macintosh File System";
|
||||
public const string CPMFileSystem = "CP/M File System";
|
||||
public const string FATXFilesystemPlugin = "FATX Filesystem Plugin";
|
||||
public const string ISO9660Filesystem = "ISO9660 Filesystem";
|
||||
public const string MicrosoftFileAllocationTable = "Microsoft File Allocation Table";
|
||||
public const string OperaFilesystemPlugin = "Opera Filesystem Plugin";
|
||||
public const string UCSDPascalFilesystem = "U.C.S.D.Pascal filesystem";
|
||||
|
||||
// Supported partitioning schemes
|
||||
public const string AcornFileCorePartitions = "Acorn FileCore partitions";
|
||||
public const string ACTApricotPartitions = "ACT Apricot partitions";
|
||||
public const string AmigaRigidDiskBlock = "Amiga Rigid Disk Block";
|
||||
public const string ApplePartitionMap = "Apple Partition Map";
|
||||
public const string AtariPartitions = "Atari partitions";
|
||||
public const string BSDDisklabel = "BSD disklabel";
|
||||
public const string DECDisklabel = "DEC disklabel";
|
||||
public const string DragonFlyBSD64bitDisklabel = "DragonFly BSD 64-bit disklabel";
|
||||
public const string GUIDPartitionTable = "GUID Partition Table";
|
||||
public const string Human68kPartitions = "Human 68k partitions";
|
||||
public const string MasterBootRecord = "Master Boot Record";
|
||||
public const string NECPC9800PartitionTable = "NEC PC-9800 partition table";
|
||||
public const string NeXTDisklabel = "NeXT Disklabel";
|
||||
public const string Plan9PartitionTable = "Plan9 partition table";
|
||||
public const string RioKarmaPartitioning = "Rio Karma partitioning";
|
||||
public const string SGIDiskVolumeHeader = "SGI Disk Volume Header";
|
||||
public const string SunDisklabel = "Sun Disklabel";
|
||||
public const string UNIXHardwired = "UNIX hardwired";
|
||||
public const string UNIXVTOC = "UNIX VTOC";
|
||||
public const string XboxPartitioning = "Xbox partitioning";
|
||||
public const string XENIX = "XENIX";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supported namespaces for Aaru
|
||||
/// </summary>
|
||||
/// TODO: Use to verify namespace settings
|
||||
public static class NamespaceStrings
|
||||
{
|
||||
// Namespaces for Apple Lisa File System
|
||||
public const string LisaOfficeSystem = "office";
|
||||
public const string LisaPascalWorkshop = "workshop"; // Default
|
||||
|
||||
// Namespaces for ISO9660 Filesystem
|
||||
public const string JolietVolumeDescriptor = "joliet"; // Default
|
||||
public const string PrimaryVolumeDescriptor = "normal";
|
||||
public const string PrimaryVolumeDescriptorwithEncoding = "romeo";
|
||||
public const string RockRidge = "rrip";
|
||||
public const string PrimaryVolumeDescriptorVersionSuffix = "vms";
|
||||
|
||||
// Namespaces for Microsoft File Allocation Table
|
||||
public const string DOS83UpperCase = "dos";
|
||||
public const string LFNWhenAvailableWithFallback = "ecs"; // Default
|
||||
public const string LongFileNames = "lfn";
|
||||
public const string WindowsNT83MixedCase = "nt";
|
||||
public const string OS2Extended = "os2";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supported options for Aaru
|
||||
/// </summary>
|
||||
/// TODO: Use to verify option settings
|
||||
public static class OptionStrings
|
||||
{
|
||||
// Aaru format
|
||||
public const string AaruCompress = "compress"; // boolean, default true;
|
||||
public const string AaruDeduplicate = "deduplicate"; // boolean, default true
|
||||
public const string AaruDictionary = "dictionary"; // number, default 33554432
|
||||
public const string AaruMaxDDTSize = "max_ddt_size"; // number, default 256
|
||||
public const string AaruMD5 = "md5"; // boolean, default false
|
||||
public const string AaruSectorsPerBlock = "sectors_per_block"; // number, default 4096 [power of 2]
|
||||
public const string AaruSHA1 = "sha1"; // boolean, default false
|
||||
public const string AaruSHA256 = "sha256"; // boolean, default false
|
||||
public const string AaruSpamSum = "spamsum"; // boolean, default false
|
||||
|
||||
// ACT Apricot Disk Image
|
||||
public const string ACTApricotDiskImageCompress = "compress"; // boolean, default false
|
||||
|
||||
// Apple DiskCopy 4.2
|
||||
public const string AppleDiskCopyMacOSX = "macosx"; // boolean, default false
|
||||
|
||||
// CDRDAO tocfile
|
||||
public const string CDRDAOTocfileSeparate = "separate"; // boolean, default false
|
||||
|
||||
// CDRWin cuesheet
|
||||
public const string CDRWinCuesheetSeparate = "separate"; // boolean, default false
|
||||
|
||||
// ISO9660 Filesystem
|
||||
public const string ISO9660FSUseEvd = "use_evd"; // boolean, default false
|
||||
public const string ISO9660FSUsePathTable = "use_path_table"; // boolean, default false
|
||||
public const string ISO9660FSUseTransTbl = "use_trans_tbl"; // boolean, default false
|
||||
|
||||
// VMware disk image
|
||||
public const string VMwareDiskImageAdapterType = "adapter_type"; // string, default ide [ide, lsilogic, buslogic, legacyESX]
|
||||
public const string VMwareDiskImageHWVersion = "hwversion"; // number, default 4
|
||||
public const string VMwareDiskImageSparse = "sparse"; // boolean, default false
|
||||
public const string VMwareDiskImageSplit = "split"; // boolean, default false
|
||||
}
|
||||
}
|
||||
22
MPF.Library/Aaru/Converters.cs
Normal file
22
MPF.Library/Aaru/Converters.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using MPF.Data;
|
||||
|
||||
namespace MPF.Aaru
|
||||
{
|
||||
public static class Converters
|
||||
{
|
||||
#region Cross-enumeration conversions
|
||||
|
||||
/// <summary>
|
||||
/// Get the default extension for a given disc type
|
||||
/// </summary>
|
||||
/// <param name="type">MediaType value to check</param>
|
||||
/// <returns>Valid extension (with leading '.'), null on error</returns>
|
||||
public static string Extension(MediaType? type)
|
||||
{
|
||||
// Aaru has a single, unified output format by default
|
||||
return ".aaruf";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
3093
MPF.Library/Aaru/Parameters.cs
Normal file
3093
MPF.Library/Aaru/Parameters.cs
Normal file
File diff suppressed because it is too large
Load Diff
4
MPF.Library/AssemblyInfo.cs
Normal file
4
MPF.Library/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")]
|
||||
304
MPF.Library/CleanRIp/Parameters.cs
Normal file
304
MPF.Library/CleanRIp/Parameters.cs
Normal file
@@ -0,0 +1,304 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using MPF.Data;
|
||||
|
||||
namespace MPF.CleanRip
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic set of CleanRip parameters
|
||||
/// </summary>
|
||||
public class Parameters : BaseParameters
|
||||
{
|
||||
#region Metadata
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override InternalProgram InternalProgram => InternalProgram.CleanRip;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(string parameters) : base(parameters) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
: base(system, type, driveLetter, filename, driveSpeed, options)
|
||||
{
|
||||
}
|
||||
|
||||
#region BaseParameters Implementations
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override (bool, List<string>) CheckAllOutputFilesExist(string basePath, bool preCheck)
|
||||
{
|
||||
List<string> missingFiles = new List<string>();
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.DVD: // Only added here to help users; not strictly correct
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
if (!File.Exists($"{basePath}_logs.zip") || !preCheck)
|
||||
{
|
||||
if (!File.Exists($"{basePath}-dumpinfo.txt"))
|
||||
missingFiles.Add($"{basePath}-dumpinfo.txt");
|
||||
if (!File.Exists($"{basePath}.bca"))
|
||||
missingFiles.Add($"{basePath}.bca");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return (false, missingFiles);
|
||||
}
|
||||
|
||||
return (!missingFiles.Any(), missingFiles);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive, bool includeArtifacts)
|
||||
{
|
||||
info.TracksAndWriteOffsets.ClrMameProData = GetCleanripDatfile(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))
|
||||
{
|
||||
info.SizeAndChecksums.Size = size;
|
||||
info.SizeAndChecksums.CRC32 = crc32;
|
||||
info.SizeAndChecksums.MD5 = md5;
|
||||
info.SizeAndChecksums.SHA1 = sha1;
|
||||
|
||||
// Dual-layer discs have the same size and layerbreak
|
||||
if (size == 8511160320)
|
||||
info.SizeAndChecksums.Layerbreak = 2084960;
|
||||
}
|
||||
|
||||
// Extract info based generically on MediaType
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.DVD: // Only added here to help users; not strictly correct
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
if (File.Exists(basePath + ".bca"))
|
||||
info.Extras.BCA = GetBCA(basePath + ".bca");
|
||||
|
||||
if (GetGameCubeWiiInformation(basePath + "-dumpinfo.txt", out RedumpRegion? gcRegion, out string gcVersion))
|
||||
{
|
||||
info.CommonDiscInfo.Region = gcRegion ?? info.CommonDiscInfo.Region;
|
||||
info.VersionAndEditions.Version = gcVersion ?? info.VersionAndEditions.Version;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill in any artifacts that exist, Base64-encoded, if we need to
|
||||
if (includeArtifacts)
|
||||
{
|
||||
if (File.Exists(basePath + ".bca"))
|
||||
info.Artifacts["bca"] = GetBase64(GetFullFile(basePath + ".bca", binary: true));
|
||||
if (File.Exists(basePath + "-dumpinfo.txt"))
|
||||
info.Artifacts["dumpinfo"] = GetBase64(GetFullFile(basePath + "-dumpinfo.txt"));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<string> GetLogFilePaths(string basePath)
|
||||
{
|
||||
List<string> logFiles = new List<string>();
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.DVD: // Only added here to help users; not strictly correct
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
if (File.Exists($"{basePath}-dumpinfo.txt"))
|
||||
logFiles.Add($"{basePath}-dumpinfo.txt");
|
||||
if (File.Exists($"{basePath}.bca"))
|
||||
logFiles.Add($"{basePath}.bca");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return logFiles;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Information Extraction Methods
|
||||
|
||||
/// <summary>
|
||||
/// Get the hex contents of the BCA file
|
||||
/// </summary>
|
||||
/// <param name="bcaPath">Path to the BCA file associated with the dump</param>
|
||||
/// <returns>BCA data as a hex string if possible, null on error</returns>
|
||||
/// <remarks>https://stackoverflow.com/questions/9932096/add-separator-to-string-at-every-n-characters</remarks>
|
||||
private static string GetBCA(string bcaPath)
|
||||
{
|
||||
// If the file doesn't exist, we can't get the info
|
||||
if (!File.Exists(bcaPath))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
string hex = GetFullFile(bcaPath, true);
|
||||
return Regex.Replace(hex, ".{32}", "$0\n");
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error was right now
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a formatted datfile from the cleanrip output, if possible
|
||||
/// </summary>
|
||||
/// <param name="iso">Path to ISO file</param>
|
||||
/// <param name="dumpinfo">Path to discinfo file</param>
|
||||
/// <returns></returns>
|
||||
private static string GetCleanripDatfile(string iso, string dumpinfo)
|
||||
{
|
||||
// If the 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 $"<rom name=\"{Path.GetFileName(iso)}\" size=\"{size}\" crc=\"{crc}\" md5=\"{md5}\" sha1=\"{sha1}\" />";
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the exception is right now
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the extracted GC and Wii version
|
||||
/// </summary>
|
||||
/// <param name="dumpinfo">Path to discinfo file</param>
|
||||
/// <param name="region">Output region, if possible</param>
|
||||
/// <param name="version">Output internal version of the game</param>
|
||||
/// <returns></returns>
|
||||
private static bool GetGameCubeWiiInformation(string dumpinfo, out RedumpRegion? region, out string version)
|
||||
{
|
||||
region = null; version = null;
|
||||
|
||||
// If the file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(dumpinfo))
|
||||
return false;
|
||||
|
||||
using (StreamReader sr = File.OpenText(dumpinfo))
|
||||
{
|
||||
try
|
||||
{
|
||||
// Make sure this file is a dumpinfo
|
||||
if (!sr.ReadLine().Contains("--File Generated by CleanRip"))
|
||||
return false;
|
||||
|
||||
// Read all lines and gather dat information
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
string line = sr.ReadLine().Trim();
|
||||
if (line.StartsWith("Version"))
|
||||
{
|
||||
version = line.Substring(9);
|
||||
}
|
||||
else if (line.StartsWith("Filename"))
|
||||
{
|
||||
string serial = line.Substring(10);
|
||||
|
||||
// char gameType = serial[0];
|
||||
// string gameid = serial[1] + serial[2];
|
||||
// string version = serial[4] + serial[5]
|
||||
|
||||
switch (serial[3])
|
||||
{
|
||||
case 'A':
|
||||
region = RedumpRegion.World;
|
||||
break;
|
||||
case 'D':
|
||||
region = RedumpRegion.Germany;
|
||||
break;
|
||||
case 'E':
|
||||
region = RedumpRegion.USA;
|
||||
break;
|
||||
case 'F':
|
||||
region = RedumpRegion.France;
|
||||
break;
|
||||
case 'I':
|
||||
region = RedumpRegion.Italy;
|
||||
break;
|
||||
case 'J':
|
||||
region = RedumpRegion.Japan;
|
||||
break;
|
||||
case 'K':
|
||||
region = RedumpRegion.Korea;
|
||||
break;
|
||||
case 'L':
|
||||
region = RedumpRegion.Europe; // Japanese import to Europe
|
||||
break;
|
||||
case 'M':
|
||||
region = RedumpRegion.Europe; // American import to Europe
|
||||
break;
|
||||
case 'N':
|
||||
region = RedumpRegion.USA; // Japanese import to USA
|
||||
break;
|
||||
case 'P':
|
||||
region = RedumpRegion.Europe;
|
||||
break;
|
||||
case 'R':
|
||||
region = RedumpRegion.Russia;
|
||||
break;
|
||||
case 'S':
|
||||
region = RedumpRegion.Spain;
|
||||
break;
|
||||
case 'Q':
|
||||
region = RedumpRegion.Korea; // Korea with Japanese language
|
||||
break;
|
||||
case 'T':
|
||||
region = RedumpRegion.Korea; // Korea with English language
|
||||
break;
|
||||
case 'X':
|
||||
region = null; // Not a real region code
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the exception is right now
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
238
MPF.Library/CueSheets/CueFile.cs
Normal file
238
MPF.Library/CueSheets/CueFile.cs
Normal file
@@ -0,0 +1,238 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace MPF.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// The audio or data file’s filetype
|
||||
/// </summary>
|
||||
public enum CueFileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Intel binary file (least significant byte first). Use for data files.
|
||||
/// </summary>
|
||||
BINARY,
|
||||
|
||||
/// <summary>
|
||||
/// Motorola binary file (most significant byte first). Use for data files.
|
||||
/// </summary>
|
||||
MOTOROLA,
|
||||
|
||||
/// <summary>
|
||||
/// Audio AIFF file (44.1KHz 16-bit stereo)
|
||||
/// </summary>
|
||||
AIFF,
|
||||
|
||||
/// <summary>
|
||||
/// Audio WAVE file (44.1KHz 16-bit stereo)
|
||||
/// </summary>
|
||||
WAVE,
|
||||
|
||||
/// <summary>
|
||||
/// Audio MP3 file (44.1KHz 16-bit stereo)
|
||||
/// </summary>
|
||||
MP3,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a single FILE in a cuesheet
|
||||
/// </summary>
|
||||
public class CueFile
|
||||
{
|
||||
/// <summary>
|
||||
/// filename
|
||||
/// </summary>
|
||||
public string FileName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// filetype
|
||||
/// </summary>
|
||||
public CueFileType FileType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of TRACK in FILE
|
||||
/// </summary>
|
||||
public List<CueTrack> Tracks { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty FILE
|
||||
/// </summary>
|
||||
public CueFile()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill a FILE from an array of lines
|
||||
/// </summary>
|
||||
/// <param name="fileName">File name to set</param>
|
||||
/// <param name="fileType">File type to set</param>
|
||||
/// <param name="cueLines">Lines array to pull from</param>
|
||||
/// <param name="i">Reference to index in array</param>
|
||||
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
|
||||
public CueFile(string fileName, string fileType, string[] cueLines, ref int i, bool throwOnError = false)
|
||||
{
|
||||
if (cueLines == null)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentNullException(nameof(cueLines));
|
||||
|
||||
return;
|
||||
}
|
||||
else if (i < 0 || i > cueLines.Length)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the current fields
|
||||
this.FileName = fileName.Trim('"');
|
||||
this.FileType = GetFileType(fileType);
|
||||
|
||||
// Increment to start
|
||||
i++;
|
||||
|
||||
for (; i < cueLines.Length; i++)
|
||||
{
|
||||
string line = cueLines[i].Trim();
|
||||
string[] splitLine = line.Split(' ');
|
||||
|
||||
// If we have an empty line, we skip
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
continue;
|
||||
|
||||
switch (splitLine[0])
|
||||
{
|
||||
// Read comments
|
||||
case "REM":
|
||||
// We ignore all comments for now
|
||||
break;
|
||||
|
||||
// Read track information
|
||||
case "TRACK":
|
||||
if (splitLine.Length < 3)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"TRACK line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.Tracks == null)
|
||||
this.Tracks = new List<CueTrack>();
|
||||
|
||||
var track = new CueTrack(splitLine[1], splitLine[2], cueLines, ref i);
|
||||
if (track == default)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"TRACK line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Tracks.Add(track);
|
||||
break;
|
||||
|
||||
// Default means return
|
||||
default:
|
||||
i--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the FILE out to a stream
|
||||
/// </summary>
|
||||
/// <param name="sw">StreamWriter to write to</param>
|
||||
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
|
||||
public void Write(StreamWriter sw, bool throwOnError = false)
|
||||
{
|
||||
// If we don't have any tracks, it's invalid
|
||||
if (this.Tracks == null)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentNullException(nameof(this.Tracks));
|
||||
|
||||
return;
|
||||
}
|
||||
else if (this.Tracks.Count == 0)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentException("No tracks provided to write");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sw.WriteLine($"FILE \"{this.FileName}\" {FromFileType(this.FileType)}");
|
||||
|
||||
foreach (var track in Tracks)
|
||||
{
|
||||
track.Write(sw);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the file type from a given string
|
||||
/// </summary>
|
||||
/// <param name="fileType">String to get value from</param>
|
||||
/// <returns>CueFileType, if possible</returns>
|
||||
private CueFileType GetFileType(string fileType)
|
||||
{
|
||||
switch (fileType.ToLowerInvariant())
|
||||
{
|
||||
case "binary":
|
||||
return CueFileType.BINARY;
|
||||
|
||||
case "motorola":
|
||||
return CueFileType.MOTOROLA;
|
||||
|
||||
case "aiff":
|
||||
return CueFileType.AIFF;
|
||||
|
||||
case "wave":
|
||||
return CueFileType.WAVE;
|
||||
|
||||
case "mp3":
|
||||
return CueFileType.MP3;
|
||||
|
||||
default:
|
||||
return CueFileType.BINARY;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string from a given file type
|
||||
/// </summary>
|
||||
/// <param name="fileType">CueFileType to get value from</param>
|
||||
/// <returns>String, if possible (default BINARY)</returns>
|
||||
private string FromFileType(CueFileType fileType)
|
||||
{
|
||||
switch (fileType)
|
||||
{
|
||||
case CueFileType.BINARY:
|
||||
return "BINARY";
|
||||
|
||||
case CueFileType.MOTOROLA:
|
||||
return "MOTOROLA";
|
||||
|
||||
case CueFileType.AIFF:
|
||||
return "AIFF";
|
||||
|
||||
case CueFileType.WAVE:
|
||||
return "WAVE";
|
||||
|
||||
case CueFileType.MP3:
|
||||
return "MP3";
|
||||
|
||||
default:
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
163
MPF.Library/CueSheets/CueIndex.cs
Normal file
163
MPF.Library/CueSheets/CueIndex.cs
Normal file
@@ -0,0 +1,163 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace MPF.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single INDEX in a TRACK
|
||||
/// </summary>
|
||||
public class CueIndex
|
||||
{
|
||||
/// <summary>
|
||||
/// INDEX number, between 0 and 99
|
||||
/// </summary>
|
||||
public int Index { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Starting time of INDEX in minutes
|
||||
/// </summary>
|
||||
public int Minutes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Starting time of INDEX in seconds
|
||||
/// </summary>
|
||||
/// <remarks>There are 60 seconds in a minute</remarks>
|
||||
public int Seconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Starting time of INDEX in frames.
|
||||
/// </summary>
|
||||
/// <remarks>There are 75 frames per second</remarks>
|
||||
public int Frames { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty INDEX
|
||||
/// </summary>
|
||||
public CueIndex()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill a INDEX from an array of lines
|
||||
/// </summary>
|
||||
/// <param name="index">Index to set</param>
|
||||
/// <param name="startTime">Start time to set</param>
|
||||
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
|
||||
public CueIndex(string index, string startTime, bool throwOnError = false)
|
||||
{
|
||||
// Set the current fields
|
||||
if (!int.TryParse(index, out int parsedIndex))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentException($"Index was not a number: {index}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (parsedIndex < 0 || parsedIndex > 99)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Index must be between 0 and 99: {parsedIndex}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore empty lines
|
||||
if (string.IsNullOrWhiteSpace(startTime))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentException("Start time was null or whitespace");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore lines that don't contain the correct information
|
||||
if (startTime.Length != 8 || startTime.Count(c => c == ':') != 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Start time was not in a recognized format: {startTime}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Split the line
|
||||
string[] splitTime = startTime.Split(':');
|
||||
if (splitTime.Length != 3)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Start time was not in a recognized format: {startTime}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the lengths
|
||||
int[] lengthSegments = new int[3];
|
||||
|
||||
// Minutes
|
||||
if (!int.TryParse(splitTime[0], out lengthSegments[0]))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Minutes segment was not a number: {splitTime[0]}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (lengthSegments[0] < 0)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Minutes segment must be 0 or greater: {lengthSegments[0]}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Seconds
|
||||
if (!int.TryParse(splitTime[1], out lengthSegments[1]))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Seconds segment was not a number: {splitTime[1]}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (lengthSegments[1] < 0 || lengthSegments[1] > 60)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Seconds segment must be between 0 and 60: {lengthSegments[1]}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Frames
|
||||
if (!int.TryParse(splitTime[2], out lengthSegments[2]))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Frames segment was not a number: {splitTime[2]}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (lengthSegments[2] < 0 || lengthSegments[2] > 75)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Frames segment must be between 0 and 75: {lengthSegments[2]}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the values
|
||||
this.Index = parsedIndex;
|
||||
this.Minutes = lengthSegments[0];
|
||||
this.Seconds = lengthSegments[1];
|
||||
this.Frames = lengthSegments[2];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the INDEX out to a stream
|
||||
/// </summary>
|
||||
/// <param name="sw">StreamWriter to write to</param>
|
||||
public void Write(StreamWriter sw)
|
||||
{
|
||||
sw.WriteLine($" INDEX {this.Index:D2} {this.Minutes:D2}:{this.Seconds:D2}:{this.Frames:D2}");
|
||||
}
|
||||
}
|
||||
}
|
||||
250
MPF.Library/CueSheets/CueSheet.cs
Normal file
250
MPF.Library/CueSheets/CueSheet.cs
Normal file
@@ -0,0 +1,250 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace MPF.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single cuesheet
|
||||
/// </summary>
|
||||
public class CueSheet
|
||||
{
|
||||
/// <summary>
|
||||
/// CATALOG
|
||||
/// </summary>
|
||||
public string Catalog { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// CDTEXTFILE
|
||||
/// </summary>
|
||||
public string CdTextFile { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// PERFORMER
|
||||
/// </summary>
|
||||
public string Performer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// SONGWRITER
|
||||
/// </summary>
|
||||
public string Songwriter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// TITLE
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of FILE in cuesheet
|
||||
/// </summary>
|
||||
public List<CueFile> Files { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty cuesheet
|
||||
/// </summary>
|
||||
public CueSheet()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a cuesheet from a file, if possible
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
|
||||
public CueSheet(string filename, bool throwOnError = false)
|
||||
{
|
||||
// Check that the file exists
|
||||
if (!File.Exists(filename))
|
||||
return;
|
||||
|
||||
// Check the extension
|
||||
string ext = Path.GetExtension(filename).TrimStart('.');
|
||||
if (!string.Equals(ext, "cue", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(ext, "txt", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Open the file and begin reading
|
||||
string[] cueLines = File.ReadAllLines(filename);
|
||||
for (int i = 0; i < cueLines.Length; i++)
|
||||
{
|
||||
string line = cueLines[i].Trim();
|
||||
|
||||
// http://stackoverflow.com/questions/554013/regular-expression-to-split-on-spaces-unless-in-quotes
|
||||
string[] splitLine = Regex
|
||||
.Matches(line, @"[^\s""]+|""[^""]*""")
|
||||
.Cast<Match>()
|
||||
.Select(m => m.Groups[0].Value)
|
||||
.ToArray();
|
||||
|
||||
// If we have an empty line, we skip
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
continue;
|
||||
|
||||
switch (splitLine[0])
|
||||
{
|
||||
// Read comments
|
||||
case "REM":
|
||||
// We ignore all comments for now
|
||||
break;
|
||||
|
||||
// Read MCN
|
||||
case "CATALOG":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"CATALOG line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Catalog = splitLine[1];
|
||||
break;
|
||||
|
||||
// Read external CD-Text file path
|
||||
case "CDTEXTFILE":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"CDTEXTFILE line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.CdTextFile = splitLine[1];
|
||||
break;
|
||||
|
||||
// Read CD-Text enhanced performer
|
||||
case "PERFORMER":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"PERFORMER line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Performer = splitLine[1];
|
||||
break;
|
||||
|
||||
// Read CD-Text enhanced songwriter
|
||||
case "SONGWRITER":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"SONGWRITER line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Songwriter = splitLine[1];
|
||||
break;
|
||||
|
||||
// Read CD-Text enhanced title
|
||||
case "TITLE":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"TITLE line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Title = splitLine[1];
|
||||
break;
|
||||
|
||||
// Read file information
|
||||
case "FILE":
|
||||
if (splitLine.Length < 3)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"FILE line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.Files == null)
|
||||
this.Files = new List<CueFile>();
|
||||
|
||||
var file = new CueFile(splitLine[1], splitLine[2], cueLines, ref i);
|
||||
if (file == default)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"FILE line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Files.Add(file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the cuesheet out to a file
|
||||
/// </summary>
|
||||
/// <param name="filename">File path to write to</param>
|
||||
public void Write(string filename)
|
||||
{
|
||||
using (var fs = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
|
||||
{
|
||||
Write(fs);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the cuesheet out to a stream
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream to write to</param>
|
||||
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
|
||||
public void Write(Stream stream, bool throwOnError = false)
|
||||
{
|
||||
// If we don't have any files, it's invalid
|
||||
if (this.Files == null)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentNullException(nameof(this.Files));
|
||||
|
||||
return;
|
||||
}
|
||||
else if (this.Files.Count == 0)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentException("No files provided to write");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
using (var sw = new StreamWriter(stream, Encoding.ASCII, 1024, true))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(this.Catalog))
|
||||
sw.WriteLine($"CATALOG {this.Catalog}");
|
||||
|
||||
if (!string.IsNullOrEmpty(this.CdTextFile))
|
||||
sw.WriteLine($"CDTEXTFILE {this.CdTextFile}");
|
||||
|
||||
if (!string.IsNullOrEmpty(this.Performer))
|
||||
sw.WriteLine($"PERFORMER {this.Performer}");
|
||||
|
||||
if (!string.IsNullOrEmpty(this.Songwriter))
|
||||
sw.WriteLine($"SONGWRITER {this.Songwriter}");
|
||||
|
||||
if (!string.IsNullOrEmpty(this.Title))
|
||||
sw.WriteLine($"TITLE {this.Title}");
|
||||
|
||||
foreach (var file in Files)
|
||||
{
|
||||
file.Write(sw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
554
MPF.Library/CueSheets/CueTrack.cs
Normal file
554
MPF.Library/CueSheets/CueTrack.cs
Normal file
@@ -0,0 +1,554 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace MPF.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Track datatype
|
||||
/// </summary>
|
||||
public enum CueTrackDataType
|
||||
{
|
||||
/// <summary>
|
||||
/// AUDIO, Audio/Music (2352)
|
||||
/// </summary>
|
||||
AUDIO,
|
||||
|
||||
/// <summary>
|
||||
/// CDG, Karaoke CD+G (2448)
|
||||
/// </summary>
|
||||
CDG,
|
||||
|
||||
/// <summary>
|
||||
/// MODE1/2048, CD-ROM Mode1 Data (cooked)
|
||||
/// </summary>
|
||||
MODE1_2048,
|
||||
|
||||
/// <summary>
|
||||
/// MODE1/2352 CD-ROM Mode1 Data (raw)
|
||||
/// </summary>
|
||||
MODE1_2352,
|
||||
|
||||
/// <summary>
|
||||
/// MODE2/2336, CD-ROM XA Mode2 Data
|
||||
/// </summary>
|
||||
MODE2_2336,
|
||||
|
||||
/// <summary>
|
||||
/// MODE2/2352, CD-ROM XA Mode2 Data
|
||||
/// </summary>
|
||||
MODE2_2352,
|
||||
|
||||
/// <summary>
|
||||
/// CDI/2336, CD-I Mode2 Data
|
||||
/// </summary>
|
||||
CDI_2336,
|
||||
|
||||
/// <summary>
|
||||
/// CDI/2352, CD-I Mode2 Data
|
||||
/// </summary>
|
||||
CDI_2352,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Special subcode flags within a track
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum CueTrackFlag
|
||||
{
|
||||
/// <summary>
|
||||
/// DCP, Digital copy permitted
|
||||
/// </summary>
|
||||
DCP = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// 4CH, Four channel audio
|
||||
/// </summary>
|
||||
FourCH = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// PRE, Pre-emphasis enabled (audio tracks only)
|
||||
/// </summary>
|
||||
PRE = 1 << 2,
|
||||
|
||||
/// <summary>
|
||||
/// SCMS, Serial Copy Management System (not supported by all recorders)
|
||||
/// </summary>
|
||||
SCMS = 1 << 3,
|
||||
|
||||
/// <summary>
|
||||
/// DATA, set for data files. This flag is set automatically based on the track’s filetype
|
||||
/// </summary>
|
||||
DATA = 1 << 4,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a single TRACK in a FILE
|
||||
/// </summary>
|
||||
public class CueTrack
|
||||
{
|
||||
/// <summary>
|
||||
/// Track number. The range is 1 to 99.
|
||||
/// </summary>
|
||||
public int Number { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Track datatype
|
||||
/// </summary>
|
||||
public CueTrackDataType DataType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// FLAGS
|
||||
/// </summary>
|
||||
public CueTrackFlag Flags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ISRC
|
||||
/// </summary>
|
||||
/// <remarks>12 characters in length</remarks>
|
||||
public string ISRC { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// PERFORMER
|
||||
/// </summary>
|
||||
public string Performer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// SONGWRITER
|
||||
/// </summary>
|
||||
public string Songwriter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// TITLE
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// PREGAP
|
||||
/// </summary>
|
||||
public PreGap PreGap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of INDEX in TRACK
|
||||
/// </summary>
|
||||
/// <remarks>Must start with 0 or 1 and then sequential</remarks>
|
||||
public List<CueIndex> Indices { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// POSTGAP
|
||||
/// </summary>
|
||||
public PostGap PostGap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty TRACK
|
||||
/// </summary>
|
||||
public CueTrack()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill a TRACK from an array of lines
|
||||
/// </summary>
|
||||
/// <param name="number">Number to set</param>
|
||||
/// <param name="dataType">Data type to set</param>
|
||||
/// <param name="cueLines">Lines array to pull from</param>
|
||||
/// <param name="i">Reference to index in array</param>
|
||||
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
|
||||
public CueTrack(string number, string dataType, string[] cueLines, ref int i, bool throwOnError = false)
|
||||
{
|
||||
if (cueLines == null)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentNullException(nameof(cueLines));
|
||||
|
||||
return;
|
||||
}
|
||||
else if (i < 0 || i > cueLines.Length)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the current fields
|
||||
if (!int.TryParse(number, out int parsedNumber))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentException($"Number was not a number: {number}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (parsedNumber < 1 || parsedNumber > 99)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Index must be between 1 and 99: {parsedNumber}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.Number = parsedNumber;
|
||||
this.DataType = GetDataType(dataType);
|
||||
|
||||
// Increment to start
|
||||
i++;
|
||||
|
||||
for (; i < cueLines.Length; i++)
|
||||
{
|
||||
string line = cueLines[i].Trim();
|
||||
string[] splitLine = line.Split(' ');
|
||||
|
||||
// If we have an empty line, we skip
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
continue;
|
||||
|
||||
switch (splitLine[0])
|
||||
{
|
||||
// Read comments
|
||||
case "REM":
|
||||
// We ignore all comments for now
|
||||
break;
|
||||
|
||||
// Read flag information
|
||||
case "FLAGS":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"FLAGS line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Flags = GetFlags(splitLine);
|
||||
break;
|
||||
|
||||
// Read International Standard Recording Code
|
||||
case "ISRC":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"ISRC line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.ISRC = splitLine[1];
|
||||
break;
|
||||
|
||||
// Read CD-Text enhanced performer
|
||||
case "PERFORMER":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"PERFORMER line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Performer = splitLine[1];
|
||||
break;
|
||||
|
||||
// Read CD-Text enhanced songwriter
|
||||
case "SONGWRITER":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"SONGWRITER line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Songwriter = splitLine[1];
|
||||
break;
|
||||
|
||||
// Read CD-Text enhanced title
|
||||
case "TITLE":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"TITLE line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Title = splitLine[1];
|
||||
break;
|
||||
|
||||
// Read pregap information
|
||||
case "PREGAP":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"PREGAP line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var pregap = new PreGap(splitLine[1]);
|
||||
if (pregap == default)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"PREGAP line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.PreGap = pregap;
|
||||
break;
|
||||
|
||||
// Read index information
|
||||
case "INDEX":
|
||||
if (splitLine.Length < 3)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"INDEX line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.Indices == null)
|
||||
this.Indices = new List<CueIndex>();
|
||||
|
||||
var index = new CueIndex(splitLine[1], splitLine[2]);
|
||||
if (index == default)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"INDEX line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Indices.Add(index);
|
||||
break;
|
||||
|
||||
// Read postgap information
|
||||
case "POSTGAP":
|
||||
if (splitLine.Length < 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"POSTGAP line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var postgap = new PostGap(splitLine[1]);
|
||||
if (postgap == default)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"POSTGAP line malformed: {line}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.PostGap = postgap;
|
||||
break;
|
||||
|
||||
// Default means return
|
||||
default:
|
||||
i--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the TRACK out to a stream
|
||||
/// </summary>
|
||||
/// <param name="sw">StreamWriter to write to</param
|
||||
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
|
||||
public void Write(StreamWriter sw, bool throwOnError = false)
|
||||
{
|
||||
// If we don't have any indices, it's invalid
|
||||
if (this.Indices == null)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentNullException(nameof(this.Indices));
|
||||
|
||||
return;
|
||||
}
|
||||
else if (this.Indices.Count == 0)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentException("No indices provided to write");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sw.WriteLine($" TRACK {this.Number:D2} {FromDataType(this.DataType)}");
|
||||
|
||||
if (this.Flags != 0)
|
||||
sw.WriteLine($" FLAGS {FromFlags(this.Flags)}");
|
||||
|
||||
if (!string.IsNullOrEmpty(this.ISRC))
|
||||
sw.WriteLine($"ISRC {this.ISRC}");
|
||||
|
||||
if (!string.IsNullOrEmpty(this.Performer))
|
||||
sw.WriteLine($"PERFORMER {this.Performer}");
|
||||
|
||||
if (!string.IsNullOrEmpty(this.Songwriter))
|
||||
sw.WriteLine($"SONGWRITER {this.Songwriter}");
|
||||
|
||||
if (!string.IsNullOrEmpty(this.Title))
|
||||
sw.WriteLine($"TITLE {this.Title}");
|
||||
|
||||
if (this.PreGap != null)
|
||||
this.PreGap.Write(sw);
|
||||
|
||||
foreach (var index in Indices)
|
||||
{
|
||||
index.Write(sw);
|
||||
}
|
||||
|
||||
if (this.PostGap != null)
|
||||
this.PostGap.Write(sw);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the data type from a given string
|
||||
/// </summary>
|
||||
/// <param name="dataType">String to get value from</param>
|
||||
/// <returns>CueTrackDataType, if possible (default AUDIO)</returns>
|
||||
private CueTrackDataType GetDataType(string dataType)
|
||||
{
|
||||
switch (dataType.ToLowerInvariant())
|
||||
{
|
||||
case "audio":
|
||||
return CueTrackDataType.AUDIO;
|
||||
|
||||
case "cdg":
|
||||
return CueTrackDataType.CDG;
|
||||
|
||||
case "mode1/2048":
|
||||
return CueTrackDataType.MODE1_2048;
|
||||
|
||||
case "mode1/2352":
|
||||
return CueTrackDataType.MODE1_2352;
|
||||
|
||||
case "mode2/2336":
|
||||
return CueTrackDataType.MODE2_2336;
|
||||
|
||||
case "mode2/2352":
|
||||
return CueTrackDataType.MODE2_2352;
|
||||
|
||||
case "cdi/2336":
|
||||
return CueTrackDataType.CDI_2336;
|
||||
|
||||
case "cdi/2352":
|
||||
return CueTrackDataType.CDI_2352;
|
||||
|
||||
default:
|
||||
return CueTrackDataType.AUDIO;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string from a given data type
|
||||
/// </summary>
|
||||
/// <param name="dataType">CueTrackDataType to get value from</param>
|
||||
/// <returns>string, if possible</returns>
|
||||
private string FromDataType(CueTrackDataType dataType)
|
||||
{
|
||||
switch (dataType)
|
||||
{
|
||||
case CueTrackDataType.AUDIO:
|
||||
return "AUDIO";
|
||||
|
||||
case CueTrackDataType.CDG:
|
||||
return "CDG";
|
||||
|
||||
case CueTrackDataType.MODE1_2048:
|
||||
return "MODE1/2048";
|
||||
|
||||
case CueTrackDataType.MODE1_2352:
|
||||
return "MODE1/2352";
|
||||
|
||||
case CueTrackDataType.MODE2_2336:
|
||||
return "MODE2/2336";
|
||||
|
||||
case CueTrackDataType.MODE2_2352:
|
||||
return "MODE2/2352";
|
||||
|
||||
case CueTrackDataType.CDI_2336:
|
||||
return "CDI/2336";
|
||||
|
||||
case CueTrackDataType.CDI_2352:
|
||||
return "CDI/2352";
|
||||
|
||||
default:
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the flag value for an array of strings
|
||||
/// </summary>
|
||||
/// <param name="flagStrings">Possible flags as strings</param>
|
||||
/// <returns>CueTrackFlag value representing the strings, if possible</returns>
|
||||
private CueTrackFlag GetFlags(string[] flagStrings)
|
||||
{
|
||||
CueTrackFlag flag = 0;
|
||||
|
||||
foreach (string flagString in flagStrings)
|
||||
{
|
||||
switch (flagString.ToLowerInvariant())
|
||||
{
|
||||
case "flags":
|
||||
// No-op since this is the start of the line
|
||||
break;
|
||||
|
||||
case "dcp":
|
||||
flag |= CueTrackFlag.DCP;
|
||||
break;
|
||||
|
||||
case "4ch":
|
||||
flag |= CueTrackFlag.FourCH;
|
||||
break;
|
||||
|
||||
case "pre":
|
||||
flag |= CueTrackFlag.PRE;
|
||||
break;
|
||||
|
||||
case "scms":
|
||||
flag |= CueTrackFlag.SCMS;
|
||||
break;
|
||||
|
||||
case "data":
|
||||
flag |= CueTrackFlag.DATA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for a set of track flags
|
||||
/// </summary>
|
||||
/// <param name="flags">CueTrackFlag to get value from</param>
|
||||
/// <returns>String value representing the CueTrackFlag, if possible</returns>
|
||||
private string FromFlags(CueTrackFlag flags)
|
||||
{
|
||||
string outputFlagString = string.Empty;
|
||||
|
||||
if (flags.HasFlag(CueTrackFlag.DCP))
|
||||
outputFlagString += "DCP ";
|
||||
|
||||
if (flags.HasFlag(CueTrackFlag.FourCH))
|
||||
outputFlagString += "4CH ";
|
||||
|
||||
if (flags.HasFlag(CueTrackFlag.PRE))
|
||||
outputFlagString += "PRE ";
|
||||
|
||||
if (flags.HasFlag(CueTrackFlag.SCMS))
|
||||
outputFlagString += "SCMS ";
|
||||
|
||||
if (flags.HasFlag(CueTrackFlag.DATA))
|
||||
outputFlagString += "DATA ";
|
||||
|
||||
return outputFlagString.Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
139
MPF.Library/CueSheets/PostGap.cs
Normal file
139
MPF.Library/CueSheets/PostGap.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace MPF.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents POSTGAP information of a track
|
||||
/// </summary>
|
||||
public class PostGap
|
||||
{
|
||||
/// <summary>
|
||||
/// Length of POSTGAP in minutes
|
||||
/// </summary>
|
||||
public int Minutes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of POSTGAP in seconds
|
||||
/// </summary>
|
||||
/// <remarks>There are 60 seconds in a minute</remarks>
|
||||
public int Seconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of POSTGAP in frames.
|
||||
/// </summary>
|
||||
/// <remarks>There are 75 frames per second</remarks>
|
||||
public int Frames { get; set; }
|
||||
|
||||
/// Create an empty POSTGAP
|
||||
/// </summary>
|
||||
public PostGap()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a POSTGAP from a mm:ss:ff length
|
||||
/// </summary>
|
||||
/// <param name="length">String to get length information from</param>
|
||||
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
|
||||
public PostGap(string length, bool throwOnError = false)
|
||||
{
|
||||
// Ignore empty lines
|
||||
if (string.IsNullOrWhiteSpace(length))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentException("Length was null or whitespace");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore lines that don't contain the correct information
|
||||
if (length.Length != 8 || length.Count(c => c == ':') != 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Length was not in a recognized format: {length}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Split the line
|
||||
string[] splitLength = length.Split(':');
|
||||
if (splitLength.Length != 3)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Length was not in a recognized format: {length}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the lengths
|
||||
int[] lengthSegments = new int[3];
|
||||
|
||||
// Minutes
|
||||
if (!int.TryParse(splitLength[0], out lengthSegments[0]))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Minutes segment was not a number: {splitLength[0]}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (lengthSegments[0] < 0)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Minutes segment must be 0 or greater: {lengthSegments[0]}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Seconds
|
||||
if (!int.TryParse(splitLength[1], out lengthSegments[1]))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Seconds segment was not a number: {splitLength[1]}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (lengthSegments[1] < 0 || lengthSegments[1] > 60)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Seconds segment must be between 0 and 60: {lengthSegments[1]}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Frames
|
||||
if (!int.TryParse(splitLength[2], out lengthSegments[2]))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Frames segment was not a number: {splitLength[2]}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (lengthSegments[2] < 0 || lengthSegments[2] > 75)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Frames segment must be between 0 and 75: {lengthSegments[2]}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the values
|
||||
this.Minutes = lengthSegments[0];
|
||||
this.Seconds = lengthSegments[1];
|
||||
this.Frames = lengthSegments[2];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the POSTGAP out to a stream
|
||||
/// </summary>
|
||||
/// <param name="sw">StreamWriter to write to</param>
|
||||
public void Write(StreamWriter sw)
|
||||
{
|
||||
sw.WriteLine($" POSTGAP {this.Minutes:D2}:{this.Seconds:D2}:{this.Frames:D2}");
|
||||
}
|
||||
}
|
||||
}
|
||||
140
MPF.Library/CueSheets/PreGap.cs
Normal file
140
MPF.Library/CueSheets/PreGap.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace MPF.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents PREGAP information of a track
|
||||
/// </summary>
|
||||
public class PreGap
|
||||
{
|
||||
/// <summary>
|
||||
/// Length of PREGAP in minutes
|
||||
/// </summary>
|
||||
public int Minutes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of PREGAP in seconds
|
||||
/// </summary>
|
||||
/// <remarks>There are 60 seconds in a minute</remarks>
|
||||
public int Seconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of PREGAP in frames.
|
||||
/// </summary>
|
||||
/// <remarks>There are 75 frames per second</remarks>
|
||||
public int Frames { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty PREGAP
|
||||
/// </summary>
|
||||
public PreGap()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a PREGAP from a mm:ss:ff length
|
||||
/// </summary>
|
||||
/// <param name="length">String to get length information from</param>
|
||||
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
|
||||
public PreGap(string length, bool throwOnError = false)
|
||||
{
|
||||
// Ignore empty lines
|
||||
if (string.IsNullOrWhiteSpace(length))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new ArgumentException("Length was null or whitespace");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore lines that don't contain the correct information
|
||||
if (length.Length != 8 || length.Count(c => c == ':') != 2)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Length was not in a recognized format: {length}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Split the line
|
||||
string[] splitLength = length.Split(':');
|
||||
if (splitLength.Length != 3)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Length was not in a recognized format: {length}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the lengths
|
||||
int[] lengthSegments = new int[3];
|
||||
|
||||
// Minutes
|
||||
if (!int.TryParse(splitLength[0], out lengthSegments[0]))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Minutes segment was not a number: {splitLength[0]}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (lengthSegments[0] < 0)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Minutes segment must be 0 or greater: {lengthSegments[0]}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Seconds
|
||||
if (!int.TryParse(splitLength[1], out lengthSegments[1]))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Seconds segment was not a number: {splitLength[1]}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (lengthSegments[1] < 0 || lengthSegments[1] > 60)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Seconds segment must be between 0 and 60: {lengthSegments[1]}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Frames
|
||||
if (!int.TryParse(splitLength[2], out lengthSegments[2]))
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new FormatException($"Frames segment was not a number: {splitLength[2]}");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (lengthSegments[2] < 0 || lengthSegments[2] > 75)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw new IndexOutOfRangeException($"Frames segment must be between 0 and 75: {lengthSegments[2]}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the values
|
||||
this.Minutes = lengthSegments[0];
|
||||
this.Seconds = lengthSegments[1];
|
||||
this.Frames = lengthSegments[2];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the PREGAP out to a stream
|
||||
/// </summary>
|
||||
/// <param name="sw">StreamWriter to write to</param>
|
||||
public void Write(StreamWriter sw)
|
||||
{
|
||||
sw.WriteLine($" PREGAP {this.Minutes:D2}:{this.Seconds:D2}:{this.Frames:D2}");
|
||||
}
|
||||
}
|
||||
}
|
||||
32
MPF.Library/DD/Constants.cs
Normal file
32
MPF.Library/DD/Constants.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
namespace MPF.DD
|
||||
{
|
||||
/// <summary>
|
||||
/// Top-level commands for DD
|
||||
/// </summary>
|
||||
public static class CommandStrings
|
||||
{
|
||||
public const string NONE = "";
|
||||
public const string List = "--list";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dumping flags for DD
|
||||
/// </summary>
|
||||
public static class FlagStrings
|
||||
{
|
||||
// Boolean flags
|
||||
public const string Progress = "--progress";
|
||||
public const string Size = "--size";
|
||||
|
||||
// Int64 flags
|
||||
public const string BlockSize = "bs";
|
||||
public const string Count = "count";
|
||||
public const string Seek = "seek";
|
||||
public const string Skip = "skip";
|
||||
|
||||
// String flags
|
||||
public const string Filter = "--filter";
|
||||
public const string InputFile = "if";
|
||||
public const string OutputFile = "of";
|
||||
}
|
||||
}
|
||||
22
MPF.Library/DD/Converters.cs
Normal file
22
MPF.Library/DD/Converters.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using MPF.Data;
|
||||
|
||||
namespace MPF.DD
|
||||
{
|
||||
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)
|
||||
{
|
||||
// DD has a single, unified output format by default
|
||||
return ".bin";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
401
MPF.Library/DD/Parameters.cs
Normal file
401
MPF.Library/DD/Parameters.cs
Normal file
@@ -0,0 +1,401 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using MPF.Data;
|
||||
|
||||
namespace MPF.DD
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic set of DD parameters
|
||||
/// </summary>
|
||||
public class Parameters : BaseParameters
|
||||
{
|
||||
#region Generic Dumping Information
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string InputPath => InputFileValue?.TrimStart('\\', '?');
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string OutputPath => OutputFileValue;
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <inheritdoc/>
|
||||
public override int? Speed
|
||||
{
|
||||
get { return 1; }
|
||||
set { }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Metadata
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override InternalProgram InternalProgram => InternalProgram.DD;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Flag Values
|
||||
|
||||
public long? BlockSizeValue { get; set; }
|
||||
|
||||
public long? CountValue { get; set; }
|
||||
|
||||
// fixed, removable, disk, partition
|
||||
public string FilterValue { get; set; }
|
||||
|
||||
public string InputFileValue { get; set; }
|
||||
|
||||
public string OutputFileValue { get; set; }
|
||||
|
||||
public long? SeekValue { get; set; }
|
||||
|
||||
public long? SkipValue { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(string parameters) : base(parameters) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
: base(system, type, driveLetter, filename, driveSpeed, options)
|
||||
{
|
||||
}
|
||||
|
||||
#region BaseParameters Implementations
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override (bool, List<string>) CheckAllOutputFilesExist(string basePath, bool preCheck)
|
||||
{
|
||||
// TODO: Figure out what sort of output files are expected... just `.bin`?
|
||||
return (true, new List<string>());
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive, bool includeArtifacts)
|
||||
{
|
||||
// TODO: Fill in submission info specifics for DD
|
||||
string outputDirectory = Path.GetDirectoryName(basePath);
|
||||
|
||||
switch (this.Type)
|
||||
{
|
||||
// Determine type-specific differences
|
||||
}
|
||||
|
||||
switch (this.System)
|
||||
{
|
||||
case KnownSystem.KonamiPython2:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string pythonTwoSerial, out RedumpRegion? pythonTwoRegion, out string pythonTwoDate))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"Internal Disc Serial: {pythonTwoSerial}\n";
|
||||
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? pythonTwoRegion;
|
||||
info.CommonDiscInfo.EXEDateBuildDate = pythonTwoDate;
|
||||
}
|
||||
|
||||
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? "";
|
||||
break;
|
||||
|
||||
case KnownSystem.SonyPlayStation:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationSerial, out RedumpRegion? playstationRegion, out string playstationDate))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationSerial}\n";
|
||||
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))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationTwoSerial}\n";
|
||||
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationTwoRegion;
|
||||
info.CommonDiscInfo.EXEDateBuildDate = playstationTwoDate;
|
||||
}
|
||||
|
||||
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? "";
|
||||
break;
|
||||
|
||||
case KnownSystem.SonyPlayStation4:
|
||||
info.VersionAndEditions.Version = GetPlayStation4Version(drive?.Letter) ?? "";
|
||||
break;
|
||||
|
||||
case KnownSystem.SonyPlayStation5:
|
||||
info.VersionAndEditions.Version = GetPlayStation5Version(drive?.Letter) ?? "";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GenerateParameters()
|
||||
{
|
||||
List<string> parameters = new List<string>();
|
||||
|
||||
if (BaseCommand == null)
|
||||
BaseCommand = CommandStrings.NONE;
|
||||
|
||||
if (!string.IsNullOrEmpty(BaseCommand))
|
||||
parameters.Add(BaseCommand);
|
||||
|
||||
#region Boolean flags
|
||||
|
||||
// Progress
|
||||
if (IsFlagSupported(FlagStrings.Progress))
|
||||
{
|
||||
if (this[FlagStrings.Progress] == true)
|
||||
parameters.Add($"{FlagStrings.Progress}");
|
||||
}
|
||||
|
||||
// Size
|
||||
if (IsFlagSupported(FlagStrings.Size))
|
||||
{
|
||||
if (this[FlagStrings.Size] == true)
|
||||
parameters.Add($"{FlagStrings.Size}");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Int64 flags
|
||||
|
||||
// Block Size
|
||||
if (IsFlagSupported(FlagStrings.BlockSize))
|
||||
{
|
||||
if (this[FlagStrings.BlockSize] == true && BlockSizeValue != null)
|
||||
parameters.Add($"{FlagStrings.BlockSize}={BlockSizeValue}");
|
||||
}
|
||||
|
||||
// Count
|
||||
if (IsFlagSupported(FlagStrings.Count))
|
||||
{
|
||||
if (this[FlagStrings.Count] == true && CountValue != null)
|
||||
parameters.Add($"{FlagStrings.Count}={CountValue}");
|
||||
}
|
||||
|
||||
// Seek
|
||||
if (IsFlagSupported(FlagStrings.Seek))
|
||||
{
|
||||
if (this[FlagStrings.Seek] == true && SeekValue != null)
|
||||
parameters.Add($"{FlagStrings.Seek}={SeekValue}");
|
||||
}
|
||||
|
||||
// Skip
|
||||
if (IsFlagSupported(FlagStrings.Skip))
|
||||
{
|
||||
if (this[FlagStrings.Skip] == true && SkipValue != null)
|
||||
parameters.Add($"{FlagStrings.Skip}={SkipValue}");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region String flags
|
||||
|
||||
// Filter
|
||||
if (IsFlagSupported(FlagStrings.Filter))
|
||||
{
|
||||
if (this[FlagStrings.Filter] == true && FilterValue != null)
|
||||
parameters.Add($"{FlagStrings.Filter}={FilterValue}");
|
||||
}
|
||||
|
||||
// Input File
|
||||
if (IsFlagSupported(FlagStrings.InputFile))
|
||||
{
|
||||
if (this[FlagStrings.InputFile] == true && InputFileValue != null)
|
||||
parameters.Add($"{FlagStrings.InputFile}=\"{InputFileValue}\"");
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
// Output File
|
||||
if (IsFlagSupported(FlagStrings.OutputFile))
|
||||
{
|
||||
if (this[FlagStrings.OutputFile] == true && OutputFileValue != null)
|
||||
parameters.Add($"{FlagStrings.OutputFile}=\"{OutputFileValue}\"");
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
return string.Join(" ", parameters);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Dictionary<string, List<string>> GetCommandSupport()
|
||||
{
|
||||
return new Dictionary<string, List<string>>()
|
||||
{
|
||||
[CommandStrings.NONE] = new List<string>()
|
||||
{
|
||||
FlagStrings.BlockSize,
|
||||
FlagStrings.Count,
|
||||
FlagStrings.Filter,
|
||||
FlagStrings.InputFile,
|
||||
FlagStrings.OutputFile,
|
||||
FlagStrings.Progress,
|
||||
FlagStrings.Seek,
|
||||
FlagStrings.Size,
|
||||
FlagStrings.Skip,
|
||||
},
|
||||
|
||||
[CommandStrings.List] = new List<string>()
|
||||
{
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GetDefaultExtension(MediaType? mediaType) => Converters.Extension(mediaType);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool IsDumpingCommand()
|
||||
{
|
||||
switch (this.BaseCommand)
|
||||
{
|
||||
case CommandStrings.List:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void ResetValues()
|
||||
{
|
||||
BaseCommand = CommandStrings.NONE;
|
||||
|
||||
flags = new Dictionary<string, bool?>();
|
||||
|
||||
BlockSizeValue = null;
|
||||
CountValue = null;
|
||||
InputFileValue = null;
|
||||
OutputFileValue = null;
|
||||
SeekValue = null;
|
||||
SkipValue = null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void SetDefaultParameters(char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
{
|
||||
BaseCommand = CommandStrings.NONE;
|
||||
|
||||
this[FlagStrings.InputFile] = true;
|
||||
InputFileValue = $"\\\\?\\{driveLetter}:";
|
||||
|
||||
this[FlagStrings.OutputFile] = true;
|
||||
OutputFileValue = filename;
|
||||
|
||||
// TODO: Add more common block sizes
|
||||
this[FlagStrings.BlockSize] = true;
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.FloppyDisk:
|
||||
BlockSizeValue = 1440 * 1024;
|
||||
break;
|
||||
|
||||
default:
|
||||
BlockSizeValue = 1024 * 1024 * 1024;
|
||||
break;
|
||||
}
|
||||
|
||||
this[FlagStrings.Progress] = true;
|
||||
this[FlagStrings.Size] = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override bool ValidateAndSetParameters(string parameters)
|
||||
{
|
||||
BaseCommand = CommandStrings.NONE;
|
||||
|
||||
// The string has to be valid by itself first
|
||||
if (string.IsNullOrWhiteSpace(parameters))
|
||||
return false;
|
||||
|
||||
// Now split the string into parts for easier validation
|
||||
// https://stackoverflow.com/questions/14655023/split-a-string-that-has-white-spaces-unless-they-are-enclosed-within-quotes
|
||||
parameters = parameters.Trim();
|
||||
List<string> parts = Regex.Matches(parameters, @"[\""].+?[\""]|[^ ]+")
|
||||
.Cast<Match>()
|
||||
.Select(m => m.Value)
|
||||
.ToList();
|
||||
|
||||
// Determine what the commandline should look like given the first item
|
||||
int start = 0;
|
||||
if (parts[0] == CommandStrings.List)
|
||||
{
|
||||
BaseCommand = parts[0];
|
||||
start = 1;
|
||||
}
|
||||
|
||||
// Loop through all auxilary flags, if necessary
|
||||
for (int i = start; i < parts.Count; i++)
|
||||
{
|
||||
// Flag read-out values
|
||||
long? longValue = null;
|
||||
string stringValue = null;
|
||||
|
||||
// Keep a count of keys to determine if we should break out to filename handling or not
|
||||
int keyCount = Keys.Count();
|
||||
|
||||
#region Boolean flags
|
||||
|
||||
// Progress
|
||||
ProcessFlagParameter(parts, FlagStrings.Progress, ref i);
|
||||
|
||||
// Size
|
||||
ProcessFlagParameter(parts, FlagStrings.Size, ref i);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Int64 flags
|
||||
|
||||
// Block Size
|
||||
longValue = ProcessInt64Parameter(parts, FlagStrings.BlockSize, ref i);
|
||||
if (longValue != null)
|
||||
BlockSizeValue = longValue;
|
||||
|
||||
// Count
|
||||
longValue = ProcessInt64Parameter(parts, FlagStrings.Count, ref i);
|
||||
if (longValue != null)
|
||||
CountValue = longValue;
|
||||
|
||||
// Seek
|
||||
longValue = ProcessInt64Parameter(parts, FlagStrings.Seek, ref i);
|
||||
if (longValue != null)
|
||||
SeekValue = longValue;
|
||||
|
||||
// Skip
|
||||
longValue = ProcessInt64Parameter(parts, FlagStrings.Skip, ref i);
|
||||
if (longValue != null)
|
||||
SkipValue = longValue;
|
||||
|
||||
#endregion
|
||||
|
||||
#region String flags
|
||||
|
||||
// Filter (fixed, removable, disk, partition)
|
||||
stringValue = ProcessStringParameter(parts, FlagStrings.Filter, ref i);
|
||||
if (!string.IsNullOrEmpty(stringValue))
|
||||
FilterValue = stringValue;
|
||||
|
||||
// Input File
|
||||
stringValue = ProcessStringParameter(parts, FlagStrings.InputFile, ref i);
|
||||
if (!string.IsNullOrEmpty(stringValue))
|
||||
InputFileValue = stringValue;
|
||||
|
||||
// Output File
|
||||
stringValue = ProcessStringParameter(parts, FlagStrings.OutputFile, ref i);
|
||||
if (!string.IsNullOrEmpty(stringValue))
|
||||
OutputFileValue = stringValue;
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
1488
MPF.Library/Data/BaseParameters.cs
Normal file
1488
MPF.Library/Data/BaseParameters.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,51 @@
|
||||
namespace DICUI.Data
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MPF.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Constant values for UI
|
||||
/// </summary>
|
||||
public static class Interface
|
||||
{
|
||||
// Button values
|
||||
public const string StartDumping = "Start Dumping";
|
||||
public const string StopDumping = "Stop Dumping";
|
||||
|
||||
// Byte arrays for signatures
|
||||
public static readonly byte[] SaturnSectorZeroStart = new byte[] { 0x53, 0x45, 0x47, 0x41, 0x20, 0x53, 0x45, 0x47, 0x41, 0x53, 0x41, 0x54, 0x55, 0x52, 0x4E, 0x20 };
|
||||
|
||||
// Private lists of known drive speed ranges
|
||||
private static IReadOnlyList<int> cd { get; } = new List<int> { 1, 2, 3, 4, 6, 8, 12, 16, 20, 24, 32, 40, 44, 48, 52, 56, 72 };
|
||||
private static IReadOnlyList<int> dvd { get; } = cd.Where(s => s <= 24).ToList();
|
||||
private static IReadOnlyList<int> bd { get; } = cd.Where(s => s <= 16).ToList();
|
||||
private static IReadOnlyList<int> unknown { get; } = new List<int> { 1 };
|
||||
|
||||
/// <summary>
|
||||
/// Get list of all drive speeds for a given MediaType
|
||||
/// </summary>
|
||||
/// <param name="type">MediaType? that represents the current item</param>
|
||||
/// <returns>Read-only list of drive speeds</returns>
|
||||
public static IReadOnlyList<int> GetSpeedsForMediaType(MediaType? type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
case MediaType.GDROM:
|
||||
return cd;
|
||||
case MediaType.DVD:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return dvd;
|
||||
case MediaType.BluRay:
|
||||
return bd;
|
||||
default:
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Template field values for submission info
|
||||
/// </summary>
|
||||
106
MPF.Library/Data/Drive.cs
Normal file
106
MPF.Library/Data/Drive.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1478
MPF.Library/Data/DumpEnvironment.cs
Normal file
1478
MPF.Library/Data/DumpEnvironment.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,32 +1,23 @@
|
||||
namespace DICUI.Data
|
||||
using System;
|
||||
|
||||
namespace MPF.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Category for Redump
|
||||
/// Available hashing types
|
||||
/// </summary>
|
||||
public enum Category
|
||||
[Flags]
|
||||
public enum Hash
|
||||
{
|
||||
Games = 1,
|
||||
Demos = 2,
|
||||
Video = 3,
|
||||
Audio = 4,
|
||||
Multimedia = 5,
|
||||
Applications = 6,
|
||||
Coverdiscs = 7,
|
||||
Educational = 8,
|
||||
BonusDiscs = 9,
|
||||
Preproduction = 10,
|
||||
AddOns = 11,
|
||||
}
|
||||
CRC = 1 << 0,
|
||||
MD5 = 1 << 1,
|
||||
SHA1 = 1 << 2,
|
||||
SHA256 = 1 << 3,
|
||||
SHA384 = 1 << 4,
|
||||
SHA512 = 1 << 5,
|
||||
|
||||
/// <summary>
|
||||
/// Dump status for Redump
|
||||
/// </summary>
|
||||
public enum DumpStatus
|
||||
{
|
||||
BadDumpRed = 2,
|
||||
PossibleBadDumpYellow = 3,
|
||||
OriginalMediaBlue = 4,
|
||||
TwoOrMoreDumpsGreen = 5,
|
||||
// Special combinations
|
||||
Standard = CRC | MD5 | SHA1,
|
||||
All = CRC | MD5 | SHA1 | SHA256 | SHA384 | SHA512,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -47,9 +38,15 @@
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
DiscImageCreator,
|
||||
// Dumping support
|
||||
Aaru,
|
||||
DD, // TODO: Currently unimplemented
|
||||
DD,
|
||||
DiscImageCreator,
|
||||
|
||||
// Verification support only
|
||||
CleanRip,
|
||||
DCDumper,
|
||||
UmdImageCreator,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -72,10 +69,12 @@
|
||||
HasbroVideoNowColor,
|
||||
HasbroVideoNowJr,
|
||||
HasbroVideoNowXP,
|
||||
MattelFisherPriceiXL,
|
||||
MattelHyperscan,
|
||||
MicrosoftXBOX,
|
||||
MicrosoftXBOX360,
|
||||
MicrosoftXBOXOne,
|
||||
MicrosoftXboxSeriesXS,
|
||||
NECPCEngineTurboGrafxCD,
|
||||
NECPCFX,
|
||||
NintendoGameCube,
|
||||
@@ -93,6 +92,7 @@
|
||||
SonyPlayStation2,
|
||||
SonyPlayStation3,
|
||||
SonyPlayStation4,
|
||||
SonyPlayStation5,
|
||||
SonyPlayStationPortable,
|
||||
TandyMemorexVisualInformationSystem,
|
||||
VMLabsNuon,
|
||||
@@ -240,12 +240,12 @@
|
||||
|
||||
AudioCD,
|
||||
BDVideo,
|
||||
DVDAudio,
|
||||
DVDVideo,
|
||||
EnhancedCD,
|
||||
HDDVDVideo,
|
||||
NavisoftNaviken21,
|
||||
PalmOS,
|
||||
PhilipsCDiDigitalVideo,
|
||||
PhotoCD,
|
||||
PlayStationGameSharkUpdates,
|
||||
RainbowDisc,
|
||||
@@ -273,59 +273,6 @@
|
||||
Custom
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of all disc langauges
|
||||
/// </summary>
|
||||
public enum Language
|
||||
{
|
||||
Afrikaans,
|
||||
Arabic,
|
||||
Basque,
|
||||
Bulgarian,
|
||||
Catalan,
|
||||
Chinese,
|
||||
Croatian,
|
||||
Czech,
|
||||
Danish,
|
||||
Dutch,
|
||||
English,
|
||||
Finnish,
|
||||
French,
|
||||
Gaelic,
|
||||
German,
|
||||
Greek,
|
||||
Hebrew,
|
||||
Hindi,
|
||||
Hungarian,
|
||||
Italian,
|
||||
Japanese,
|
||||
Korean,
|
||||
Norwegian,
|
||||
Polish,
|
||||
Portuguese,
|
||||
Punjabi,
|
||||
Romanian,
|
||||
Russian,
|
||||
Slovak,
|
||||
Slovenian,
|
||||
Spanish,
|
||||
Swedish,
|
||||
Tamil,
|
||||
Thai,
|
||||
Turkish,
|
||||
Ukrainian,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// All possible language selections
|
||||
/// </summary>
|
||||
public enum LanguageSelection
|
||||
{
|
||||
BiosSettings,
|
||||
LanguageSelector,
|
||||
OptionsMenu,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Known media types
|
||||
/// </summary>
|
||||
@@ -385,8 +332,9 @@
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media types according to https://docs.microsoft.com/en-us/previous-versions/windows/desktop/cimwin32a/win32-physicalmedia
|
||||
/// 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,
|
||||
@@ -458,6 +406,182 @@
|
||||
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>
|
||||
@@ -472,47 +596,52 @@
|
||||
// Regular systems
|
||||
AcornArchimedes,
|
||||
AppleMacintosh,
|
||||
AtariJaguarCDInteractiveMultimediaSystem,
|
||||
AudioCD,
|
||||
BDVideo,
|
||||
BandaiPippin,
|
||||
BandaiPlaydiaQuickInteractiveSystem,
|
||||
BDVideo,
|
||||
CommodoreAmigaCD,
|
||||
CommodoreAmigaCD32,
|
||||
CommodoreAmigaCDTV,
|
||||
DVDVideo,
|
||||
EnhancedCD,
|
||||
FujitsuFMTownsseries,
|
||||
funworldPhotoPlay,
|
||||
HasbroVideoNow,
|
||||
HasbroVideoNowColor,
|
||||
HasbroVideoNowJr,
|
||||
HasbroVideoNowXP,
|
||||
IBMPCcompatible,
|
||||
IncredibleTechnologiesEagle,
|
||||
KonamieAmusement,
|
||||
KonamiFireBeat,
|
||||
KonamiM2,
|
||||
KonamiSystem573,
|
||||
KonamiSystemGV,
|
||||
KonamiTwinkle,
|
||||
KonamieAmusement,
|
||||
MattelFisherPriceiXL,
|
||||
MattelHyperScan,
|
||||
MemorexVisualInformationSystem,
|
||||
MicrosoftXbox,
|
||||
MicrosoftXbox360,
|
||||
MicrosoftXboxOne,
|
||||
NECPC88series,
|
||||
NECPC98series,
|
||||
NECPCEngineCDTurboGrafxCD,
|
||||
NECPCFXPCFXGA,
|
||||
MicrosoftXboxSeriesXS,
|
||||
NamcoSegaNintendoTriforce,
|
||||
NamcoSystem12,
|
||||
NamcoSystem246,
|
||||
NavisoftNaviken21,
|
||||
NinendoGameCube,
|
||||
NECPCEngineCDTurboGrafxCD,
|
||||
NECPC88series,
|
||||
NECPC98series,
|
||||
NECPCFXPCFXGA,
|
||||
NintendoGameCube,
|
||||
NintendoWii,
|
||||
NintendoWiiU,
|
||||
PalmOS,
|
||||
Panasonic3DOInteractiveMultiplayer,
|
||||
PanasonicM2,
|
||||
PhilipsCDi,
|
||||
PhilipsCDiDigitalVideo,
|
||||
PhotoCD,
|
||||
PlayStationGameSharkUpdates,
|
||||
SegaChihiro,
|
||||
@@ -521,17 +650,18 @@
|
||||
SegaMegaCDSegaCD,
|
||||
SegaNaomi,
|
||||
SegaNaomi2,
|
||||
SegaPrologue21,
|
||||
SegaRingEdge,
|
||||
SegaRingEdge2,
|
||||
SegaSaturn,
|
||||
SegaTitanVideo,
|
||||
SegaTriforce,
|
||||
SharpX68000,
|
||||
SNKNeoGeoCD,
|
||||
SonyPlayStation,
|
||||
SonyPlayStation2,
|
||||
SonyPlayStation3,
|
||||
SonyPlayStation4,
|
||||
SonyPlayStation5,
|
||||
SonyPlayStationPortable,
|
||||
TABAustriaQuizard,
|
||||
TaoiKTV,
|
||||
@@ -542,75 +672,6 @@
|
||||
ZAPiTGamesGameWaveFamilyEntertainmentSystem,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of all known Redump regions
|
||||
/// </summary>
|
||||
public enum Region
|
||||
{
|
||||
Argentina,
|
||||
Asia,
|
||||
AsiaEurope,
|
||||
AsiaUSA,
|
||||
Australia,
|
||||
Austria,
|
||||
AustriaSwitzerland,
|
||||
Belgium,
|
||||
BelgiumNetherlands,
|
||||
Brazil,
|
||||
Canada,
|
||||
China,
|
||||
Croatia,
|
||||
Czech,
|
||||
Denmark,
|
||||
Europe,
|
||||
EuropeAsia,
|
||||
EuropeAustralia,
|
||||
Finland,
|
||||
France,
|
||||
FranceSpain,
|
||||
Germany,
|
||||
GreaterChina,
|
||||
Greece,
|
||||
Hungary,
|
||||
India,
|
||||
Ireland,
|
||||
Israel,
|
||||
Italy,
|
||||
Japan,
|
||||
JapanAsia,
|
||||
JapanEurope,
|
||||
JapanKorea,
|
||||
JapanUSA,
|
||||
Korea,
|
||||
LatinAmerica,
|
||||
Netherlands,
|
||||
Norway,
|
||||
Poland,
|
||||
Portugal,
|
||||
Russia,
|
||||
Scandinavia,
|
||||
Singapore,
|
||||
Slovakia,
|
||||
SouthAfrica,
|
||||
Spain,
|
||||
Sweden,
|
||||
Switzerland,
|
||||
Taiwan,
|
||||
Thailand,
|
||||
Turkey,
|
||||
UnitedArabEmirates,
|
||||
UK,
|
||||
UKAustralia,
|
||||
Ukraine,
|
||||
USA,
|
||||
USAAsia,
|
||||
USABrazil,
|
||||
USACanada,
|
||||
USAEurope,
|
||||
USAJapan,
|
||||
World,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generic yes/no values for Redump
|
||||
/// </summary>
|
||||
@@ -620,4 +681,97 @@
|
||||
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
|
||||
}
|
||||
296
MPF.Library/Data/IniFile.cs
Normal file
296
MPF.Library/Data/IniFile.cs
Normal file
@@ -0,0 +1,296 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace MPF.Data
|
||||
{
|
||||
public class IniFile : IDictionary<string, string>
|
||||
{
|
||||
private Dictionary<string, string> _keyValuePairs = new Dictionary<string, string>();
|
||||
|
||||
public string this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_keyValuePairs == null)
|
||||
_keyValuePairs = new Dictionary<string, string>();
|
||||
|
||||
key = key.ToLowerInvariant();
|
||||
if (_keyValuePairs.ContainsKey(key))
|
||||
return _keyValuePairs[key];
|
||||
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_keyValuePairs == null)
|
||||
_keyValuePairs = new Dictionary<string, string>();
|
||||
|
||||
key = key.ToLowerInvariant();
|
||||
_keyValuePairs[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty INI file
|
||||
/// </summary>
|
||||
public IniFile()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populate an INI file from path
|
||||
/// </summary>
|
||||
public IniFile(string path)
|
||||
{
|
||||
this.Parse(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populate an INI file from stream
|
||||
/// </summary>
|
||||
public IniFile(Stream stream)
|
||||
{
|
||||
this.Parse(stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add or update a key and value to the INI file
|
||||
/// </summary>
|
||||
public void AddOrUpdate(string key, string value)
|
||||
{
|
||||
_keyValuePairs[key.ToLowerInvariant()] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a key from the INI file
|
||||
/// </summary>
|
||||
public void Remove(string key)
|
||||
{
|
||||
_keyValuePairs.Remove(key.ToLowerInvariant());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an INI file based on the path
|
||||
/// </summary>
|
||||
public bool Parse(string path)
|
||||
{
|
||||
// If we don't have a file, we can't read it
|
||||
if (!File.Exists(path))
|
||||
return false;
|
||||
|
||||
using (var fileStream = File.OpenRead(path))
|
||||
{
|
||||
return Parse(fileStream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an INI file from a stream
|
||||
/// </summary>
|
||||
public bool Parse(Stream stream)
|
||||
{
|
||||
// If the stream is invalid or unreadable, we can't process it
|
||||
if (stream == null || !stream.CanRead || stream.Position >= stream.Length - 1)
|
||||
return false;
|
||||
|
||||
// Keys are case-insensitive by default
|
||||
try
|
||||
{
|
||||
using (StreamReader sr = new StreamReader(stream))
|
||||
{
|
||||
string section = string.Empty;
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
string line = sr.ReadLine().Trim();
|
||||
|
||||
// Comments start with ';'
|
||||
if (line.StartsWith(";"))
|
||||
{
|
||||
// No-op, we don't process comments
|
||||
}
|
||||
|
||||
// Section titles are surrounded by square brackets
|
||||
else if (line.StartsWith("["))
|
||||
{
|
||||
section = line.TrimStart('[').TrimEnd(']');
|
||||
}
|
||||
|
||||
// Valid INI lines are in the format key=value
|
||||
else if (line.Contains("="))
|
||||
{
|
||||
// Split the line by '=' for key-value pairs
|
||||
string[] data = line.Split('=');
|
||||
|
||||
// If the value field contains an '=', we need to put them back in
|
||||
string key = data[0].Trim();
|
||||
string value = string.Join("=", data.Skip(1)).Trim();
|
||||
|
||||
// Section names are prepended to the key with a '.' separating
|
||||
if (!string.IsNullOrEmpty(section))
|
||||
key = $"{section}.{key}";
|
||||
|
||||
// Set or overwrite keys in the returned dictionary
|
||||
_keyValuePairs[key.ToLowerInvariant()] = value;
|
||||
}
|
||||
|
||||
// All other lines are ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error was, just catch and return
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an INI file to a path
|
||||
/// </summary>
|
||||
public bool Write(string path)
|
||||
{
|
||||
// If we don't have a valid dictionary with values, we can't write out
|
||||
if (_keyValuePairs == null || _keyValuePairs.Count == 0)
|
||||
return false;
|
||||
|
||||
using (var fileStream = File.OpenWrite(path))
|
||||
{
|
||||
return Write(fileStream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an INI file to a stream
|
||||
/// </summary>
|
||||
public bool Write(Stream stream)
|
||||
{
|
||||
// If we don't have a valid dictionary with values, we can't write out
|
||||
if (_keyValuePairs == null || _keyValuePairs.Count == 0)
|
||||
return false;
|
||||
|
||||
// If the stream is invalid or unwritable, we can't output to it
|
||||
if (stream == null || !stream.CanWrite || stream.Position >= stream.Length - 1)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
using (StreamWriter sw = new StreamWriter(stream))
|
||||
{
|
||||
// Order the dictionary by keys to link sections together
|
||||
var orderedKeyValuePairs = _keyValuePairs.OrderBy(kvp => kvp.Key);
|
||||
|
||||
string section = string.Empty;
|
||||
foreach (var keyValuePair in orderedKeyValuePairs)
|
||||
{
|
||||
// Extract the key and value
|
||||
string key = keyValuePair.Key;
|
||||
string value = keyValuePair.Value;
|
||||
|
||||
// We assume '.' is a section name separator
|
||||
if (key.Contains('.'))
|
||||
{
|
||||
// Split the key by '.'
|
||||
string[] data = keyValuePair.Key.Split('.');
|
||||
|
||||
// If the key contains an '.', we need to put them back in
|
||||
string newSection = data[0].Trim();
|
||||
key = string.Join(".", data.Skip(1)).Trim();
|
||||
|
||||
// If we have a new section, write it out
|
||||
if (!string.Equals(newSection, section, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
sw.WriteLine($"[{newSection}]");
|
||||
section = newSection;
|
||||
}
|
||||
}
|
||||
|
||||
// Now write out the key and value in a standardized way
|
||||
sw.WriteLine($"{key}={value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error was, just catch and return
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#region IDictionary Impelementations
|
||||
|
||||
public ICollection<string> Keys => ((IDictionary<string, string>)_keyValuePairs).Keys;
|
||||
|
||||
public ICollection<string> Values => ((IDictionary<string, string>)_keyValuePairs).Values;
|
||||
|
||||
public int Count => ((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Count;
|
||||
|
||||
public bool IsReadOnly => ((ICollection<KeyValuePair<string, string>>)_keyValuePairs).IsReadOnly;
|
||||
|
||||
public void Add(string key, string value)
|
||||
{
|
||||
((IDictionary<string, string>)_keyValuePairs).Add(key.ToLowerInvariant(), value);
|
||||
}
|
||||
|
||||
bool IDictionary<string, string>.Remove(string key)
|
||||
{
|
||||
return ((IDictionary<string, string>)_keyValuePairs).Remove(key.ToLowerInvariant());
|
||||
}
|
||||
|
||||
public bool TryGetValue(string key, out string value)
|
||||
{
|
||||
return ((IDictionary<string, string>)_keyValuePairs).TryGetValue(key.ToLowerInvariant(), out value);
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<string, string> item)
|
||||
{
|
||||
var newItem = new KeyValuePair<string, string>(item.Key.ToLowerInvariant(), item.Value);
|
||||
((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Add(newItem);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Clear();
|
||||
}
|
||||
|
||||
public bool Contains(KeyValuePair<string, string> item)
|
||||
{
|
||||
var newItem = new KeyValuePair<string, string>(item.Key.ToLowerInvariant(), item.Value);
|
||||
return ((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Contains(newItem);
|
||||
}
|
||||
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
return _keyValuePairs.ContainsKey(key.ToLowerInvariant());
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex)
|
||||
{
|
||||
((ICollection<KeyValuePair<string, string>>)_keyValuePairs).CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<string, string> item)
|
||||
{
|
||||
var newItem = new KeyValuePair<string, string>(item.Key.ToLowerInvariant(), item.Value);
|
||||
return ((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Remove(newItem);
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable<KeyValuePair<string, string>>)_keyValuePairs).GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable)_keyValuePairs).GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
569
MPF.Library/Data/Options.cs
Normal file
569
MPF.Library/Data/Options.cs
Normal file
@@ -0,0 +1,569 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MPF.Utilities;
|
||||
|
||||
namespace MPF.Data
|
||||
{
|
||||
public class Options : IDictionary<string, string>, ICloneable
|
||||
{
|
||||
private Dictionary<string, string> _settings;
|
||||
|
||||
#region Internal Program
|
||||
|
||||
/// <summary>
|
||||
/// Path to Aaru
|
||||
/// </summary>
|
||||
public string AaruPath
|
||||
{
|
||||
get { return GetStringSetting(_settings, "AaruPath", "Programs\\Aaru\\Aaru.exe"); }
|
||||
set { _settings["AaruPath"] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Path to DiscImageCreator
|
||||
/// </summary>
|
||||
public string DiscImageCreatorPath
|
||||
{
|
||||
get { return GetStringSetting(_settings, "DiscImageCreatorPath", "Programs\\Creator\\DiscImageCreator.exe"); }
|
||||
set { _settings["DiscImageCreatorPath"] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Path to dd for Windows
|
||||
/// </summary>
|
||||
public string DDPath
|
||||
{
|
||||
get { return GetStringSetting(_settings, "DDPath", "Programs\\DD\\dd.exe"); }
|
||||
set { _settings["DDPath"] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected dumping program
|
||||
/// </summary>
|
||||
public InternalProgram InternalProgram
|
||||
{
|
||||
get
|
||||
{
|
||||
string valueString = GetStringSetting(_settings, "InternalProgram", InternalProgram.DiscImageCreator.ToString());
|
||||
var valueEnum = Converters.ToInternalProgram(valueString);
|
||||
return valueEnum == InternalProgram.NONE ? InternalProgram.DiscImageCreator : valueEnum;
|
||||
}
|
||||
set
|
||||
{
|
||||
_settings["InternalProgram"] = value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI Defaults
|
||||
|
||||
/// <summary>
|
||||
/// Enable dark mode for UI elements
|
||||
/// </summary>
|
||||
public bool EnableDarkMode
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "EnableDarkMode", false); }
|
||||
set { _settings["EnableDarkMode"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default output path for dumps
|
||||
/// </summary>
|
||||
public string DefaultOutputPath
|
||||
{
|
||||
get { return GetStringSetting(_settings, "DefaultOutputPath", "ISO"); }
|
||||
set { _settings["DefaultOutputPath"] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default system if none can be detected
|
||||
/// </summary>
|
||||
public KnownSystem DefaultSystem
|
||||
{
|
||||
get
|
||||
{
|
||||
string valueString = GetStringSetting(_settings, "DefaultSystem", KnownSystem.NONE.ToString());
|
||||
var valueEnum = Converters.ToKnownSystem(valueString);
|
||||
return valueEnum ?? KnownSystem.NONE;
|
||||
}
|
||||
set
|
||||
{
|
||||
_settings["DefaultSystem"] = Converters.GetLongName(value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dumping Speeds
|
||||
|
||||
/// <summary>
|
||||
/// Default CD dumping speed
|
||||
/// </summary>
|
||||
public int PreferredDumpSpeedCD
|
||||
{
|
||||
get { return GetInt32Setting(_settings, "PreferredDumpSpeedCD", 72); }
|
||||
set { _settings["PreferredDumpSpeedCD"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default DVD dumping speed
|
||||
/// </summary>
|
||||
public int PreferredDumpSpeedDVD
|
||||
{
|
||||
get { return GetInt32Setting(_settings, "PreferredDumpSpeedDVD", 24); }
|
||||
set { _settings["PreferredDumpSpeedDVD"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default BD dumping speed
|
||||
/// </summary>
|
||||
public int PreferredDumpSpeedBD
|
||||
{
|
||||
get { return GetInt32Setting(_settings, "PreferredDumpSpeedBD", 16); }
|
||||
set { _settings["PreferredDumpSpeedBD"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Aaru
|
||||
|
||||
/// <summary>
|
||||
/// Enable debug output while dumping by default
|
||||
/// </summary>
|
||||
public bool AaruEnableDebug
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "AaruEnableDebug", false); }
|
||||
set { _settings["AaruEnableDebug"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable verbose output while dumping by default
|
||||
/// </summary>
|
||||
public bool AaruEnableVerbose
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "AaruEnableVerbose", false); }
|
||||
set { _settings["AaruEnableVerbose"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable force dumping of media by default
|
||||
/// </summary>
|
||||
public bool AaruForceDumping
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "AaruForceDumping", true); }
|
||||
set { _settings["AaruForceDumping"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default number of sector/subchannel rereads
|
||||
/// </summary>
|
||||
public int AaruRereadCount
|
||||
{
|
||||
get { return GetInt32Setting(_settings, "AaruRereadCount", 5); }
|
||||
set { _settings["AaruRereadCount"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strip personal data information from Aaru metadata by default
|
||||
/// </summary>
|
||||
public bool AaruStripPersonalData
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "AaruStripPersonalData", false); }
|
||||
set { _settings["AaruStripPersonalData"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DiscImageCreator
|
||||
|
||||
/// <summary>
|
||||
/// Enable overly-secure dumping flags by default
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Split this into component parts later. Currently does:
|
||||
/// - Scan sector protection and set subchannel read level to 2 for CD
|
||||
/// - Set scan file protect flag for DVD
|
||||
/// </remarks>
|
||||
public bool DICParanoidMode
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "DICParanoidMode", false); }
|
||||
set { _settings["DICParanoidMode"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable the Quiet flag by default
|
||||
/// </summary>
|
||||
public bool DICQuietMode
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "DICQuietMode", false); }
|
||||
set { _settings["DICQuietMode"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default number of C2 rereads
|
||||
/// </summary>
|
||||
public int DICRereadCount
|
||||
{
|
||||
get { return GetInt32Setting(_settings, "DICRereadCount", 20); }
|
||||
set { _settings["DICRereadCount"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset drive after dumping (useful for older drives)
|
||||
/// </summary>
|
||||
public bool DICResetDriveAfterDump
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "DICResetDriveAfterDump", false); }
|
||||
set { _settings["DICResetDriveAfterDump"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use the CMI flag for supported disc types
|
||||
/// </summary>
|
||||
public bool DICUseCMIFlag
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "DICUseCMIFlag", false); }
|
||||
set { _settings["DICUseCMIFlag"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extra Dumping Options
|
||||
|
||||
/// <summary>
|
||||
/// Scan the disc for protection after dumping
|
||||
/// </summary>
|
||||
public bool ScanForProtection
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "ScanForProtection", true); }
|
||||
set { _settings["ScanForProtection"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add placeholder values in the submission info
|
||||
/// </summary>
|
||||
public bool AddPlaceholders
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "AddPlaceholders", true); }
|
||||
set { _settings["AddPlaceholders"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show the disc information window after dumping
|
||||
/// </summary>
|
||||
public bool PromptForDiscInformation
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "PromptForDiscInformation", true); }
|
||||
set { _settings["PromptForDiscInformation"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Eject the disc after dumping
|
||||
/// </summary>
|
||||
public bool EjectAfterDump
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "EjectAfterDump", false); }
|
||||
set { _settings["EjectAfterDump"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ignore fixed drives when populating the list
|
||||
/// </summary>
|
||||
public bool IgnoreFixedDrives
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "IgnoreFixedDrives", true); }
|
||||
set { _settings["IgnoreFixedDrives"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show dumping tools in their own window instead of in the log
|
||||
/// </summary>
|
||||
public bool ToolsInSeparateWindow
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "ToolsInSeparateWindow", true); }
|
||||
set { _settings["ToolsInSeparateWindow"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Output the compressed JSON version of the submission info
|
||||
/// </summary>
|
||||
public bool OutputSubmissionJSON
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "OutputSubmissionJSON", false); }
|
||||
set { _settings["OutputSubmissionJSON"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Include log files in serialized JSON data
|
||||
/// </summary>
|
||||
public bool IncludeArtifacts
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "IncludeArtifacts", false); }
|
||||
set { _settings["IncludeArtifacts"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compress output log files to reduce space
|
||||
/// </summary>
|
||||
public bool CompressLogFiles
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "CompressLogFiles", true); }
|
||||
set { _settings["CompressLogFiles"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Skip Options
|
||||
|
||||
/// <summary>
|
||||
/// Skip detecting media type on disc scan
|
||||
/// </summary>
|
||||
public bool SkipMediaTypeDetection
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "SkipMediaTypeDetection", false); }
|
||||
set { _settings["SkipMediaTypeDetection"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Skip detecting known system on disc scan
|
||||
/// </summary>
|
||||
public bool SkipSystemDetection
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "SkipSystemDetection", false); }
|
||||
set { _settings["SkipSystemDetection"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protection Scanning Options
|
||||
|
||||
/// <summary>
|
||||
/// Scan archive contents during protection scanning
|
||||
/// </summary>
|
||||
public bool ScanArchivesForProtection
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "ScanArchivesForProtection", true); }
|
||||
set { _settings["ScanArchivesForProtection"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scan for executable packers during protection scanning
|
||||
/// </summary>
|
||||
public bool ScanPackersForProtection
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "ScanPackersForProtection", false); }
|
||||
set { _settings["ScanPackersForProtection"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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>
|
||||
public bool IncludeDebugProtectionInformation
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "IncludeDebugProtectionInformation", false); }
|
||||
set { _settings["IncludeDebugProtectionInformation"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Logging Options
|
||||
|
||||
/// <summary>
|
||||
/// Enable verbose and debug logs to be written
|
||||
/// </summary>
|
||||
public bool VerboseLogging
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "VerboseLogging", true); }
|
||||
set { _settings["VerboseLogging"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Have the log panel expanded by default on startup
|
||||
/// </summary>
|
||||
public bool OpenLogWindowAtStartup
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "OpenLogWindowAtStartup", true); }
|
||||
set { _settings["OpenLogWindowAtStartup"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable fancy formatting of log statements
|
||||
/// Disables EnableProgressProcessing if disabled
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is mainly for outputting redirected console outputs. Not many
|
||||
/// other bits of the logs include any specially handled outputs.
|
||||
/// </remarks>
|
||||
public bool EnableLogFormatting
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "EnableLogFormatting", false); }
|
||||
set { _settings["EnableLogFormatting"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable progress bar updating based on log text
|
||||
/// Disabled if EnableLogFormatting is disabled
|
||||
/// </summary>
|
||||
public bool EnableProgressProcessing
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "EnableProgressProcessing", false); }
|
||||
set { _settings["EnableProgressProcessing"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Redump Login Information
|
||||
|
||||
public string RedumpUsername
|
||||
{
|
||||
get { return GetStringSetting(_settings, "RedumpUsername", ""); }
|
||||
set { _settings["RedumpUsername"] = value; }
|
||||
}
|
||||
|
||||
// TODO: Figure out a way to keep this encrypted in some way, BASE64 to start?
|
||||
public string RedumpPassword
|
||||
{
|
||||
get { return GetStringSetting(_settings, "RedumpPassword", ""); }
|
||||
set { _settings["RedumpPassword"] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if a complete set of Redump credentials might exist
|
||||
/// </summary>
|
||||
public bool HasRedumpLogin { get => !string.IsNullOrWhiteSpace(RedumpUsername) && !string.IsNullOrWhiteSpace(RedumpPassword); }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor taking a dictionary for settings
|
||||
/// </summary>
|
||||
/// <param name="settings"></param>
|
||||
public Options(Dictionary<string, string> settings = null)
|
||||
{
|
||||
this._settings = settings ?? new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a clone of the object
|
||||
/// </summary>
|
||||
public object Clone()
|
||||
{
|
||||
return new Options(new Dictionary<string, string>(_settings));
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Get a Boolean setting from a settings, dictionary
|
||||
/// </summary>
|
||||
/// <param name="settings">Dictionary representing the settings</param>
|
||||
/// <param name="key">Setting key to get a value for</param>
|
||||
/// <param name="defaultValue">Default value to return if no value is found</param>
|
||||
/// <returns>Setting value if possible, default value otherwise</returns>
|
||||
private bool GetBooleanSetting(Dictionary<string, string> settings, string key, bool defaultValue)
|
||||
{
|
||||
if (settings.ContainsKey(key))
|
||||
{
|
||||
if (Boolean.TryParse(settings[key], out bool value))
|
||||
return value;
|
||||
else
|
||||
return defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an Int32 setting from a settings, dictionary
|
||||
/// </summary>
|
||||
/// <param name="settings">Dictionary representing the settings</param>
|
||||
/// <param name="key">Setting key to get a value for</param>
|
||||
/// <param name="defaultValue">Default value to return if no value is found</param>
|
||||
/// <returns>Setting value if possible, default value otherwise</returns>
|
||||
private int GetInt32Setting(Dictionary<string, string> settings, string key, int defaultValue)
|
||||
{
|
||||
if (settings.ContainsKey(key))
|
||||
{
|
||||
if (Int32.TryParse(settings[key], out int value))
|
||||
return value;
|
||||
else
|
||||
return defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a String setting from a settings, dictionary
|
||||
/// </summary>
|
||||
/// <param name="settings">Dictionary representing the settings</param>
|
||||
/// <param name="key">Setting key to get a value for</param>
|
||||
/// <param name="defaultValue">Default value to return if no value is found</param>
|
||||
/// <returns>Setting value if possible, default value otherwise</returns>
|
||||
private string GetStringSetting(Dictionary<string, string> settings, string key, string defaultValue)
|
||||
{
|
||||
if (settings.ContainsKey(key))
|
||||
return settings[key];
|
||||
else
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDictionary implementations
|
||||
|
||||
public ICollection<string> Keys => _settings.Keys;
|
||||
|
||||
public ICollection<string> Values => _settings.Values;
|
||||
|
||||
public int Count => _settings.Count;
|
||||
|
||||
public bool IsReadOnly => ((IDictionary<string, string>)_settings).IsReadOnly;
|
||||
|
||||
public string this[string key]
|
||||
{
|
||||
get { return (_settings.ContainsKey(key) ? _settings[key] : null); }
|
||||
set { _settings[key] = value; }
|
||||
}
|
||||
|
||||
public bool ContainsKey(string key) => _settings.ContainsKey(key);
|
||||
|
||||
public void Add(string key, string value) => _settings.Add(key, value);
|
||||
|
||||
public bool Remove(string key) => _settings.Remove(key);
|
||||
|
||||
public bool TryGetValue(string key, out string value) => _settings.TryGetValue(key, out value);
|
||||
|
||||
public void Add(KeyValuePair<string, string> item) => _settings.Add(item.Key, item.Value);
|
||||
|
||||
public void Clear() => _settings.Clear();
|
||||
|
||||
public bool Contains(KeyValuePair<string, string> item) => ((IDictionary<string, string>)_settings).Contains(item);
|
||||
|
||||
public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex) => ((IDictionary<string, string>)_settings).CopyTo(array, arrayIndex);
|
||||
|
||||
public bool Remove(KeyValuePair<string, string> item) => ((IDictionary<string, string>)_settings).Remove(item);
|
||||
|
||||
public IEnumerator<KeyValuePair<string, string>> GetEnumerator() => _settings.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => _settings.GetEnumerator();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
78
MPF.Library/Data/ProcessingQueue.cs
Normal file
78
MPF.Library/Data/ProcessingQueue.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MPF.Data
|
||||
{
|
||||
public class ProcessingQueue<T> : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Internal queue to hold data to process
|
||||
/// </summary>
|
||||
private readonly ConcurrentQueue<T> InternalQueue;
|
||||
|
||||
/// <summary>
|
||||
/// Custom processing step for dequeued data
|
||||
/// </summary>
|
||||
private readonly Action<T> CustomProcessing;
|
||||
|
||||
/// <summary>
|
||||
/// Cancellation method for the processing task
|
||||
/// </summary>
|
||||
private readonly CancellationTokenSource TokenSource;
|
||||
|
||||
public ProcessingQueue(Action<T> customProcessing)
|
||||
{
|
||||
this.InternalQueue = new ConcurrentQueue<T>();
|
||||
this.CustomProcessing = customProcessing;
|
||||
this.TokenSource = new CancellationTokenSource();
|
||||
Task.Run(() => ProcessQueue(), this.TokenSource.Token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose the current instance
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.TokenSource.Cancel();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue a new item for processing
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public void Enqueue(T item)
|
||||
{
|
||||
// Only accept new data when not cancelled
|
||||
if (!this.TokenSource.IsCancellationRequested)
|
||||
this.InternalQueue.Enqueue(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process
|
||||
/// </summary>
|
||||
private void ProcessQueue()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Nothing in the queue means we get to idle
|
||||
if (this.InternalQueue.Count == 0)
|
||||
{
|
||||
if (this.TokenSource.IsCancellationRequested)
|
||||
break;
|
||||
|
||||
Thread.Sleep(10);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the next item from the queue
|
||||
if (!this.InternalQueue.TryDequeue(out T nextItem))
|
||||
continue;
|
||||
|
||||
// Invoke the lambda, if possible
|
||||
this.CustomProcessing?.Invoke(nextItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace DICUI.Utilities
|
||||
namespace MPF.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Generic success/failure result object, with optional message
|
||||
@@ -32,13 +32,6 @@
|
||||
/// <param name="message">String to add as a message</param>
|
||||
public static Result Success(string message) => new Result(true, message);
|
||||
|
||||
/// <summary>
|
||||
/// Create a success result with a custom message with format parameters
|
||||
/// </summary>
|
||||
/// <param name="message">String to add as a message</param>
|
||||
/// <param name="args">Formatting parameters for the string</param>
|
||||
public static Result Success(string message, params object[] args) => new Result(true, string.Format(message, args));
|
||||
|
||||
/// <summary>
|
||||
/// Create a default failure result with no message
|
||||
/// </summary>
|
||||
@@ -51,13 +44,6 @@
|
||||
/// <param name="message">String to add as a message</param>
|
||||
public static Result Failure(string message) => new Result(false, message);
|
||||
|
||||
/// <summary>
|
||||
/// Create a failure result with a custom message with format parameters
|
||||
/// </summary>
|
||||
/// <param name="message">String to add as a message</param>
|
||||
/// <param name="args">Formatting parameters for the string</param>
|
||||
public static Result Failure(string message, params object[] args) => new Result(false, string.Format(message, args));
|
||||
|
||||
/// <summary>
|
||||
/// Results can be compared to boolean values based on the success value
|
||||
/// </summary>
|
||||
@@ -1,16 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Net;
|
||||
using DICUI.Utilities;
|
||||
using MPF.Data;
|
||||
using MPF.Utilities;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace DICUI.Data
|
||||
namespace MPF.Data
|
||||
{
|
||||
public class SubmissionInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Version of the current schema
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "schema_version", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public int SchemaVersion { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// List of matched Redump IDs
|
||||
/// </summary>
|
||||
@@ -56,192 +60,8 @@ namespace DICUI.Data
|
||||
[JsonProperty(PropertyName = "size_and_checksums", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public SizeAndChecksumsSection SizeAndChecksums { get; set; } = new SizeAndChecksumsSection();
|
||||
|
||||
#region Regexes
|
||||
|
||||
private readonly Regex addedRegex = new Regex(@"<tr><th>Added</th><td>(.*?)</td></tr>");
|
||||
private readonly Regex barcodeRegex = new Regex(@"<tr><th>Barcode</th></tr><tr><td>(.*?)</td></tr>");
|
||||
private readonly Regex bcaRegex = new Regex(@"<h3>BCA .*?/></h3></td><td .*?></td></tr>"
|
||||
+ "<tr><th>Row</th><th>Contents</th><th>ASCII</th></tr>"
|
||||
+ "<tr><td>(?<row1number>.*?)</td><td>(?<row1contents>.*?)</td><td>(?<row1ascii>.*?)</td></tr>"
|
||||
+ "<tr><td>(?<row2number>.*?)</td><td>(?<row2contents>.*?)</td><td>(?<row2ascii>.*?)</td></tr>"
|
||||
+ "<tr><td>(?<row3number>.*?)</td><td>(?<row3contents>.*?)</td><td>(?<row3ascii>.*?)</td></tr>"
|
||||
+ "<tr><td>(?<row4number>.*?)</td><td>(?<row4contents>.*?)</td><td>(?<row4ascii>.*?)</td></tr>");
|
||||
private readonly Regex categoryRegex = new Regex(@"<tr><th>Category</th><td>(.*?)</td></tr>");
|
||||
private readonly Regex commentsRegex = new Regex(@"<tr><th>Comments</th></tr><tr><td>(.*?)</td></tr>");
|
||||
private readonly Regex contentsRegex = new Regex(@"<tr><th>Contents</th></tr><tr .*?><td>(.*?)</td></tr>");
|
||||
private readonly Regex discNumberLetterRegex = new Regex(@"\((.*?)\)");
|
||||
private readonly Regex dumpersRegex = new Regex(@"<a href=""/discs/dumper/(.*?)/"">");
|
||||
private readonly Regex editionRegex = new Regex(@"<tr><th>Edition</th><td>(.*?)</td></tr>");
|
||||
private readonly Regex errorCountRegex = new Regex(@"<tr><th>Errors count</th><td>(.*?)</td></tr>");
|
||||
private readonly Regex foreignTitleRegex = new Regex(@"<h2>(.*?)</h2>");
|
||||
private readonly Regex fullMatchRegex = new Regex(@"<td class=""static"">full match ids: (.*?)</td>");
|
||||
private readonly Regex languagesRegex = new Regex(@"<img src=""/images/languages/(.*?)\.png"" alt="".*?"" title="".*?"" />\s*");
|
||||
private readonly Regex lastModifiedRegex = new Regex(@"<tr><th>Last modified</th><td>(.*?)</td></tr>");
|
||||
private readonly Regex mediaRegex = new Regex(@"<tr><th>Media</th><td>(.*?)</td></tr>");
|
||||
private readonly Regex partialMatchRegex = new Regex(@"<td class=""static"">partial match ids: (.*?)</td>");
|
||||
private readonly Regex pvdRegex = new Regex(@"<h3>Primary Volume Descriptor (PVD) <img .*?/></h3></td><td .*?></td></tr>"
|
||||
+ @"<tr><th>Record / Entry</th><th>Contents</th><th>Date</th><th>Time</th><th>GMT</th></tr>"
|
||||
+ @"<tr><td>Creation</td><td>(?<creationbytes>.*?)</td><td>(?<creationdate>.*?)</td><td>(?<creationtime>.*?)</td><td>(?<creationtimezone>.*?)</td></tr>"
|
||||
+ @"<tr><td>Modification</td><td>(?<modificationbytes>.*?)</td><td>(?<modificationdate>.*?)</td><td>(?<modificationtime>.*?)</td><td>(?<modificationtimezone>.*?)</td></tr>"
|
||||
+ @"<tr><td>Expiration</td><td>(?<expirationbytes>.*?)</td><td>(?<expirationdate>.*?)</td><td>(?<expirationtime>.*?)</td><td>(?<expirationtimezone>.*?)</td></tr>"
|
||||
+ @"<tr><td>Effective</td><td>(?<effectivebytes>.*?)</td><td>(?<effectivedate>.*?)</td><td>(?<effectivetime>.*?)</td><td>(?<effectivetimezone>.*?)</td></tr>");
|
||||
private readonly Regex regionRegex = new Regex(@"<tr><th>Region</th><td><a href=""/discs/region/(.*?)/"">");
|
||||
private readonly Regex ringCodeDoubleRegex = new Regex(@""); // Varies based on available fields, like Addtional Mould
|
||||
private readonly Regex ringCodeSingleRegex = new Regex(@""); // Varies based on available fields, like Addtional Mould
|
||||
private readonly Regex serialRegex = new Regex(@"<tr><th>Serial</th><td>(.*?)</td></tr>");
|
||||
private readonly Regex systemRegex = new Regex(@"<tr><th>System</th><td><a href=""/discs/system/(.*?)/"">");
|
||||
private readonly Regex titleRegex = new Regex(@"<h1>(.*?)</h1>");
|
||||
private readonly Regex trackRegex = new Regex(@"<tr><td>(?<number>.*?)</td><td>(?<type>.*?)</td><td>(?<pregap>.*?)</td><td>(?<length>.*?)</td><td>(?<sectors>.*?)</td><td>(?<size>.*?)</td><td>(?<crc32>.*?)</td><td>(?<md5>.*?)</td><td>(?<sha1>.*?)</td></tr>");
|
||||
private readonly Regex trackCountRegex = new Regex(@"<tr><th>Number of tracks</th><td>(.*?)</td></tr>");
|
||||
private readonly Regex versionRegex = new Regex(@"<tr><th>Version</th><td>(.*?)</td></tr>");
|
||||
private readonly Regex writeOffsetRegex = new Regex(@"<tr><th>Write offset</th><td>(.*?)</td></tr>");
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Fill in information from a Redump disc page
|
||||
/// </summary>
|
||||
/// <param name="discData">String representation of the disc page</param>
|
||||
public void FillFromDiscPage(string discData)
|
||||
{
|
||||
// Title, Disc Number/Letter, Disc Title
|
||||
var match = titleRegex.Match(discData);
|
||||
if (match.Success)
|
||||
{
|
||||
string title = WebUtility.HtmlDecode(match.Groups[1].Value);
|
||||
|
||||
// If we have parenthesis, title is everything before the first one
|
||||
int firstParenLocation = title.IndexOf(" (");
|
||||
if (firstParenLocation >= 0)
|
||||
{
|
||||
this.CommonDiscInfo.Title = title.Substring(0, firstParenLocation);
|
||||
var subMatches = discNumberLetterRegex.Match(title);
|
||||
for (int i = 1; i < subMatches.Groups.Count; i++)
|
||||
{
|
||||
string subMatch = subMatches.Groups[i].Value;
|
||||
|
||||
// Disc number or letter
|
||||
if (subMatch.StartsWith("Disc"))
|
||||
this.CommonDiscInfo.DiscNumberLetter = subMatch.Remove(0, "Disc ".Length);
|
||||
|
||||
// Disc title
|
||||
else
|
||||
this.CommonDiscInfo.DiscTitle = subMatch;
|
||||
}
|
||||
}
|
||||
// Otherwise, leave the title as-is
|
||||
else
|
||||
{
|
||||
this.CommonDiscInfo.Title = title;
|
||||
}
|
||||
}
|
||||
|
||||
// Foreign Title
|
||||
match = foreignTitleRegex.Match(discData);
|
||||
if (match.Success)
|
||||
this.CommonDiscInfo.ForeignTitleNonLatin = WebUtility.HtmlDecode(match.Groups[1].Value);
|
||||
else
|
||||
this.CommonDiscInfo.ForeignTitleNonLatin = null;
|
||||
|
||||
// Category
|
||||
match = categoryRegex.Match(discData);
|
||||
if (match.Success)
|
||||
this.CommonDiscInfo.Category = Converters.ToCategory(match.Groups[1].Value);
|
||||
else
|
||||
this.CommonDiscInfo.Category = Data.Category.Games;
|
||||
|
||||
// Region
|
||||
match = regionRegex.Match(discData);
|
||||
if (match.Success)
|
||||
this.CommonDiscInfo.Region = Converters.ToRegion(match.Groups[1].Value);
|
||||
|
||||
// Languages
|
||||
var matches = languagesRegex.Matches(discData);
|
||||
if (matches.Count > 0)
|
||||
{
|
||||
List<Language?> tempLanguages = new List<Language?>();
|
||||
foreach (Match submatch in matches)
|
||||
tempLanguages.Add(Converters.ToLanguage(submatch.Groups[1].Value));
|
||||
|
||||
this.CommonDiscInfo.Languages = tempLanguages.ToArray();
|
||||
}
|
||||
|
||||
// Serial
|
||||
match = serialRegex.Match(discData);
|
||||
if (match.Success)
|
||||
this.CommonDiscInfo.Serial = WebUtility.HtmlDecode(match.Groups[1].Value);
|
||||
|
||||
// Error count
|
||||
match = errorCountRegex.Match(discData);
|
||||
if (match.Success)
|
||||
{
|
||||
// If the error counts don't match, then use the one from the disc page
|
||||
if (!string.IsNullOrEmpty(this.CommonDiscInfo.ErrorsCount) && match.Groups[1].Value != this.CommonDiscInfo.ErrorsCount)
|
||||
this.CommonDiscInfo.ErrorsCount = match.Groups[1].Value;
|
||||
}
|
||||
|
||||
// Version
|
||||
match = versionRegex.Match(discData);
|
||||
if (match.Success)
|
||||
this.VersionAndEditions.Version = WebUtility.HtmlDecode(match.Groups[1].Value);
|
||||
|
||||
// Edition
|
||||
match = editionRegex.Match(discData);
|
||||
if (match.Success)
|
||||
this.VersionAndEditions.OtherEditions = WebUtility.HtmlDecode(match.Groups[1].Value);
|
||||
|
||||
// Dumpers
|
||||
matches = dumpersRegex.Matches(discData);
|
||||
if (matches.Count > 0)
|
||||
{
|
||||
// Start with any currently listed dumpers
|
||||
List<string> tempDumpers = new List<string>();
|
||||
if (this.DumpersAndStatus.Dumpers.Length > 0)
|
||||
{
|
||||
foreach (string dumper in this.DumpersAndStatus.Dumpers)
|
||||
tempDumpers.Add(dumper);
|
||||
}
|
||||
|
||||
foreach (Match submatch in matches)
|
||||
tempDumpers.Add(WebUtility.HtmlDecode(submatch.Groups[1].Value));
|
||||
|
||||
this.DumpersAndStatus.Dumpers = tempDumpers.ToArray();
|
||||
}
|
||||
|
||||
// Barcode
|
||||
match = barcodeRegex.Match(discData);
|
||||
if (match.Success)
|
||||
this.CommonDiscInfo.Barcode = WebUtility.HtmlDecode(match.Groups[1].Value);
|
||||
|
||||
// Comments
|
||||
match = commentsRegex.Match(discData);
|
||||
if (match.Success)
|
||||
{
|
||||
this.CommonDiscInfo.Comments = WebUtility.HtmlDecode(match.Groups[1].Value)
|
||||
.Replace("<br />", "\n")
|
||||
.Replace("<b>ISBN</b>", "[T:ISBN]") + "\n";
|
||||
}
|
||||
|
||||
// Contents
|
||||
match = contentsRegex.Match(discData);
|
||||
if (match.Success)
|
||||
{
|
||||
this.CommonDiscInfo.Contents = WebUtility.HtmlDecode(match.Groups[1].Value)
|
||||
.Replace("<br />", "\n")
|
||||
.Replace("</div>", "");
|
||||
this.CommonDiscInfo.Contents = Regex.Replace(this.CommonDiscInfo.Contents, @"<div .*?>", "");
|
||||
}
|
||||
|
||||
// Added
|
||||
match = addedRegex.Match(discData);
|
||||
if (match.Success)
|
||||
this.Added = DateTime.Parse(match.Groups[1].Value);
|
||||
|
||||
// Last Modified
|
||||
match = lastModifiedRegex.Match(discData);
|
||||
if (match.Success)
|
||||
this.LastModified = DateTime.Parse(match.Groups[1].Value);
|
||||
}
|
||||
[JsonProperty(PropertyName = "artifacts", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public Dictionary<string, string> Artifacts { get; set; } = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -249,13 +69,12 @@ namespace DICUI.Data
|
||||
/// </summary>
|
||||
public class CommonDiscInfoSection
|
||||
{
|
||||
// TODO: Name not defined
|
||||
// Name not defined by Redump
|
||||
[JsonProperty(PropertyName = "d_system", Required = Required.AllowNull)]
|
||||
[JsonConverter(typeof(KnownSystemConverter))]
|
||||
public KnownSystem? System { get; set; }
|
||||
|
||||
// TODO: Name not defined
|
||||
// TODO: Have this convert to a new `RedumpMedia?` if possible, for submission
|
||||
// Name not defined by Redump
|
||||
[JsonProperty(PropertyName = "d_media", Required = Required.AllowNull)]
|
||||
[JsonConverter(typeof(MediaTypeConverter))]
|
||||
public MediaType? Media { get; set; }
|
||||
@@ -273,19 +92,19 @@ namespace DICUI.Data
|
||||
public string DiscTitle { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_category", Required = Required.AllowNull)]
|
||||
public Category? Category { get; set; }
|
||||
public RedumpDiscCategory? Category { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_region", Required = Required.AllowNull)]
|
||||
[JsonConverter(typeof(RegionConverter))]
|
||||
public Region? Region { get; set; }
|
||||
[JsonConverter(typeof(RedumpRegionConverter))]
|
||||
public RedumpRegion? Region { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_languages", Required = Required.AllowNull)]
|
||||
[JsonConverter(typeof(LanguagesConverter))]
|
||||
public Language?[] Languages { get; set; }
|
||||
[JsonConverter(typeof(RedumpLanguageConverter))]
|
||||
public RedumpLanguage?[] Languages { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_languages_selection", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
[JsonConverter(typeof(LanguageSelectionConverter))]
|
||||
public LanguageSelection?[] LanguageSelection { get; set; }
|
||||
[JsonConverter(typeof(RedumpLanguageSelectionConverter))]
|
||||
public RedumpLanguageSelection?[] LanguageSelection { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_serial", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Serial { get; set; }
|
||||
@@ -297,34 +116,52 @@ namespace DICUI.Data
|
||||
public string RingId { get; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_ma1", Required = Required.AllowNull)]
|
||||
public string MasteringRingFirstLayerDataSide { get; set; }
|
||||
public string Layer0MasteringRing { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_ma1_sid", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string MasteringSIDCodeFirstLayerDataSide { get; set; }
|
||||
public string Layer0MasteringSID { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_ts1", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string ToolstampMasteringCodeFirstLayerDataSide { get; set; }
|
||||
public string Layer0ToolstampMasteringCode { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_mo1_sid", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string MouldSIDCodeFirstLayerDataSide { get; set; }
|
||||
public string Layer0MouldSID { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "dr_ring_0_mo1", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string AdditionalMouldFirstLayerDataSide { get; set; }
|
||||
public string Layer0AdditionalMould { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_ma2", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string MasteringRingSecondLayerLabelSide { get; set; }
|
||||
[JsonProperty(PropertyName = "d_ring_0_ma2", Required = Required.AllowNull)]
|
||||
public string Layer1MasteringRing { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_ma2_sid", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string MasteringSIDCodeSecondLayerLabelSide { get; set; }
|
||||
public string Layer1MasteringSID { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_ts2", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string ToolstampMasteringCodeSecondLayerLabelSide { get; set; }
|
||||
public string Layer1ToolstampMasteringCode { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_mo2_sid", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string MouldSIDCodeSecondLayerLabelSide { get; set; }
|
||||
public string Layer1MouldSID { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "dr_ring_0_mo2", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string AdditionalMouldSecondLayerLabelSide { get; set; }
|
||||
public string Layer1AdditionalMould { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_ma3", Required = Required.AllowNull)]
|
||||
public string Layer2MasteringRing { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_ma3_sid", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Layer2MasteringSID { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_ts3", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Layer2ToolstampMasteringCode { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_ma4", Required = Required.AllowNull)]
|
||||
public string Layer3MasteringRing { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_ma4_sid", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Layer3MasteringSID { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_ts4", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Layer3ToolstampMasteringCode { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_ring_0_offsets", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string RingOffsetsHidden { get { return "1"; } }
|
||||
@@ -450,7 +287,7 @@ namespace DICUI.Data
|
||||
public class DumpersAndStatusSection
|
||||
{
|
||||
[JsonProperty(PropertyName = "d_status", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public DumpStatus Status { get; set; }
|
||||
public RedumpDumpStatus Status { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_dumpers", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string[] Dumpers { get; set; }
|
||||
@@ -478,13 +315,19 @@ namespace DICUI.Data
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Size & checksums section of New Disc form (DVD/BD/UMD-based)
|
||||
/// Size & checksums section of New Disc form (DVD/BD/UMD-based)
|
||||
/// </summary>
|
||||
public class SizeAndChecksumsSection
|
||||
{
|
||||
[JsonProperty(PropertyName = "d_layerbreak", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public long Layerbreak { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_layerbreak_2", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public long Layerbreak2 { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_layerbreak_3", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public long Layerbreak3 { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "d_size", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public long Size { get; set; }
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
namespace DICUI.DiscImageCreator
|
||||
namespace MPF.DiscImageCreator
|
||||
{
|
||||
/// <summary>
|
||||
/// Top-level commands for DiscImageCreator
|
||||
/// </summary>
|
||||
public static class CommandStrings
|
||||
{
|
||||
public const string NONE = "";
|
||||
public const string Audio = "audio";
|
||||
public const string BluRay = "bd";
|
||||
public const string Close = "close";
|
||||
@@ -24,6 +25,7 @@ namespace DICUI.DiscImageCreator
|
||||
public const string Stop = "stop";
|
||||
public const string Sub = "sub";
|
||||
public const string Swap = "swap";
|
||||
public const string Tape = "tape";
|
||||
public const string XBOX = "xbox";
|
||||
public const string XBOXSwap = "xboxswap";
|
||||
public const string XGD2Swap = "xgd2swap";
|
||||
@@ -43,7 +45,10 @@ namespace DICUI.DiscImageCreator
|
||||
public const string CopyrightManagementInformation = "/c";
|
||||
public const string D8Opcode = "/d8";
|
||||
public const string DisableBeep = "/q";
|
||||
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";
|
||||
@@ -51,7 +56,9 @@ namespace DICUI.DiscImageCreator
|
||||
public const string NoFixSubRtoW = "/nr";
|
||||
public const string NoFixSubQSecuROM = "/ns";
|
||||
public const string NoSkipSS = "/nss";
|
||||
public const string PadSector = "/ps";
|
||||
public const string Raw = "/raw";
|
||||
public const string Resume = "/re";
|
||||
public const string Reverse = "/r";
|
||||
public const string ScanAntiMod = "/am";
|
||||
public const string ScanFileProtect = "/sf";
|
||||
@@ -59,6 +66,7 @@ namespace DICUI.DiscImageCreator
|
||||
public const string SeventyFour = "/74";
|
||||
public const string SkipSector = "/sk";
|
||||
public const string SubchannelReadLevel = "/s";
|
||||
public const string UseAnchorVolumeDescriptorPointer = "/avdp";
|
||||
public const string VideoNow = "/vn";
|
||||
public const string VideoNowColor = "/vnc";
|
||||
public const string VideoNowXP = "/vnx";
|
||||
124
MPF.Library/DiscImageCreator/Converters.cs
Normal file
124
MPF.Library/DiscImageCreator/Converters.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using MPF.Data;
|
||||
|
||||
namespace MPF.DiscImageCreator
|
||||
{
|
||||
public static class Converters
|
||||
{
|
||||
#region Cross-enumeration conversions
|
||||
|
||||
/// <summary>
|
||||
/// Get the most common known system for a given MediaType
|
||||
/// </summary>
|
||||
/// <param name="baseCommand">Command value to check</param>
|
||||
/// <returns>KnownSystem if possible, null on error</returns>
|
||||
public static KnownSystem? ToKnownSystem(string baseCommand)
|
||||
{
|
||||
switch (baseCommand)
|
||||
{
|
||||
case CommandStrings.Audio:
|
||||
return KnownSystem.AudioCD;
|
||||
case CommandStrings.CompactDisc:
|
||||
case CommandStrings.Data:
|
||||
case CommandStrings.DigitalVideoDisc:
|
||||
case CommandStrings.Disk:
|
||||
case CommandStrings.Floppy:
|
||||
case CommandStrings.Tape:
|
||||
return KnownSystem.IBMPCCompatible;
|
||||
case CommandStrings.GDROM:
|
||||
case CommandStrings.Swap:
|
||||
return KnownSystem.SegaDreamcast;
|
||||
case CommandStrings.BluRay:
|
||||
return KnownSystem.SonyPlayStation3;
|
||||
case CommandStrings.SACD:
|
||||
return KnownSystem.SuperAudioCD;
|
||||
case CommandStrings.XBOX:
|
||||
case CommandStrings.XBOXSwap:
|
||||
return KnownSystem.MicrosoftXBOX;
|
||||
case CommandStrings.XGD2Swap:
|
||||
case CommandStrings.XGD3Swap:
|
||||
return KnownSystem.MicrosoftXBOX360;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the MediaType associated with a given base command
|
||||
/// </summary>
|
||||
/// <param name="baseCommand">Command value to check</param>
|
||||
/// <returns>MediaType if possible, null on error</returns>
|
||||
/// <remarks>This takes the "safe" route by assuming the larger of any given format</remarks>
|
||||
public static MediaType? ToMediaType(string baseCommand)
|
||||
{
|
||||
switch (baseCommand)
|
||||
{
|
||||
case CommandStrings.Audio:
|
||||
case CommandStrings.CompactDisc:
|
||||
case CommandStrings.Data:
|
||||
case CommandStrings.SACD:
|
||||
return MediaType.CDROM;
|
||||
case CommandStrings.GDROM:
|
||||
case CommandStrings.Swap:
|
||||
return MediaType.GDROM;
|
||||
case CommandStrings.DigitalVideoDisc:
|
||||
case CommandStrings.XBOX:
|
||||
case CommandStrings.XBOXSwap:
|
||||
case CommandStrings.XGD2Swap:
|
||||
case CommandStrings.XGD3Swap:
|
||||
return MediaType.DVD;
|
||||
case CommandStrings.BluRay:
|
||||
return MediaType.BluRay;
|
||||
|
||||
// Non-optical
|
||||
case CommandStrings.Floppy:
|
||||
return MediaType.FloppyDisk;
|
||||
case CommandStrings.Disk:
|
||||
return MediaType.HardDisk;
|
||||
case CommandStrings.Tape:
|
||||
return MediaType.DataCartridge;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the default extension for a given disc type
|
||||
/// </summary>
|
||||
/// <param name="type">MediaType value to check</param>
|
||||
/// <returns>Valid extension (with leading '.'), null on error</returns>
|
||||
public static string Extension(MediaType? type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
case MediaType.GDROM:
|
||||
case MediaType.Cartridge:
|
||||
case MediaType.HardDisk:
|
||||
case MediaType.CompactFlash:
|
||||
case MediaType.MMC:
|
||||
case MediaType.SDCard:
|
||||
case MediaType.FlashDrive:
|
||||
return ".bin";
|
||||
case MediaType.DVD:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.BluRay:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return ".iso";
|
||||
case MediaType.LaserDisc:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
return ".raw";
|
||||
case MediaType.NintendoWiiUOpticalDisc:
|
||||
return ".wud";
|
||||
case MediaType.FloppyDisk:
|
||||
return ".img";
|
||||
case MediaType.Cassette:
|
||||
return ".wav";
|
||||
case MediaType.NONE:
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
3267
MPF.Library/DiscImageCreator/Parameters.cs
Normal file
3267
MPF.Library/DiscImageCreator/Parameters.cs
Normal file
File diff suppressed because it is too large
Load Diff
160
MPF.Library/Hashing/Hasher.cs
Normal file
160
MPF.Library/Hashing/Hasher.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using MPF.Data;
|
||||
using OptimizedCRC;
|
||||
|
||||
namespace MPF.Hashing
|
||||
{
|
||||
/// <summary>
|
||||
/// Async hashing class wraper
|
||||
/// </summary>
|
||||
public class Hasher
|
||||
{
|
||||
public Hash HashType { get; private set; }
|
||||
private IDisposable _hasher;
|
||||
|
||||
public Hasher(Hash hashType)
|
||||
{
|
||||
this.HashType = hashType;
|
||||
GetHasher();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the correct hashing class based on the hash type
|
||||
/// </summary>
|
||||
private void GetHasher()
|
||||
{
|
||||
switch (HashType)
|
||||
{
|
||||
case Hash.CRC:
|
||||
_hasher = new OptimizedCRC.OptimizedCRC();
|
||||
break;
|
||||
|
||||
case Hash.MD5:
|
||||
_hasher = MD5.Create();
|
||||
break;
|
||||
|
||||
case Hash.SHA1:
|
||||
_hasher = SHA1.Create();
|
||||
break;
|
||||
|
||||
case Hash.SHA256:
|
||||
_hasher = SHA256.Create();
|
||||
break;
|
||||
|
||||
case Hash.SHA384:
|
||||
_hasher = SHA384.Create();
|
||||
break;
|
||||
|
||||
case Hash.SHA512:
|
||||
_hasher = SHA512.Create();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_hasher.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process a buffer of some length with the internal hash algorithm
|
||||
/// </summary>
|
||||
public void Process(byte[] buffer, int size)
|
||||
{
|
||||
switch (HashType)
|
||||
{
|
||||
case Hash.CRC:
|
||||
(_hasher as OptimizedCRC.OptimizedCRC).Update(buffer, 0, size);
|
||||
break;
|
||||
|
||||
case Hash.MD5:
|
||||
case Hash.SHA1:
|
||||
case Hash.SHA256:
|
||||
case Hash.SHA384:
|
||||
case Hash.SHA512:
|
||||
(_hasher as HashAlgorithm).TransformBlock(buffer, 0, size, null, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalize the internal hash algorigthm
|
||||
/// </summary>
|
||||
public void Terminate()
|
||||
{
|
||||
byte[] emptyBuffer = new byte[0];
|
||||
switch (HashType)
|
||||
{
|
||||
case Hash.CRC:
|
||||
(_hasher as OptimizedCRC.OptimizedCRC).Update(emptyBuffer, 0, 0);
|
||||
break;
|
||||
|
||||
case Hash.MD5:
|
||||
case Hash.SHA1:
|
||||
case Hash.SHA256:
|
||||
case Hash.SHA384:
|
||||
case Hash.SHA512:
|
||||
(_hasher as HashAlgorithm).TransformFinalBlock(emptyBuffer, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get internal hash as a byte array
|
||||
/// </summary>
|
||||
public byte[] GetHash()
|
||||
{
|
||||
switch (HashType)
|
||||
{
|
||||
case Hash.CRC:
|
||||
return BitConverter.GetBytes((_hasher as OptimizedCRC.OptimizedCRC).Value).Reverse().ToArray();
|
||||
|
||||
case Hash.MD5:
|
||||
case Hash.SHA1:
|
||||
case Hash.SHA256:
|
||||
case Hash.SHA384:
|
||||
case Hash.SHA512:
|
||||
return (_hasher as HashAlgorithm).Hash;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get internal hash as a string
|
||||
/// </summary>
|
||||
public string GetHashString()
|
||||
{
|
||||
byte[] hash = GetHash();
|
||||
if (hash == null)
|
||||
return null;
|
||||
|
||||
return ByteArrayToString(hash);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a byte array to a hex string
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte array to convert</param>
|
||||
/// <returns>Hex string representing the byte array</returns>
|
||||
/// <link>http://stackoverflow.com/questions/311165/how-do-you-convert-byte-array-to-hexadecimal-string-and-vice-versa</link>
|
||||
private static string ByteArrayToString(byte[] bytes)
|
||||
{
|
||||
// If we get null in, we send null out
|
||||
if (bytes == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
string hex = BitConverter.ToString(bytes);
|
||||
return hex.Replace("-", string.Empty).ToLowerInvariant();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
153
MPF.Library/Hashing/OptimizedCRC.cs
Normal file
153
MPF.Library/Hashing/OptimizedCRC.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2012-2015 Eugene Larchenko (spct@mail.ru)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace OptimizedCRC
|
||||
{
|
||||
internal class OptimizedCRC : IDisposable
|
||||
{
|
||||
private const uint kCrcPoly = 0xEDB88320;
|
||||
private const uint kInitial = 0xFFFFFFFF;
|
||||
private const int CRC_NUM_TABLES = 8;
|
||||
private static readonly uint[] Table;
|
||||
|
||||
static OptimizedCRC()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
Table = new uint[256 * CRC_NUM_TABLES];
|
||||
int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
uint r = (uint)i;
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
|
||||
}
|
||||
Table[i] = r;
|
||||
}
|
||||
for (; i < 256 * CRC_NUM_TABLES; i++)
|
||||
{
|
||||
uint r = Table[i - 256];
|
||||
Table[i] = Table[r & 0xFF] ^ (r >> 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public uint UnsignedValue;
|
||||
|
||||
public OptimizedCRC()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset CRC
|
||||
/// </summary>
|
||||
public void Init()
|
||||
{
|
||||
UnsignedValue = kInitial;
|
||||
}
|
||||
|
||||
public int Value
|
||||
{
|
||||
get { return (int)~UnsignedValue; }
|
||||
}
|
||||
|
||||
public void Update(byte[] data, int offset, int count)
|
||||
{
|
||||
new ArraySegment<byte>(data, offset, count); // check arguments
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var table = OptimizedCRC.Table;
|
||||
|
||||
uint crc = UnsignedValue;
|
||||
|
||||
for (; (offset & 7) != 0 && count != 0; count--)
|
||||
{
|
||||
crc = (crc >> 8) ^ table[(byte)crc ^ data[offset++]];
|
||||
}
|
||||
|
||||
if (count >= 8)
|
||||
{
|
||||
/*
|
||||
* Idea from 7-zip project sources (http://7-zip.org/sdk.html)
|
||||
*/
|
||||
|
||||
int end = (count - 8) & ~7;
|
||||
count -= end;
|
||||
end += offset;
|
||||
|
||||
while (offset != end)
|
||||
{
|
||||
crc ^= (uint)(data[offset] + (data[offset + 1] << 8) + (data[offset + 2] << 16) + (data[offset + 3] << 24));
|
||||
uint high = (uint)(data[offset + 4] + (data[offset + 5] << 8) + (data[offset + 6] << 16) + (data[offset + 7] << 24));
|
||||
offset += 8;
|
||||
|
||||
crc = table[(byte)crc + 0x700]
|
||||
^ table[(byte)(crc >>= 8) + 0x600]
|
||||
^ table[(byte)(crc >>= 8) + 0x500]
|
||||
^ table[/*(byte)*/(crc >> 8) + 0x400]
|
||||
^ table[(byte)(high) + 0x300]
|
||||
^ table[(byte)(high >>= 8) + 0x200]
|
||||
^ table[(byte)(high >>= 8) + 0x100]
|
||||
^ table[/*(byte)*/(high >> 8) + 0x000];
|
||||
}
|
||||
}
|
||||
|
||||
while (count-- != 0)
|
||||
{
|
||||
crc = (crc >> 8) ^ table[(byte)crc ^ data[offset++]];
|
||||
}
|
||||
|
||||
UnsignedValue = crc;
|
||||
}
|
||||
|
||||
static public int Compute(byte[] data, int offset, int count)
|
||||
{
|
||||
var crc = new OptimizedCRC();
|
||||
crc.Update(data, offset, count);
|
||||
return crc.Value;
|
||||
}
|
||||
|
||||
static public int Compute(byte[] data)
|
||||
{
|
||||
return Compute(data, 0, data.Length);
|
||||
}
|
||||
|
||||
static public int Compute(ArraySegment<byte> block)
|
||||
{
|
||||
return Compute(block.Array, block.Offset, block.Count);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
UnsignedValue = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
79
MPF.Library/Hashing/ThreadLoadBuffer.cs
Normal file
79
MPF.Library/Hashing/ThreadLoadBuffer.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace Compress.ThreadReaders
|
||||
{
|
||||
public class ThreadLoadBuffer : IDisposable
|
||||
{
|
||||
private readonly AutoResetEvent _waitEvent;
|
||||
private readonly AutoResetEvent _outEvent;
|
||||
private readonly Thread _tWorker;
|
||||
|
||||
private byte[] _buffer;
|
||||
private int _size;
|
||||
private readonly Stream _ds;
|
||||
private bool _finished;
|
||||
public bool errorState;
|
||||
|
||||
public int SizeRead;
|
||||
|
||||
public ThreadLoadBuffer(Stream ds)
|
||||
{
|
||||
_waitEvent = new AutoResetEvent(false);
|
||||
_outEvent = new AutoResetEvent(false);
|
||||
_finished = false;
|
||||
_ds = ds;
|
||||
errorState = false;
|
||||
|
||||
_tWorker = new Thread(MainLoop);
|
||||
_tWorker.Start();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_waitEvent.Close();
|
||||
_outEvent.Close();
|
||||
}
|
||||
|
||||
private void MainLoop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
_waitEvent.WaitOne();
|
||||
if (_finished)
|
||||
{
|
||||
break;
|
||||
}
|
||||
try
|
||||
{
|
||||
SizeRead = _ds.Read(_buffer, 0, _size);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorState = true;
|
||||
}
|
||||
_outEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
public void Trigger(byte[] buffer, int size)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_size = size;
|
||||
_waitEvent.Set();
|
||||
}
|
||||
|
||||
public void Wait()
|
||||
{
|
||||
_outEvent.WaitOne();
|
||||
}
|
||||
|
||||
public void Finish()
|
||||
{
|
||||
_finished = true;
|
||||
_waitEvent.Set();
|
||||
_tWorker.Join();
|
||||
}
|
||||
}
|
||||
}
|
||||
97
MPF.Library/MPF.Library.csproj
Normal file
97
MPF.Library/MPF.Library.csproj
Normal file
@@ -0,0 +1,97 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net48;netcoreapp3.1</TargetFrameworks>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<Title>MPF Library</Title>
|
||||
<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>
|
||||
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
|
||||
<Version>2.1</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>
|
||||
|
||||
<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>
|
||||
|
||||
<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">
|
||||
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<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">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="$(PkgBurnOutSharp)\content\**" PackagePath="contentFiles\any\any;content" CopyToOutputDirectory="Always" PackageCopyToOutput="true" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Management" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,15 +1,18 @@
|
||||
using DICUI.Data;
|
||||
using MPF.Data;
|
||||
|
||||
namespace DICUI.Utilities
|
||||
namespace MPF.Redump
|
||||
{
|
||||
public static class Extensions
|
||||
/// <summary>
|
||||
/// Information pertaining to Redump systems
|
||||
/// </summary>
|
||||
public static class Extras
|
||||
{
|
||||
#region Redump Information Lists
|
||||
#region Special lists
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that are not publically accessible
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem[] BannedSystems = new RedumpSystem[]
|
||||
public static readonly RedumpSystem?[] BannedSystems = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.AudioCD,
|
||||
RedumpSystem.BDVideo,
|
||||
@@ -21,24 +24,27 @@ namespace DICUI.Utilities
|
||||
RedumpSystem.KonamiM2,
|
||||
RedumpSystem.MicrosoftXbox360,
|
||||
RedumpSystem.MicrosoftXboxOne,
|
||||
//RedumpSystem.MicrosoftXboxSeriesXS,
|
||||
RedumpSystem.NavisoftNaviken21,
|
||||
RedumpSystem.NintendoWii,
|
||||
RedumpSystem.NintendoWiiU,
|
||||
RedumpSystem.PanasonicM2,
|
||||
RedumpSystem.PhilipsCDiDigitalVideo,
|
||||
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[]
|
||||
public static readonly RedumpSystem?[] HasCues = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.AppleMacintosh,
|
||||
RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem,
|
||||
RedumpSystem.AudioCD,
|
||||
RedumpSystem.BandaiPippin,
|
||||
RedumpSystem.BandaiPlaydiaQuickInteractiveSystem,
|
||||
@@ -46,28 +52,33 @@ namespace DICUI.Utilities
|
||||
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.NECPCEngineCDTurboGrafxCD,
|
||||
RedumpSystem.NECPCFXPCFXGA,
|
||||
RedumpSystem.PalmOS,
|
||||
RedumpSystem.Panasonic3DOInteractiveMultiplayer,
|
||||
RedumpSystem.PanasonicM2,
|
||||
RedumpSystem.PhilipsCDi,
|
||||
RedumpSystem.PhilipsCDiDigitalVideo,
|
||||
RedumpSystem.PhotoCD,
|
||||
RedumpSystem.PlayStationGameSharkUpdates,
|
||||
RedumpSystem.SegaChihiro,
|
||||
@@ -75,8 +86,8 @@ namespace DICUI.Utilities
|
||||
RedumpSystem.SegaMegaCDSegaCD,
|
||||
RedumpSystem.SegaNaomi,
|
||||
RedumpSystem.SegaNaomi2,
|
||||
RedumpSystem.SegaPrologue21,
|
||||
RedumpSystem.SegaSaturn,
|
||||
RedumpSystem.SegaTriforce,
|
||||
RedumpSystem.SNKNeoGeoCD,
|
||||
RedumpSystem.SonyPlayStation,
|
||||
RedumpSystem.SonyPlayStation2,
|
||||
@@ -90,7 +101,7 @@ namespace DICUI.Utilities
|
||||
/// <summary>
|
||||
/// List of systems that has a Dat pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem[] HasDat = new RedumpSystem[]
|
||||
public static readonly RedumpSystem?[] HasDat = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.MicrosoftXboxBIOS,
|
||||
RedumpSystem.NintendoGameCubeBIOS,
|
||||
@@ -98,41 +109,48 @@ namespace DICUI.Utilities
|
||||
RedumpSystem.SonyPlayStation2BIOS,
|
||||
|
||||
RedumpSystem.AppleMacintosh,
|
||||
RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem,
|
||||
RedumpSystem.AudioCD,
|
||||
RedumpSystem.BDVideo,
|
||||
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.KonamieAmusement,
|
||||
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.NECPCEngineCDTurboGrafxCD,
|
||||
RedumpSystem.NECPCFXPCFXGA,
|
||||
RedumpSystem.NinendoGameCube,
|
||||
RedumpSystem.NintendoGameCube,
|
||||
RedumpSystem.NintendoWii,
|
||||
RedumpSystem.NintendoWiiU,
|
||||
RedumpSystem.PalmOS,
|
||||
RedumpSystem.Panasonic3DOInteractiveMultiplayer,
|
||||
RedumpSystem.PanasonicM2,
|
||||
RedumpSystem.PhilipsCDi,
|
||||
RedumpSystem.PhilipsCDiDigitalVideo,
|
||||
RedumpSystem.PhotoCD,
|
||||
RedumpSystem.PlayStationGameSharkUpdates,
|
||||
RedumpSystem.SegaChihiro,
|
||||
@@ -144,12 +162,12 @@ namespace DICUI.Utilities
|
||||
RedumpSystem.SegaRingEdge,
|
||||
RedumpSystem.SegaRingEdge2,
|
||||
RedumpSystem.SegaSaturn,
|
||||
RedumpSystem.SegaTriforce,
|
||||
RedumpSystem.SNKNeoGeoCD,
|
||||
RedumpSystem.SonyPlayStation,
|
||||
RedumpSystem.SonyPlayStation2,
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
RedumpSystem.SonyPlayStation4,
|
||||
//RedumpSystem.SonyPlayStation5,
|
||||
RedumpSystem.SonyPlayStationPortable,
|
||||
RedumpSystem.TABAustriaQuizard,
|
||||
RedumpSystem.TomyKissSite,
|
||||
@@ -162,7 +180,7 @@ namespace DICUI.Utilities
|
||||
/// <summary>
|
||||
/// List of systems that has a Decrypted Keys pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem[] HasDkeys = new RedumpSystem[]
|
||||
public static readonly RedumpSystem?[] HasDkeys = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
};
|
||||
@@ -170,19 +188,19 @@ namespace DICUI.Utilities
|
||||
/// <summary>
|
||||
/// List of systems that has a GDI pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem[] HasGdi = new RedumpSystem[]
|
||||
public static readonly RedumpSystem?[] HasGdi = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.NamcoSegaNintendoTriforce,
|
||||
RedumpSystem.SegaChihiro,
|
||||
RedumpSystem.SegaDreamcast,
|
||||
RedumpSystem.SegaNaomi,
|
||||
RedumpSystem.SegaNaomi2,
|
||||
RedumpSystem.SegaTriforce,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that has a Keys pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem[] HasKeys = new RedumpSystem[]
|
||||
public static readonly RedumpSystem?[] HasKeys = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.NintendoWiiU,
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
@@ -191,7 +209,7 @@ namespace DICUI.Utilities
|
||||
/// <summary>
|
||||
/// List of systems that has an LSD pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem[] HasLsd = new RedumpSystem[]
|
||||
public static readonly RedumpSystem?[] HasLsd = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.IBMPCcompatible,
|
||||
RedumpSystem.SonyPlayStation,
|
||||
@@ -200,62 +218,12 @@ namespace DICUI.Utilities
|
||||
/// <summary>
|
||||
/// List of systems that has an SBI pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem[] HasSbi = new RedumpSystem[]
|
||||
public static readonly RedumpSystem?[] HasSbi = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.IBMPCcompatible,
|
||||
RedumpSystem.SonyPlayStation,
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
public static bool DoesSupportDriveSpeed(this MediaType? type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
case MediaType.DVD:
|
||||
case MediaType.GDROM:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.BluRay:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static KnownSystemCategory Category(this KnownSystem? system)
|
||||
{
|
||||
if (system < KnownSystem.MarkerDiscBasedConsoleEnd)
|
||||
return KnownSystemCategory.DiscBasedConsole;
|
||||
/*
|
||||
else if (system < KnownSystem.MarkerOtherConsoleEnd)
|
||||
return KnownSystemCategory.OtherConsole;
|
||||
*/
|
||||
else if (system < KnownSystem.MarkerComputerEnd)
|
||||
return KnownSystemCategory.Computer;
|
||||
else if (system < KnownSystem.MarkerArcadeEnd)
|
||||
return KnownSystemCategory.Arcade;
|
||||
else if (system < KnownSystem.MarkerOtherEnd)
|
||||
return KnownSystemCategory.Other;
|
||||
else
|
||||
return KnownSystemCategory.Custom;
|
||||
}
|
||||
|
||||
public static bool IsMarker(this KnownSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case KnownSystem.MarkerArcadeEnd:
|
||||
case KnownSystem.MarkerComputerEnd:
|
||||
case KnownSystem.MarkerDiscBasedConsoleEnd:
|
||||
// case KnownSystem.MarkerOtherConsoleEnd:
|
||||
case KnownSystem.MarkerOtherEnd:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1588
MPF.Library/Redump/RedumpWebClient.cs
Normal file
1588
MPF.Library/Redump/RedumpWebClient.cs
Normal file
File diff suppressed because it is too large
Load Diff
218
MPF.Library/UmdImageCreator/Parameters.cs
Normal file
218
MPF.Library/UmdImageCreator/Parameters.cs
Normal file
@@ -0,0 +1,218 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MPF.Data;
|
||||
|
||||
namespace MPF.UmdImageCreator
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic set of UmdImageCreator parameters
|
||||
/// </summary>
|
||||
public class Parameters : BaseParameters
|
||||
{
|
||||
#region Metadata
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override InternalProgram InternalProgram => InternalProgram.UmdImageCreator;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(string parameters) : base(parameters) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
: base(system, type, driveLetter, filename, driveSpeed, options)
|
||||
{
|
||||
}
|
||||
|
||||
#region BaseParameters Implementations
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override (bool, List<string>) CheckAllOutputFilesExist(string basePath, bool preCheck)
|
||||
{
|
||||
List<string> missingFiles = new List<string>();
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.UMD:
|
||||
if (!File.Exists($"{basePath}_logs.zip") || !preCheck)
|
||||
{
|
||||
if (!File.Exists($"{basePath}_disc.txt"))
|
||||
missingFiles.Add($"{basePath}_disc.txt");
|
||||
if (!File.Exists($"{basePath}_mainError.txt"))
|
||||
missingFiles.Add($"{basePath}_mainError.txt");
|
||||
if (!File.Exists($"{basePath}_mainInfo.txt"))
|
||||
missingFiles.Add($"{basePath}_mainInfo.txt");
|
||||
if (!File.Exists($"{basePath}_volDesc.txt"))
|
||||
missingFiles.Add($"{basePath}_volDesc.txt");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return (false, missingFiles);
|
||||
}
|
||||
|
||||
return (!missingFiles.Any(), missingFiles);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive, bool includeArtifacts)
|
||||
{
|
||||
// Extract info based generically on MediaType
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.UMD:
|
||||
info.Extras.PVD = GetPVD(basePath + "_mainInfo.txt") ?? "";
|
||||
|
||||
if (GetFileHashes(basePath + ".iso", out long filesize, out string crc32, out string md5, out string sha1))
|
||||
{
|
||||
info.SizeAndChecksums.Size = filesize;
|
||||
info.SizeAndChecksums.CRC32 = crc32;
|
||||
info.SizeAndChecksums.MD5 = md5;
|
||||
info.SizeAndChecksums.SHA1 = sha1;
|
||||
}
|
||||
|
||||
if (GetUMDAuxInfo(basePath + "_disc.txt", out string title, out RedumpDiscCategory? 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.SizeAndChecksums.Size = umdsize;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(umdlayer))
|
||||
info.SizeAndChecksums.Layerbreak = Int64.Parse(umdlayer ?? "-1");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill in any artifacts that exist, Base64-encoded, if we need to
|
||||
if (includeArtifacts)
|
||||
{
|
||||
if (File.Exists(basePath + "_disc.txt"))
|
||||
info.Artifacts["disc"] = GetBase64(GetFullFile(basePath + "_disc.txt"));
|
||||
if (File.Exists(basePath + "_mainError.txt"))
|
||||
info.Artifacts["mainError"] = GetBase64(GetFullFile(basePath + "_mainError.txt"));
|
||||
if (File.Exists(basePath + "_mainInfo.txt"))
|
||||
info.Artifacts["mainInfo"] = GetBase64(GetFullFile(basePath + "_mainInfo.txt"));
|
||||
if (File.Exists(basePath + "_volDesc.txt"))
|
||||
info.Artifacts["volDesc"] = GetBase64(GetFullFile(basePath + "_volDesc.txt"));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<string> GetLogFilePaths(string basePath)
|
||||
{
|
||||
List<string> logFiles = new List<string>();
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.UMD:
|
||||
if (File.Exists($"{basePath}_disc.txt"))
|
||||
logFiles.Add($"{basePath}_disc.txt");
|
||||
if (File.Exists($"{basePath}_mainError.txt"))
|
||||
logFiles.Add($"{basePath}_mainError.txt");
|
||||
if (File.Exists($"{basePath}_mainInfo.txt"))
|
||||
logFiles.Add($"{basePath}_mainInfo.txt");
|
||||
if (File.Exists($"{basePath}_volDesc.txt"))
|
||||
logFiles.Add($"{basePath}_volDesc.txt");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return logFiles;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Information Extraction Methods
|
||||
|
||||
/// <summary>
|
||||
/// Get the PVD from the input file, if possible
|
||||
/// </summary>
|
||||
/// <param name="mainInfo">_mainInfo.txt file location</param>
|
||||
/// <returns>Newline-deliminated PVD if possible, null on error</returns>
|
||||
private static string GetPVD(string mainInfo)
|
||||
{
|
||||
// If the file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(mainInfo))
|
||||
return null;
|
||||
|
||||
using (StreamReader sr = File.OpenText(mainInfo))
|
||||
{
|
||||
try
|
||||
{
|
||||
// Make sure we're in the right sector
|
||||
while (!sr.ReadLine().StartsWith("========== LBA[000016, 0x0000010]: Main Channel ==========")) ;
|
||||
|
||||
// Fast forward to the PVD
|
||||
while (!sr.ReadLine().StartsWith("0310")) ;
|
||||
|
||||
// Now that we're at the PVD, read each line in and concatenate
|
||||
string pvd = "";
|
||||
for (int i = 0; i < 6; i++)
|
||||
pvd += sr.ReadLine() + "\n"; // 320-370
|
||||
|
||||
return pvd;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the exception is right now
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the UMD auxiliary info from the outputted files, if possible
|
||||
/// </summary>
|
||||
/// <param name="disc">_disc.txt file location</param>
|
||||
/// <returns>True on successful extraction of info, false otherwise</returns>
|
||||
private static bool GetUMDAuxInfo(string disc, out string title, out RedumpDiscCategory? umdcat, out string umdversion, out string umdlayer, out long umdsize)
|
||||
{
|
||||
title = null; umdcat = null; umdversion = null; umdlayer = null; umdsize = -1;
|
||||
|
||||
// If the file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(disc))
|
||||
return false;
|
||||
|
||||
using (StreamReader sr = File.OpenText(disc))
|
||||
{
|
||||
try
|
||||
{
|
||||
// Loop through everything to get the first instance of each required field
|
||||
string line = string.Empty;
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
line = sr.ReadLine().Trim();
|
||||
|
||||
if (line.StartsWith("TITLE") && title == null)
|
||||
title = line.Substring("TITLE: ".Length);
|
||||
else if (line.StartsWith("DISC_VERSION") && umdversion == null)
|
||||
umdversion = line.Split(' ')[1];
|
||||
else if (line.StartsWith("pspUmdTypes"))
|
||||
umdcat = GetUMDCategory(line.Split(' ')[1]);
|
||||
else if (line.StartsWith("L0 length"))
|
||||
umdlayer = line.Split(' ')[2];
|
||||
else if (line.StartsWith("FileSize:"))
|
||||
umdsize = Int64.Parse(line.Split(' ')[1]);
|
||||
}
|
||||
|
||||
// If the L0 length is the size of the full disc, there's no layerbreak
|
||||
if (Int64.Parse(umdlayer) * 2048 == umdsize)
|
||||
umdlayer = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the exception is right now
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
174
MPF.Library/Utilities/BinaryReaderExtensions.cs
Normal file
174
MPF.Library/Utilities/BinaryReaderExtensions.cs
Normal file
@@ -0,0 +1,174 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace MPF.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Big endian reading overloads for BinaryReader
|
||||
/// </summary>
|
||||
internal static class BinaryReaderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads the specified number of bytes from the stream, starting from a specified point in the byte array.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to read data into.</param>
|
||||
/// <param name="index">The starting point in the buffer at which to begin reading into the buffer.</param>
|
||||
/// <param name="count">The number of bytes to read.</param>
|
||||
/// <returns>The number of bytes read into buffer. This might be less than the number of bytes requested if that many bytes are not available, or it might be zero if the end of the stream is reached.</returns>
|
||||
public static int ReadBigEndian(this BinaryReader reader, byte[] buffer, int index, int count)
|
||||
{
|
||||
int retval = reader.Read(buffer, index, count);
|
||||
Array.Reverse(buffer);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of characters from the stream, starting from a specified point in the character array.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to read data into.</param>
|
||||
/// <param name="index">The starting point in the buffer at which to begin reading into the buffer.</param>
|
||||
/// <param name="count">The number of characters to read.</param>
|
||||
/// <returns>The total number of characters read into the buffer. This might be less than the number of characters requested if that many characters are not currently available, or it might be zero if the end of the stream is reached.</returns>
|
||||
public static int ReadBigEndian(this BinaryReader reader, char[] buffer, int index, int count)
|
||||
{
|
||||
int retval = reader.Read(buffer, index, count);
|
||||
Array.Reverse(buffer);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of bytes from the current stream into a byte array and advances the current position by that number of bytes.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of bytes to read. This value must be 0 or a non-negative number or an exception will occur.</param>
|
||||
/// <returns>A byte array containing data read from the underlying stream. This might be less than the number of bytes requested if the end of the stream is reached.</returns>
|
||||
public static byte[] ReadBytesBigEndian(this BinaryReader reader, int count)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(count);
|
||||
Array.Reverse(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of characters from the current stream, returns the data in a character array, and advances the current position in accordance with the Encoding used and the specific character being read from the stream.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of characters to read. This value must be 0 or a non-negative number or an exception will occur.</param>
|
||||
/// <returns>A character array containing data read from the underlying stream. This might be less than the number of bytes requested if the end of the stream is reached.</returns>
|
||||
public static char[] ReadCharsBigEndian(this BinaryReader reader, int count)
|
||||
{
|
||||
char[] retval = reader.ReadChars(count);
|
||||
Array.Reverse(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a decimal value from the current stream and advances the current position of the stream by sixteen bytes.
|
||||
/// </summary>
|
||||
/// <returns>A decimal value read from the current stream.</returns>
|
||||
public static decimal ReadDecimalBigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(16);
|
||||
Array.Reverse(retval);
|
||||
|
||||
int i1 = BitConverter.ToInt32(retval, 0);
|
||||
int i2 = BitConverter.ToInt32(retval, 4);
|
||||
int i3 = BitConverter.ToInt32(retval, 8);
|
||||
int i4 = BitConverter.ToInt32(retval, 12);
|
||||
|
||||
return new decimal(new int[] { i1, i2, i3, i4 });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// eads an 8-byte floating point value from the current stream and advances the current position of the stream by eight bytes.
|
||||
/// </summary>
|
||||
/// <returns>An 8-byte floating point value read from the current stream.</returns>
|
||||
public static double ReadDoubleBigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(8);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToDouble(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 2-byte signed integer from the current stream and advances the current position of the stream by two bytes.
|
||||
/// </summary>
|
||||
/// <returns>A 2-byte signed integer read from the current stream.</returns>
|
||||
public static short ReadInt16BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(2);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToInt16(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 4-byte signed integer from the current stream and advances the current position of the stream by four bytes.
|
||||
/// </summary>
|
||||
/// <returns>A 4-byte signed integer read from the current stream.</returns>
|
||||
public static int ReadInt32BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(4);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToInt32(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an 8-byte signed integer from the current stream and advances the current position of the stream by eight bytes.
|
||||
/// </summary>
|
||||
/// <returns>An 8-byte signed integer read from the current stream.</returns>
|
||||
public static long ReadInt64BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(8);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToInt64(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 4-byte floating point value from the current stream and advances the current position of the stream by four bytes.
|
||||
/// </summary>
|
||||
/// <returns>A 4-byte floating point value read from the current stream.</returns>
|
||||
public static float ReadSingleBigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(4);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToSingle(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 2-byte unsigned integer from the current stream using little-endian encoding and advances the position of the stream by two bytes.
|
||||
///
|
||||
/// This API is not CLS-compliant.
|
||||
/// </summary>
|
||||
/// <returns>A 2-byte unsigned integer read from this stream.</returns>
|
||||
public static ushort ReadUInt16BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(2);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToUInt16(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 4-byte unsigned integer from the current stream and advances the position of the stream by four bytes.
|
||||
///
|
||||
/// This API is not CLS-compliant.
|
||||
/// </summary>
|
||||
/// <returns>A 4-byte unsigned integer read from this stream.</returns>
|
||||
public static uint ReadUInt32BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(4);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToUInt32(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an 8-byte unsigned integer from the current stream and advances the position of the stream by eight bytes.
|
||||
///
|
||||
/// This API is not CLS-compliant.
|
||||
/// </summary>
|
||||
/// <returns>An 8-byte unsigned integer read from this stream.</returns>
|
||||
public static ulong ReadUInt64BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(8);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToUInt64(retval, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
119
MPF.Library/Utilities/EnumExtensions.cs
Normal file
119
MPF.Library/Utilities/EnumExtensions.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
122
MPF.Library/Utilities/Logging.cs
Normal file
122
MPF.Library/Utilities/Logging.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MPF.Utilities
|
||||
{
|
||||
internal static class Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Process a chunk of text and send it to a handler
|
||||
/// </summary>
|
||||
/// <param name="reader">TextReader representing the input</param>
|
||||
/// <param name="baseClass">Invoking class, passed on to the event handler</param>
|
||||
/// <param name="handler">Event handler to be invoked to write to log</param>
|
||||
public static async Task OutputToLog(TextReader reader, object baseClass, EventHandler<string> handler)
|
||||
{
|
||||
// Initialize the required variables
|
||||
char[] buffer = new char[256];
|
||||
int read = 0;
|
||||
var sb = new StringBuilder();
|
||||
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Try to read the next chunk of characters
|
||||
read = await reader.ReadAsync(buffer, 0, buffer.Length);
|
||||
if (read == 0)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert the characters into a string
|
||||
string line = new string(buffer, 0, read);
|
||||
|
||||
// If we have no newline characters, store in the string builder
|
||||
if (!line.Contains('\r') && !line.Contains('\n'))
|
||||
sb.Append(line);
|
||||
|
||||
// If we have a newline, append and log
|
||||
else if (line.Contains('\n') || line.Contains("\r\n"))
|
||||
ProcessNewLines(sb, line, baseClass, handler);
|
||||
|
||||
// If we have a carriage return only, append and log first and last instances
|
||||
else if (line.Contains('\r'))
|
||||
ProcessCarriageReturns(sb, line, baseClass, handler);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
handler?.Invoke(baseClass, sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process a chunk that contains newlines
|
||||
/// </summary>
|
||||
/// <param name="sb">StringBuilder to write from and append to</param>
|
||||
/// <param name="line">Current line to process</param>
|
||||
/// <param name="baseClass">Invoking class, passed on to the event handler</param>
|
||||
/// <param name="handler">Event handler to be invoked to write to log</param>
|
||||
private static void ProcessNewLines(StringBuilder sb, string line, object baseClass, EventHandler<string> handler)
|
||||
{
|
||||
line = line.Replace("\r\n", "\n");
|
||||
var split = line.Split('\n');
|
||||
for (int i = 0; i < split.Length; i++)
|
||||
{
|
||||
// If the chunk contains a carriage return, handle it like a separate line
|
||||
if (split[i].Contains('\r'))
|
||||
{
|
||||
ProcessCarriageReturns(sb, split[i], baseClass, handler);
|
||||
continue;
|
||||
}
|
||||
|
||||
// For the first item, append to anything existing and then write out
|
||||
if (i == 0)
|
||||
{
|
||||
sb.Append(split[i]);
|
||||
handler?.Invoke(baseClass, sb.ToString());
|
||||
sb.Clear();
|
||||
}
|
||||
|
||||
// For the last item, just append so it's dealt with the next time
|
||||
else if (i == split.Length - 1)
|
||||
{
|
||||
sb.Append(split[i]);
|
||||
}
|
||||
|
||||
// For everything else, directly write out
|
||||
else
|
||||
{
|
||||
handler?.Invoke(baseClass, split[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process a chunk that contains carriage returns
|
||||
/// </summary>
|
||||
/// <param name="sb">StringBuilder to write from and append to</param>
|
||||
/// <param name="line">Current line to process</param>
|
||||
/// <param name="baseClass">Invoking class, passed on to the event handler</param>
|
||||
/// <param name="handler">Event handler to be invoked to write to log</param>
|
||||
private static void ProcessCarriageReturns(StringBuilder sb, string line, object baseClass, EventHandler<string> handler)
|
||||
{
|
||||
var split = line.Split('\r');
|
||||
|
||||
// Append and log the first
|
||||
sb.Append(split[0]);
|
||||
handler?.Invoke(baseClass, sb.ToString());
|
||||
|
||||
// Append the last
|
||||
sb.Clear();
|
||||
sb.Append($"\r{split[split.Length - 1]}");
|
||||
}
|
||||
}
|
||||
}
|
||||
116
MPF.Library/Utilities/Tools.cs
Normal file
116
MPF.Library/Utilities/Tools.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,12 @@ using System.Linq;
|
||||
using System.Management;
|
||||
using System.Threading.Tasks;
|
||||
using BurnOutSharp;
|
||||
using DICUI.Data;
|
||||
using MPF.Data;
|
||||
#if NET_FRAMEWORK
|
||||
using IMAPI2;
|
||||
#endif
|
||||
|
||||
namespace DICUI.Utilities
|
||||
namespace MPF.Utilities
|
||||
{
|
||||
public static class Validators
|
||||
{
|
||||
@@ -84,6 +84,10 @@ namespace DICUI.Utilities
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
case KnownSystem.MattelFisherPriceiXL:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/HyperScan
|
||||
case KnownSystem.MattelHyperscan:
|
||||
types.Add(MediaType.CDROM);
|
||||
@@ -91,14 +95,14 @@ namespace DICUI.Utilities
|
||||
|
||||
// https://en.wikipedia.org/wiki/Xbox_(console)
|
||||
case KnownSystem.MicrosoftXBOX:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Xbox_360
|
||||
case KnownSystem.MicrosoftXBOX360:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Xbox_One
|
||||
@@ -106,6 +110,11 @@ namespace DICUI.Utilities
|
||||
types.Add(MediaType.BluRay);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Xbox_Series_X_and_Series_S
|
||||
case KnownSystem.MicrosoftXboxSeriesXS:
|
||||
types.Add(MediaType.BluRay);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/TurboGrafx-16
|
||||
case KnownSystem.NECPCEngineTurboGrafxCD:
|
||||
types.Add(MediaType.CDROM);
|
||||
@@ -118,6 +127,7 @@ namespace DICUI.Utilities
|
||||
|
||||
// https://en.wikipedia.org/wiki/GameCube
|
||||
case KnownSystem.NintendoGameCube:
|
||||
types.Add(MediaType.DVD); // Only added here to help users; not strictly correct
|
||||
types.Add(MediaType.NintendoGameCubeGameDisc);
|
||||
break;
|
||||
|
||||
@@ -128,6 +138,7 @@ namespace DICUI.Utilities
|
||||
|
||||
// https://en.wikipedia.org/wiki/Wii
|
||||
case KnownSystem.NintendoWii:
|
||||
types.Add(MediaType.DVD); // Only added here to help users; not strictly correct
|
||||
types.Add(MediaType.NintendoWiiOpticalDisc);
|
||||
break;
|
||||
|
||||
@@ -196,6 +207,11 @@ namespace DICUI.Utilities
|
||||
types.Add(MediaType.BluRay);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/PlayStation_5
|
||||
case KnownSystem.SonyPlayStation5:
|
||||
types.Add(MediaType.BluRay);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/PlayStation_Portable
|
||||
case KnownSystem.SonyPlayStationPortable:
|
||||
types.Add(MediaType.UMD);
|
||||
@@ -256,8 +272,10 @@ namespace DICUI.Utilities
|
||||
case KnownSystem.IBMPCCompatible:
|
||||
types.Add(MediaType.CDROM);
|
||||
types.Add(MediaType.DVD);
|
||||
types.Add(MediaType.BluRay);
|
||||
types.Add(MediaType.FloppyDisk);
|
||||
types.Add(MediaType.HardDisk);
|
||||
types.Add(MediaType.DataCartridge);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/PC-8800_series
|
||||
@@ -611,6 +629,11 @@ namespace DICUI.Utilities
|
||||
types.Add(MediaType.BluRay);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/DVD-Audio
|
||||
case KnownSystem.DVDAudio:
|
||||
types.Add(MediaType.DVD);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/DVD-Video
|
||||
case KnownSystem.DVDVideo:
|
||||
types.Add(MediaType.DVD);
|
||||
@@ -636,11 +659,6 @@ namespace DICUI.Utilities
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// UNKNOWN
|
||||
case KnownSystem.PhilipsCDiDigitalVideo:
|
||||
types.Add(MediaType.CDROM);
|
||||
break;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Photo_CD
|
||||
case KnownSystem.PhotoCD:
|
||||
types.Add(MediaType.CDROM);
|
||||
@@ -692,18 +710,6 @@ namespace DICUI.Utilities
|
||||
return types;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a list of systems
|
||||
/// </summary>
|
||||
/// <returns>KnownSystems, if possible</returns>
|
||||
public static List<KnownSystem?> CreateListOfSystems()
|
||||
{
|
||||
return Enum.GetValues(typeof(KnownSystem))
|
||||
.OfType<KnownSystem?>()
|
||||
.Where(s => !s.IsMarker() && s != KnownSystem.NONE)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a list of active drives matched to their volume labels
|
||||
/// </summary>
|
||||
@@ -763,22 +769,24 @@ namespace DICUI.Utilities
|
||||
/// <param name="drive"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// https://stackoverflow.com/questions/11420365/detecting-if-disc-is-in-dvd-drive
|
||||
/// This may eventually be replaced by Aaru.Devices being able to be about 10x more accurate.
|
||||
/// This will also end up making it so that IMAPI2 is no longer necessary. Unfortunately, that
|
||||
/// will only work for .NET Core 3.1 and beyond.
|
||||
/// </remarks>
|
||||
public static MediaType? GetMediaType(Drive drive)
|
||||
public static (MediaType?, string) GetMediaType(Drive drive)
|
||||
{
|
||||
// Take care of the non-optical stuff first
|
||||
// TODO: See if any of these can be more granular, like Optical is
|
||||
if (drive.InternalDriveType == InternalDriveType.Floppy)
|
||||
return MediaType.FloppyDisk;
|
||||
return (MediaType.FloppyDisk, null);
|
||||
else if (drive.InternalDriveType == InternalDriveType.HardDisk)
|
||||
return MediaType.HardDisk;
|
||||
return (MediaType.HardDisk, null);
|
||||
else if (drive.InternalDriveType == InternalDriveType.Removable)
|
||||
return MediaType.FlashDrive;
|
||||
return (MediaType.FlashDrive, null);
|
||||
|
||||
// Get the DeviceID and MediaType from the current drive letter
|
||||
// Get the current drive information
|
||||
string deviceId = null;
|
||||
ushort mediaType = 0;
|
||||
bool loaded = false;
|
||||
try
|
||||
{
|
||||
// Get the device ID first
|
||||
@@ -789,15 +797,18 @@ namespace DICUI.Utilities
|
||||
foreach (ManagementObject queryObj in searcher.Get())
|
||||
{
|
||||
deviceId = (string)queryObj["DeviceID"];
|
||||
loaded = (bool)queryObj["MediaLoaded"];
|
||||
}
|
||||
|
||||
// If we got no valid device, we don't care and just return
|
||||
if (deviceId == null)
|
||||
return null;
|
||||
return (null, "Device could not be found");
|
||||
else if (!loaded)
|
||||
return (null, "Device is not reporting media loaded");
|
||||
|
||||
#if NET_FRAMEWORK
|
||||
MsftDiscMaster2 discMaster = new MsftDiscMaster2();
|
||||
deviceId = deviceId.ToLower().Replace('\\', '#');
|
||||
deviceId = deviceId.ToLower().Replace('\\', '#').Replace('/', '#');
|
||||
string id = null;
|
||||
foreach (var disc in discMaster)
|
||||
{
|
||||
@@ -807,39 +818,34 @@ namespace DICUI.Utilities
|
||||
|
||||
// If we couldn't find the drive, we don't care and return
|
||||
if (id == null)
|
||||
return null;
|
||||
return (null, "Device ID could not be found");
|
||||
|
||||
// Otherwise, we get the media type, if any
|
||||
// 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;
|
||||
if (media != IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_UNKNOWN)
|
||||
return media.IMAPIToMediaType();
|
||||
|
||||
return null;
|
||||
return (media.IMAPIToMediaType(), null);
|
||||
#else
|
||||
// Now try to get the physical media associated
|
||||
searcher = new ManagementObjectSearcher(
|
||||
"root\\CIMV2",
|
||||
$"SELECT * FROM Win32_PhysicalMedia");
|
||||
//$"SELECT * FROM Win32_PhysicalMedia WHERE Name = '{deviceId}'");
|
||||
// TODO: This entire .NET Core path still doesn't work
|
||||
// This may honestly require an entire import of IMAPI2 stuff and then try
|
||||
// as best as possible to get it working.
|
||||
|
||||
foreach (ManagementObject queryObj in searcher.Get())
|
||||
{
|
||||
deviceId = (string)queryObj["Tag"];
|
||||
mediaType = (ushort)queryObj["MediaType"];
|
||||
}
|
||||
|
||||
return ((PhysicalMediaType)mediaType).ToMediaType();
|
||||
return (null, "Media detection only supported on .NET Framework");
|
||||
#endif
|
||||
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
// We don't care what the error was
|
||||
return null;
|
||||
return (null, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -847,24 +853,56 @@ namespace DICUI.Utilities
|
||||
/// Get the current system from drive
|
||||
/// </summary>
|
||||
/// <param name="drive"></param>
|
||||
/// <param name="defaultValue"></param>
|
||||
/// <returns></returns>
|
||||
public static KnownSystem? GetKnownSystem(Drive drive)
|
||||
public static KnownSystem? GetKnownSystem(Drive drive, KnownSystem? defaultValue)
|
||||
{
|
||||
// If drive or drive letter are provided, we can't do anything
|
||||
if (drive?.Letter == null)
|
||||
return null;
|
||||
return defaultValue;
|
||||
|
||||
string drivePath = $"{drive.Letter}:\\";
|
||||
|
||||
// If we can't read the media in that drive, we can't do anything
|
||||
if (!Directory.Exists(drivePath))
|
||||
return null;
|
||||
return defaultValue;
|
||||
|
||||
// We're going to assume for floppies, HDDs, and removable drives
|
||||
// TODO: Try to be smarter about this
|
||||
if (drive.InternalDriveType != InternalDriveType.Optical)
|
||||
return KnownSystem.IBMPCCompatible;
|
||||
|
||||
// Audio CD
|
||||
if (drive.VolumeLabel.Equals("Audio CD", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return KnownSystem.AudioCD;
|
||||
}
|
||||
|
||||
// DVD-Audio
|
||||
if (Directory.Exists(Path.Combine(drivePath, "AUDIO_TS"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(drivePath, "AUDIO_TS")).Count() > 0)
|
||||
{
|
||||
return KnownSystem.DVDAudio;
|
||||
}
|
||||
|
||||
// DVD-Video and Xbox
|
||||
if (Directory.Exists(Path.Combine(drivePath, "VIDEO_TS"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(drivePath, "VIDEO_TS")).Count() > 0)
|
||||
{
|
||||
// TODO: Maybe add video track hashes to compare for Xbox and X360?
|
||||
if (drive.VolumeLabel.StartsWith("SEP13011042", StringComparison.OrdinalIgnoreCase))
|
||||
return KnownSystem.MicrosoftXBOX;
|
||||
|
||||
return KnownSystem.DVDVideo;
|
||||
}
|
||||
|
||||
// HD-DVD-Video
|
||||
if (Directory.Exists(Path.Combine(drivePath, "HVDVD_TS"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(drivePath, "HVDVD_TS")).Count() > 0)
|
||||
{
|
||||
return KnownSystem.HDDVDVideo;
|
||||
}
|
||||
|
||||
// Sega Dreamcast
|
||||
if (File.Exists(Path.Combine(drivePath, "IP.BIN")))
|
||||
{
|
||||
@@ -880,23 +918,32 @@ namespace DICUI.Utilities
|
||||
return KnownSystem.SegaCDMegaCD;
|
||||
}
|
||||
|
||||
// Sega Saturn
|
||||
try
|
||||
{
|
||||
byte[] sector = drive?.ReadSector(0);
|
||||
if (sector != null)
|
||||
{
|
||||
if (sector.StartsWith(Interface.SaturnSectorZeroStart))
|
||||
return KnownSystem.SegaSaturn;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Sony PlayStation and Sony PlayStation 2
|
||||
if (File.Exists(Path.Combine(drivePath, "SYSTEM.CNF")))
|
||||
string psxExePath = Path.Combine(drivePath, "PSX.EXE");
|
||||
string systemCnfPath = Path.Combine(drivePath, "SYSTEM.CNF");
|
||||
if (File.Exists(systemCnfPath))
|
||||
{
|
||||
// Check for either BOOT or BOOT2
|
||||
using (StreamReader reader = File.OpenText(Path.Combine(drivePath, "SYSTEM.CNF")))
|
||||
{
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
string line = reader.ReadLine();
|
||||
if (line.Contains("BOOT2"))
|
||||
return KnownSystem.SonyPlayStation2;
|
||||
else if (line.Contains("BOOT"))
|
||||
return KnownSystem.SonyPlayStation;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a weird disc, just assume PS1
|
||||
var systemCnf = new IniFile(systemCnfPath);
|
||||
if (systemCnf.ContainsKey("BOOT"))
|
||||
return KnownSystem.SonyPlayStation;
|
||||
else if (systemCnf.ContainsKey("BOOT2"))
|
||||
return KnownSystem.SonyPlayStation2;
|
||||
}
|
||||
else if (File.Exists(psxExePath))
|
||||
{
|
||||
return KnownSystem.SonyPlayStation;
|
||||
}
|
||||
|
||||
@@ -906,14 +953,27 @@ namespace DICUI.Utilities
|
||||
return KnownSystem.SonyPlayStation4;
|
||||
}
|
||||
|
||||
// Sony PlayStation 5
|
||||
if (drive.VolumeLabel.Equals("PS5VOLUME", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return KnownSystem.SonyPlayStation5;
|
||||
}
|
||||
|
||||
// V.Tech V.Flash / V.Smile Pro
|
||||
if (File.Exists(Path.Combine(drivePath, "0SYSTEM")))
|
||||
{
|
||||
return KnownSystem.VTechVFlashVSmilePro;
|
||||
}
|
||||
|
||||
// VCD
|
||||
if (Directory.Exists(Path.Combine(drivePath, "VCD"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(drivePath, "VCD")).Count() > 0)
|
||||
{
|
||||
return KnownSystem.VideoCD;
|
||||
}
|
||||
|
||||
// Default return
|
||||
return KnownSystem.NONE;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -938,51 +998,65 @@ namespace DICUI.Utilities
|
||||
case MediaType.SDCard:
|
||||
case MediaType.FlashDrive:
|
||||
case MediaType.HDDVD:
|
||||
return Result.Success("{0} ready to dump", type.LongName());
|
||||
return Result.Success($"{type.LongName()} ready to dump");
|
||||
|
||||
// Partially supported types
|
||||
case MediaType.GDROM:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return Result.Success("{0} partially supported for dumping", type.LongName());
|
||||
return Result.Success($"{type.LongName()} partially supported for dumping");
|
||||
|
||||
// Special case for other supported tools
|
||||
case MediaType.UMD:
|
||||
return Result.Success("{0} supported for submission info parsing", type.LongName());
|
||||
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");
|
||||
return Result.Failure($"Please select a valid media type");
|
||||
|
||||
// Undumpable but recognized types
|
||||
default:
|
||||
return Result.Failure("{0} media are not supported for dumping", type.LongName());
|
||||
return Result.Failure($"{type.LongName()} media are not supported for dumping");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run protection scan on a given dump environment
|
||||
/// </summary>
|
||||
/// <param name="env">DumpEnvirionment containing all required information</param>
|
||||
/// <returns>Copy protection detected in the envirionment, if any</returns>
|
||||
public static async Task<string> RunProtectionScanOnPath(string path)
|
||||
/// <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>TCopy protection detected in the envirionment, if any</returns>
|
||||
public static async Task<(bool, string)> RunProtectionScanOnPath(string path, Options options, IProgress<ProtectionProgress> progress = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var found = await Task.Run(() =>
|
||||
{
|
||||
return ProtectionFind.Scan(path);
|
||||
var scanner = new Scanner(progress)
|
||||
{
|
||||
IncludePosition = options.IncludeDebugProtectionInformation,
|
||||
ScanAllFiles = options.ForceScanningForProtection,
|
||||
ScanArchives = options.ScanArchivesForProtection,
|
||||
ScanPackers = options.ScanPackersForProtection,
|
||||
};
|
||||
return scanner.GetProtections(path);
|
||||
});
|
||||
|
||||
if (found == null || found.Count == 0)
|
||||
return "None found";
|
||||
return (true, "None found");
|
||||
|
||||
// Strip out "CD Check" instances due to false positives
|
||||
return string.Join("\n", found.Where(kvp => !kvp.Value.Equals("CD Check", StringComparison.OrdinalIgnoreCase)).Select(kvp => kvp.Key + ": " + kvp.Value).ToArray());
|
||||
// Join the output protections for writing
|
||||
string protections = string.Join(", ", found
|
||||
.Where(kvp => kvp.Value != null && kvp.Value.Any())
|
||||
.SelectMany(kvp => kvp.Value)
|
||||
.Distinct()
|
||||
.OrderBy(p => p));
|
||||
return (true, protections);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return $"Path could not be scanned! {ex}";
|
||||
return (false, ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net462;net472;net48;netcoreapp3.1</TargetFrameworks>
|
||||
<TargetFrameworks>net48;netcoreapp3.1</TargetFrameworks>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DICUI.Library\DICUI.Library.csproj">
|
||||
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj">
|
||||
<Project>{51ab0928-13f9-44bf-a407-b6957a43a056}</Project>
|
||||
<Name>DICUI.Library</Name>
|
||||
<Name>MPF.Library</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\DICUI\DICUI.csproj">
|
||||
<ProjectReference Include="..\MPF\MPF.csproj">
|
||||
<Project>{7b1b75eb-8940-466f-bd51-76471a57f9be}</Project>
|
||||
<Name>DICUI</Name>
|
||||
<Name>MPF</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeCoverage" Version="16.3.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
|
||||
<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" />
|
||||
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
|
||||
<PackageReference Include="xunit.analyzers" Version="0.10.0" />
|
||||
@@ -27,7 +28,10 @@
|
||||
<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.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,7 +1,7 @@
|
||||
using DICUI.Utilities;
|
||||
using MPF.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace DICUI.Test
|
||||
namespace MPF.Test
|
||||
{
|
||||
public class ResultTest
|
||||
{
|
||||
@@ -14,11 +14,6 @@ namespace DICUI.Test
|
||||
string message = "Success!";
|
||||
actual = Result.Success(message);
|
||||
Assert.Equal(message, actual.Message);
|
||||
|
||||
message = "Success! {0}";
|
||||
string parameter = "Parameter";
|
||||
actual = Result.Success(message, parameter);
|
||||
Assert.Equal(string.Format(message, parameter), actual.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -30,11 +25,6 @@ namespace DICUI.Test
|
||||
string message = "Failure!";
|
||||
actual = Result.Failure(message);
|
||||
Assert.Equal(message, actual.Message);
|
||||
|
||||
message = "Failure! {0}";
|
||||
string parameter = "Parameter";
|
||||
actual = Result.Failure(message, parameter);
|
||||
Assert.Equal(string.Format(message, parameter), actual.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.Linq;
|
||||
using DICUI.Data;
|
||||
using MPF.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace DICUI.Test.Data
|
||||
namespace MPF.Test.Data
|
||||
{
|
||||
public class UIElementsTest
|
||||
{
|
||||
@@ -10,11 +10,11 @@ namespace DICUI.Test.Data
|
||||
[InlineData(MediaType.CDROM, 72)]
|
||||
[InlineData(MediaType.DVD, 24)]
|
||||
[InlineData(MediaType.BluRay, 16)]
|
||||
[InlineData(MediaType.LaserDisc, 72)] // TODO: Update when fully determined
|
||||
[InlineData(null, 72)] // TODO: Update when fully determined
|
||||
[InlineData(MediaType.LaserDisc, 1)]
|
||||
[InlineData(null, 1)]
|
||||
public void GetAllowedDriveSpeedForMediaTypeTest(MediaType? mediaType, int maxExpected)
|
||||
{
|
||||
var actual = Constants.GetSpeedsForMediaType(mediaType);
|
||||
var actual = Interface.GetSpeedsForMediaType(mediaType);
|
||||
Assert.Equal(maxExpected, actual.Last());
|
||||
}
|
||||
}
|
||||
139
MPF.Test/Utilities/ConvertersTest.cs
Normal file
139
MPF.Test/Utilities/ConvertersTest.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
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,9 +1,9 @@
|
||||
using System.IO;
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
using MPF.Data;
|
||||
using MPF.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace DICUI.Test
|
||||
namespace MPF.Test
|
||||
{
|
||||
public class DumpEnvironmentTest
|
||||
{
|
||||
@@ -16,14 +16,12 @@ namespace DICUI.Test
|
||||
[InlineData("stop D", 'D', false, MediaType.DVD, true)]
|
||||
public void ParametersValidTest(string parameters, char letter, bool isFloppy, MediaType? mediaType, bool expected)
|
||||
{
|
||||
var env = new DumpEnvironment
|
||||
{
|
||||
Parameters = new DiscImageCreator.Parameters(parameters),
|
||||
Drive = isFloppy
|
||||
? new Drive(InternalDriveType.Floppy, new DriveInfo(letter.ToString()))
|
||||
: new Drive(InternalDriveType.Optical, new DriveInfo(letter.ToString())),
|
||||
Type = mediaType,
|
||||
};
|
||||
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);
|
||||
@@ -40,15 +38,9 @@ namespace DICUI.Test
|
||||
[InlineData("superhero", "blah&foo.bin", "superhero", "blah&foo.bin")]
|
||||
public void FixOutputPathsTest(string outputDirectory, string outputFilename, string expectedOutputDirectory, string expectedOutputFilename)
|
||||
{
|
||||
var env = new DumpEnvironment
|
||||
{
|
||||
OutputDirectory = outputDirectory,
|
||||
OutputFilename = outputFilename,
|
||||
};
|
||||
|
||||
env.FixOutputPaths();
|
||||
Assert.Equal(expectedOutputDirectory, env.OutputDirectory);
|
||||
Assert.Equal(expectedOutputFilename, env.OutputFilename);
|
||||
(string actualOutputDirectory, string actualOutputFilename) = DumpEnvironment.NormalizeOutputPaths(outputDirectory, outputFilename, false);
|
||||
Assert.Equal(expectedOutputDirectory, actualOutputDirectory);
|
||||
Assert.Equal(expectedOutputFilename, actualOutputFilename);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
using MPF.Data;
|
||||
using MPF.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace DICUI.Test.Utilities
|
||||
namespace MPF.Test.Utilities
|
||||
{
|
||||
public class KnownSystemExtensionsTest
|
||||
{
|
||||
@@ -1,8 +1,8 @@
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
using MPF.Data;
|
||||
using MPF.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace DICUI.Test.Utilities
|
||||
namespace MPF.Test.Utilities
|
||||
{
|
||||
public class MediaTypeExtensionsTest
|
||||
{
|
||||
@@ -1,48 +1,50 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using DICUI.Data;
|
||||
using DICUI.DiscImageCreator;
|
||||
using DICUI.Utilities;
|
||||
using MPF.Data;
|
||||
using MPF.DiscImageCreator;
|
||||
using MPF.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace DICUI.Test.Utilities
|
||||
namespace MPF.Test.Utilities
|
||||
{
|
||||
public class ParametersTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(KnownSystem.MicrosoftXBOX, MediaType.CDROM, Command.CompactDisc)]
|
||||
[InlineData(KnownSystem.MicrosoftXBOX, MediaType.DVD, Command.XBOX)]
|
||||
[InlineData(KnownSystem.MicrosoftXBOX, MediaType.LaserDisc, Command.NONE)]
|
||||
[InlineData(KnownSystem.SegaNu, MediaType.BluRay, Command.BluRay)]
|
||||
[InlineData(KnownSystem.AppleMacintosh, MediaType.FloppyDisk, Command.Floppy)]
|
||||
[InlineData(KnownSystem.RawThrillsVarious, MediaType.GDROM, Command.NONE)]
|
||||
public void ParametersFromSystemAndTypeTest(KnownSystem? knownSystem, MediaType? mediaType, Command expected)
|
||||
[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 actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, true, false, -1);
|
||||
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 Flag[] { Flag.Raw })]
|
||||
[InlineData(KnownSystem.IBMPCCompatible, MediaType.DVD, false, 20, null, new Flag[] { })]
|
||||
[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 Flag[] { Flag.C2Opcode, Flag.NoFixSubQSecuROM, Flag.ScanFileProtect, Flag.ScanSectorProtect, Flag.SubchannelReadLevel })]
|
||||
[InlineData(KnownSystem.AppleMacintosh, MediaType.CDROM, false, 20, null, new Flag[] { Flag.C2Opcode, Flag.NoFixSubQSecuROM, Flag.ScanFileProtect })]
|
||||
[InlineData(KnownSystem.IBMPCCompatible, MediaType.DVD, true, 500, null, new Flag[] { Flag.CopyrightManagementInformation, Flag.ScanFileProtect })]
|
||||
[InlineData(KnownSystem.HDDVDVideo, MediaType.HDDVD, true, 500, null, new Flag[] { Flag.CopyrightManagementInformation })]
|
||||
[InlineData(KnownSystem.IBMPCCompatible, MediaType.DVD, false, 500, null, new Flag[] { })]
|
||||
[InlineData(KnownSystem.HDDVDVideo, MediaType.HDDVD, false, 500, null, new Flag[] { })]
|
||||
[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 Flag[] { Flag.C2Opcode })]
|
||||
[InlineData(KnownSystem.SegaDreamcast, MediaType.GDROM, false, -1, null, new Flag[] { Flag.C2Opcode })]
|
||||
[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, Flag[] expected)
|
||||
public void ParametersFromOptionsTest(KnownSystem? knownSystem, MediaType? mediaType, bool paranoid, int rereadC2, int? subchannelLevel, string[] expected)
|
||||
{
|
||||
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, paranoid, false, rereadC2);
|
||||
var options = new Options { DICParanoidMode = paranoid, DICRereadCount = rereadC2 };
|
||||
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, options);
|
||||
|
||||
HashSet<Flag> expectedSet = new HashSet<Flag>(expected ?? new Flag[0]);
|
||||
HashSet<Flag> actualSet = new HashSet<Flag>(actual.Keys.Cast<Flag>() ?? new Flag[0]);
|
||||
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]);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user