Compare commits

...

422 Commits
2.3 ... 2.6.2

Author SHA1 Message Date
Matt Nadareski
3dcac28488 Bump version to 2.6.2 2023-07-24 09:40:20 -04:00
Matt Nadareski
4cd7073bf6 Clarify build instructions 2023-07-23 23:51:05 -04:00
Matt Nadareski
1af21e7aba Add build instructions to README 2023-07-23 23:48:04 -04:00
Matt Nadareski
52adcd0b46 Add *nix publish script 2023-07-23 23:44:03 -04:00
Matt Nadareski
8a91593e58 Add Windows publish script 2023-07-23 21:42:10 -04:00
Matt Nadareski
729f8273fc Fix universal hash URL generation 2023-07-23 19:16:57 -04:00
Matt Nadareski
78df6f6583 Fix .NET Framework 4.8 build 2023-07-23 16:48:44 -04:00
Matt Nadareski
dc8dae4df7 Attempt to match universal hash 2023-07-23 16:41:40 -04:00
Matt Nadareski
53db9dbf81 Modify the track count on checking 2023-07-23 15:09:46 -04:00
Matt Nadareski
22755a4af9 Skip extra tracks during checking (fixes #529) 2023-07-22 21:31:20 -04:00
Matt Nadareski
ba28b414ba Normalize old universal hash text (fixes #528) 2023-07-20 20:26:57 -04:00
Matt Nadareski
95d10ecb1e Always show extension for Redumper (fixes #525) 2023-07-20 11:35:15 -04:00
Matt Nadareski
c5ab2c747a Support LibCrypt data from Redumper 2023-07-19 17:07:59 -04:00
Matt Nadareski
476c494f4e Universal hash only for audio discs (fixes #524) 2023-07-19 13:33:14 -04:00
Matt Nadareski
758c49c1cc Ensure custom parameters properly set (fixes #523) 2023-07-19 12:51:22 -04:00
Matt Nadareski
d80ad3b3cf Bump version to 2.6.1 2023-07-19 09:36:34 -04:00
Matt Nadareski
3d06f80703 Fix comment field pulling again 2023-07-19 00:05:33 -04:00
Matt Nadareski
7344460409 Fix comment field pulling again (fixes #522) 2023-07-18 22:40:08 -04:00
Matt Nadareski
19f58d9dde Set extensions for Redumper in UI (fixes #521) 2023-07-18 20:56:08 -04:00
Matt Nadareski
ad9f39f832 Be more explicit about .NET 6 limitation 2023-07-17 13:23:00 -04:00
Matt Nadareski
d51117b058 Be more explicit about .NET 6 limitation (fixes #519) 2023-07-17 13:17:42 -04:00
Matt Nadareski
0d65d5114a Set best compression levels for log files (fixes #518) 2023-07-17 13:13:16 -04:00
Matt Nadareski
30fec3c3d0 Don't pull comment fields that auto-populate (fixes #517) 2023-07-17 10:28:37 -04:00
Matt Nadareski
8eb86fde90 Simplify Redumper error value extraction (fixes #515) 2023-07-14 16:42:47 -04:00
Matt Nadareski
7616c6b2ba Bump version to 2.6 2023-07-14 13:47:00 -04:00
Matt Nadareski
e0742cdfc7 Update Nuget packages to newest stable 2023-07-14 12:07:44 -04:00
Matt Nadareski
a19937d630 Omit pulling universal hash (fixes #513) 2023-07-12 17:29:35 -04:00
Matt Nadareski
fa92402bc5 Ensure we found the tags we're skipping (fixes #512) 2023-07-11 10:57:50 -04:00
Matt Nadareski
cdc3da5839 Reduce pulled information for Xbox and X360 (fixes #512) 2023-07-10 11:15:32 -04:00
Matt Nadareski
3430f8c1db New layerbreak takes precedence 2023-07-10 09:38:52 -04:00
Matt Nadareski
12fd55e76c Parse and format Redumper CD multisession data 2023-07-09 20:55:33 -04:00
Matt Nadareski
0013606d61 Update redumper to build 183 2023-07-09 14:43:47 -04:00
Matt Nadareski
4d520d7d63 Add ordering to disc or book type 2023-07-06 22:50:21 -04:00
Matt Nadareski
7bfe174680 Use HashSet for disc or book type 2023-07-06 15:21:37 -04:00
Matt Nadareski
4951e7bf42 Strip colons from Redumper disc key (fixes #508) 2023-06-27 15:44:55 -04:00
Matt Nadareski
d7d9c468ae UMDs are Sony discs (fixes #507) 2023-06-26 11:46:57 -04:00
Matt Nadareski
32faa33ad3 Update redumper to build 176 2023-06-26 01:06:46 -04:00
Matt Nadareski
8a5475380a Check Redumper dat section for completeness 2023-06-23 11:20:17 -04:00
Matt Nadareski
1dd5542390 Add missing Aaru error log to zip 2023-06-21 16:27:23 -04:00
Matt Nadareski
5156b89eca Normalize multi-instance site tags (fixes #505) 2023-06-19 21:21:20 -04:00
Matt Nadareski
83ea04c880 Normalize Redumper CSS outputs 2023-06-19 21:13:18 -04:00
Matt Nadareski
8695d2981e Fix non-reading loop 2023-06-18 23:18:50 -04:00
Matt Nadareski
e0c299e6f0 Adjust CSS title key parsing 2023-06-18 23:01:17 -04:00
Matt Nadareski
16ec54f389 Add support for redumper CD synonyms 2023-06-18 21:56:49 -04:00
Matt Nadareski
998bf5d5fa Update redumper to build 174 2023-06-18 21:55:57 -04:00
Matt Nadareski
07ec821e9a Hook up CSS output for testing 2023-06-18 21:15:50 -04:00
Matt Nadareski
56cf8f3574 Initial support for Redumper CSS outputs 2023-06-18 21:13:25 -04:00
Matt Nadareski
c6ebfcd6d9 Update redumper to build 173 2023-06-18 21:01:52 -04:00
Matt Nadareski
6ceffce63d Fix previous commit, clean up helpers 2023-06-12 13:42:13 -04:00
Matt Nadareski
f43aafc00d Update Redumper PS1 output parsing 2023-06-12 13:31:49 -04:00
Matt Nadareski
ab598d8377 Fix Redumper DAT/layer parsing 2023-06-11 00:57:42 -04:00
Matt Nadareski
dbd876a1c1 Fix VSCode build 2023-06-11 00:56:54 -04:00
Matt Nadareski
fd102cb56b Fix 2-layer DVD support in Redumper 2023-06-10 20:46:54 -04:00
Matt Nadareski
0afb49b657 Add TODO with notes to Redumper 2023-06-10 18:01:52 -04:00
Matt Nadareski
be980fe0c4 Add placeholder and TODOs for Redumper 2023-06-10 17:49:31 -04:00
Matt Nadareski
08b4e8d602 Support Redumper DVD layerbreak 2023-06-10 17:41:48 -04:00
Matt Nadareski
e483e1cdc6 Unblock Redumper DVD support 2023-06-10 12:03:14 -04:00
Matt Nadareski
5c2dce78e2 Update redumper to build 166 2023-06-09 23:00:20 -04:00
Matt Nadareski
26ea383775 Update to DIC 20230606 2023-06-06 11:13:29 -04:00
Matt Nadareski
64938fd7f1 Fix MCD region(s) parsing 2023-05-30 13:04:33 -04:00
Matt Nadareski
22318ee3c1 Add MCD/SS header support for Redumper (fixes #495)
This also does a replacement for all instances of `?? "";` with `?? string.Empty;`, which is more correct.
2023-05-30 12:58:37 -04:00
Matt Nadareski
b2b54a2706 Update changelog 2023-05-28 16:13:57 -04:00
fuzzball
40f04e0321 Change the fast-forward keyword (#493) 2023-05-28 13:06:49 -07:00
fuzzball
a7638b8063 Get write offset from redumper 119 (#484) 2023-05-28 13:06:20 -07:00
Matt Nadareski
2abcad2a0f Add more safety to DAT generation (fixes #492) 2023-05-28 16:05:00 -04:00
Matt Nadareski
e088b05de4 Update redumper to build 151 2023-05-19 13:10:39 -04:00
Matt Nadareski
a31d894b79 Add executable listing for XSX (fixes #491) 2023-05-10 09:26:50 -04:00
Matt Nadareski
34fae4572d Fix non-zero offset text (fixes #490) 2023-05-09 13:38:22 -04:00
Matt Nadareski
1ecf0ad1fa Fix other media type method 2023-04-26 16:00:20 -04:00
Matt Nadareski
7c7509020f Add PIC identifier to SubmissionInfo (fixes #488) 2023-04-26 10:24:30 -04:00
Matt Nadareski
7c6b118282 Add internal theme support with class (fixes #487) 2023-04-26 09:51:29 -04:00
Matt Nadareski
c154a844e3 Truncate PIC data for PS4/PS5 (fixes #486) 2023-04-26 08:35:36 -04:00
Matt Nadareski
088f1b8545 Add missing BD disc type identifier string 2023-04-26 08:29:56 -04:00
Matt Nadareski
fc3c636bdd Single file packing for .NET 6 again 2023-04-25 09:07:42 -04:00
Matt Nadareski
14c807c882 Fix subdump mkdir path in AV config 2023-04-24 21:52:52 -04:00
Matt Nadareski
d0e9c51786 Fix subdump output path in AV config 2023-04-24 21:42:20 -04:00
Matt Nadareski
b428bc0ba0 Be more specific with runtime identifiers 2023-04-24 21:31:39 -04:00
Matt Nadareski
6dbbb91438 De-indent ringcode data 2023-04-24 14:42:13 -04:00
Matt Nadareski
2066d36424 Ensure blank lines don't interfere 2023-04-24 00:01:07 -04:00
Matt Nadareski
29552cd39d Fix upcoming suppl DAT parsing 2023-04-23 23:59:44 -04:00
Matt Nadareski
640e7091cc Attempt to more accurately parse layerbreaks 2023-04-23 23:38:57 -04:00
Matt Nadareski
af12c18d2e Fix missing size for ISO data 2023-04-23 22:26:24 -04:00
Matt Nadareski
f28cf614c3 Fix info tool hash finding 2023-04-23 10:00:13 -04:00
Matt Nadareski
888cb8ec9f Support single digit subs 2023-04-23 09:45:56 -04:00
Matt Nadareski
04035ac524 Add suppl support to Xbox 2023-04-22 21:51:18 -04:00
Matt Nadareski
600374eb2d Prepare for future DIC changes
This also takes care of additional `sub` files generated for nonstandard tracks, such as Track 00 and Track AA (fixes #483)
2023-04-22 21:19:02 -04:00
Matt Nadareski
6ecb932a82 Start migrating to datafile serialization 2023-04-22 16:48:40 -04:00
Matt Nadareski
4cbc9ac109 Add datafile helper method 2023-04-22 16:25:18 -04:00
Matt Nadareski
5ee0b7345b Add datafile models 2023-04-22 15:11:14 -04:00
Matt Nadareski
cc55330fad Make TOC file optional for CD/GD 2023-04-21 13:19:27 -04:00
Matt Nadareski
6589380fdf Remove path from PS1/PS2 serial (fixes #481) 2023-04-19 11:36:13 -04:00
Matt Nadareski
bd45482bf7 Disable special SmartE handling for DIC 2023-04-17 14:06:27 -04:00
Matt Nadareski
e14c8a8f03 Ensure dumping program box can enable/disable 2023-04-13 12:34:51 -04:00
Matt Nadareski
4ac00e9a1a Comment out . handling for DIC 2023-04-13 12:33:14 -04:00
Matt Nadareski
edf983e304 Update to DIC 20230413 2023-04-13 12:27:46 -04:00
Matt Nadareski
01a69ef9b3 Add dumping program selection to main UI (#479)
* Add dumping program selection to main UI

* Fix program dropdown

* Fix lingering location

* Final changes
2023-04-11 08:15:53 -07:00
Matt Nadareski
a368afc14a UMDs always have "2 layers" (fixes #473) 2023-04-10 10:21:47 -04:00
Matt Nadareski
d83fed16f5 Handle PIC based on disc type 2023-04-10 10:14:44 -04:00
Matt Nadareski
949df08690 Add PIC models for BD (unused) 2023-04-10 10:13:58 -04:00
Matt Nadareski
ab3abb5b3e Re-enable BD33 and BD66 2023-04-10 08:57:51 -04:00
Matt Nadareski
d16e73a530 Add UltraCade 2023-04-09 21:24:47 -04:00
Matt Nadareski
3f8c55ca47 Clarify non-Redump systems 2023-04-09 21:10:08 -04:00
Matt Nadareski
2e9aaa50f9 Update redumper to build 118
This change also does the following:
- Performs some minor cleanup on `OptionsViewModel`
- Add options for enabling verbose and debug by default for Redumper (similar to Aaru)
2023-04-09 20:54:52 -04:00
Matt Nadareski
36951dc5da Resync with Redump 2023-04-08 21:32:20 -04:00
Matt Nadareski
b39c8dd738 Add DIC . notice to README 2023-04-01 21:51:02 -04:00
Matt Nadareski
a1155cf9b7 Update to DIC 20230401 2023-04-01 20:32:42 -04:00
Matt Nadareski
1d151d213e Update redumper to build 115 2023-03-31 10:30:19 -04:00
Matt Nadareski
6dc0c1438a Update changelog 2023-03-31 10:25:09 -04:00
fuzzball
8739569db6 Change the mark for fast-forwarding (#475) 2023-03-31 07:21:36 -07:00
Matt Nadareski
0dcba9ce71 Add Hasbro iON (fixes #471) 2023-03-20 15:59:16 -04:00
Matt Nadareski
8d37b85e12 Update README 2023-03-20 15:47:01 -04:00
Matt Nadareski
43cf8e1a45 Split MMI invocation in drive listing 2023-03-20 15:16:35 -04:00
Matt Nadareski
7317553483 Update redumper to build 113 2023-03-20 10:19:27 -04:00
Matt Nadareski
0b342e265c Add Windows 7 note to README 2023-03-20 10:11:39 -04:00
Matt Nadareski
08359dd45f Update changelog 2023-03-19 14:13:32 -04:00
fuzzball
a24415cae6 Increase the version of AppVeyor (#470) 2023-03-19 11:09:33 -07:00
fuzzball
59f8161308 Pull hardware info from redumper log (#469) 2023-03-19 11:09:12 -07:00
Matt Nadareski
51f955a14c Add warning to login tab 2023-03-13 14:23:54 -04:00
Matt Nadareski
ddebdef00c Update README 2023-03-13 13:25:32 -04:00
Matt Nadareski
6a4b6d613a Bump version to 2.5, update copyright year 2023-03-12 15:48:24 -04:00
Matt Nadareski
97aef5e29c Update changelog 2023-03-12 15:43:15 -04:00
fuzzball
9549178c3a Detect EOF during the search for error counts (#465) 2023-03-12 13:22:49 -04:00
Matt Nadareski
c531539c87 Readd accidentally deleted line (fixes #452) 2023-03-11 22:26:45 -05:00
Matt Nadareski
fa04461631 Return list of missing files for Redumper 2023-03-10 20:56:31 -05:00
Matt Nadareski
83d230dfe1 Handle quotes embedded 2023-03-10 17:05:18 -05:00
Matt Nadareski
ca18bbb72c Ensure drive and speed are set 2023-03-10 16:52:46 -05:00
Matt Nadareski
de0f2c1ad9 Update parameters with = handling 2023-03-10 16:43:17 -05:00
Matt Nadareski
2f0019282e Ensure min values are taken care of 2023-03-10 16:13:19 -05:00
Matt Nadareski
72ca479c9f Ensure Redumper parameters are set 2023-03-10 15:33:27 -05:00
Matt Nadareski
de3c4362e7 Fix incorrect image name setting 2023-03-10 15:10:24 -05:00
Matt Nadareski
987348fee8 Use and trim quotes for Redumper 2023-03-10 14:13:36 -05:00
Matt Nadareski
100e012fe6 Fix Redumper path generation 2023-03-10 10:27:09 -05:00
Matt Nadareski
af59ebe1ff Add TOC back as optional file 2023-03-09 13:43:10 -05:00
Matt Nadareski
0762c88655 Fix errant forward slashes 2023-03-09 10:18:23 -05:00
Matt Nadareski
bbe9c94545 Update to DIC 20230309 2023-03-09 10:07:06 -05:00
Matt Nadareski
c7efda7da8 Move drive finding inside of the try/catch 2023-03-09 09:10:29 -05:00
Matt Nadareski
5c78f9bc29 Add identifiers in more places 2023-03-08 22:49:01 -05:00
Matt Nadareski
e7c17c7b4b Remove unsupported identifiers 2023-03-08 22:30:05 -05:00
Matt Nadareski
7a2497f168 Add win7-x64 to identifier list 2023-03-08 22:25:21 -05:00
Matt Nadareski
5172f6f253 Attempt to support Windows 7 2023-03-08 22:11:32 -05:00
Matt Nadareski
9017472fa4 Set saner defaults for dumping speeds
I have to assume that new users will never look a the settings, so max is no longer a default that makes sense.
2023-03-08 11:43:05 -05:00
Matt Nadareski
6659c410c6 Minor cosmetic changes 2023-03-07 10:47:14 -05:00
fuzzball
8c7b66a2f5 Get error count from recent redumper log (#462)
* Get error count from recent redumper log

* Revert "Get error count from recent redumper log"

This reverts commit 50f5f71686.

* Fix to keep existing code format
2023-03-07 07:21:33 -08:00
Matt Nadareski
8f57d78200 Update to BurnOutSharp 2.7.0 2023-03-06 09:52:59 -05:00
Matt Nadareski
ad2ee9efa8 Update changelog 2023-03-04 22:43:44 -05:00
Wilson
192964f65a Originally intended behaviour of the Update Label button. (#459)
* Originally intended behaviour of the Update Label button. Sets up the environment and simply updates the output path and filename. No System, Media, Drive, or Speed changes. It's a very fast update meant for large lots of similar discs.

* Functionized the FastUpdateLabel code path.
Added new UI option to enable Fast Update Label feature.
Added missing function calls. Prevents UI misbehaviour.

* Fixed several glaring holes in the process. ^_^

* Removed some unecessary code.
2023-03-04 19:40:10 -08:00
Matt Nadareski
672f30af35 Handle undetected discs on refresh (fixes #461) 2023-03-03 08:40:33 -05:00
Matt Nadareski
a7a17298f2 Fix incorrect option slider display 2023-03-01 12:34:53 -05:00
Matt Nadareski
e17ad8e4a1 Handle missing extension gracefully (fixes #460) 2023-03-01 10:51:41 -05:00
Matt Nadareski
2a544676e6 Can't publish single file for UI 2023-02-25 10:52:12 -05:00
Matt Nadareski
6abfa9581d Update VSCode config files 2023-02-25 10:38:30 -05:00
Matt Nadareski
a6de548e5d Update changelog 2023-02-24 22:18:22 -05:00
fuzzball
9dc3e579b5 Get the version of redumper (#446)
* Get the version

* Correct the name of redumper (lowercase)
2023-02-24 19:15:58 -08:00
Matt Nadareski
c5be7d7f73 Trim PIC for PS3 (fixes #443) 2023-02-24 16:09:05 -05:00
Matt Nadareski
70c0da703b Use media size for type detection on .NET 6 2023-02-24 15:14:43 -05:00
Matt Nadareski
1cbe81fba6 Add Redumper non-zero data start 2023-02-24 13:40:14 -05:00
Matt Nadareski
420e356f34 Fix Redumper write offset support 2023-02-24 13:32:22 -05:00
Matt Nadareski
0e0ff0cb80 Add Redumper Universal Hash support 2023-02-24 13:00:38 -05:00
Matt Nadareski
9003d05ae2 Make .NET 6 slightly better 2023-02-24 00:17:53 -05:00
Matt Nadareski
c247225cac Remove System.Management 2023-02-23 23:36:19 -05:00
Matt Nadareski
4bccaa8ecf Introduce cross-platform MMI 2023-02-23 22:29:26 -05:00
Matt Nadareski
b579fec7ab Semi-unify drive finding 2023-02-23 21:37:36 -05:00
Matt Nadareski
37e4525c98 Fix typo in DICMultiSectorReadValue (fixes #447) 2023-02-23 21:04:56 -05:00
Matt Nadareski
2269537848 Fix other -windows places for .NET 6 2023-02-23 17:11:46 -05:00
Matt Nadareski
441fb91222 Packaging requires -windows for framework 2023-02-23 17:04:39 -05:00
Matt Nadareski
89e0473019 Handle no drives betterer 2023-02-23 16:59:37 -05:00
Matt Nadareski
3e13b35c84 Handle no drives better 2023-02-23 16:55:27 -05:00
Matt Nadareski
fd4910fc36 Attempt to handle no drives (fixes #444) 2023-02-23 16:50:00 -05:00
Matt Nadareski
964685770f Reformat CICM for old .NET versions 2023-02-23 16:43:36 -05:00
Matt Nadareski
634d64b5a1 Update Redumper to build_106 2023-02-23 16:36:11 -05:00
Matt Nadareski
19ec1c448f Enable .NET 6 Windows builds 2023-02-23 16:33:39 -05:00
Matt Nadareski
e3532d6f02 Fix Aaru removal 2023-02-23 16:26:16 -05:00
Matt Nadareski
aaf0aabb55 Remove Aaru as submodule 2023-02-23 16:11:29 -05:00
Matt Nadareski
575a5936ca Remove usage of Aaru 2023-02-23 15:47:01 -05:00
Matt Nadareski
391d265353 Use relative path output for DIC 2023-02-23 15:22:21 -05:00
Matt Nadareski
f90d19821c Update to DIC 20230201 (fixes #450) 2023-02-23 15:00:07 -05:00
Matt Nadareski
b79babf57e Add nicer failure message (fixes #453) 2023-02-23 14:32:46 -05:00
Matt Nadareski
a929bb0022 Fix relative paths for DIC (fixes #452) 2023-02-23 13:01:17 -05:00
Matt Nadareski
975eb97e27 Be smarter about old paths (fixes #455) 2023-02-23 12:31:27 -05:00
Matt Nadareski
49800cf0ed Go back to pre .NET 7 Aaru 2023-01-20 23:10:31 -08:00
Matt Nadareski
de18609e00 Add drive format (fs) to log 2023-01-20 22:55:13 -08:00
Matt Nadareski
9911446bf9 Revert submodule update 2023-01-20 22:46:02 -08:00
Matt Nadareski
a9223211ab Revert "Update internal Aaru to latest source"
This reverts commit a30ee3e6ff.
2023-01-20 22:45:28 -08:00
Matt Nadareski
54c4eeba03 Revert "Update internal Aaru to latest source"
This reverts commit a30ee3e6ff.
2023-01-20 22:39:21 -08:00
Matt Nadareski
a30ee3e6ff Update internal Aaru to latest source 2023-01-20 22:30:54 -08:00
Matt Nadareski
1fa19489a3 ReadAllText not ReadAllLines 2023-01-20 21:41:05 -08:00
John Veness
f6298dfe89 Make output file options consistent (#449)
Made "Output Protection File" to be consistent with "Output Submission JSON".
2023-01-16 10:32:52 -08:00
Matt Nadareski
79802a53f6 Update nuget packages 2023-01-06 13:54:24 -08:00
Matt Nadareski
54bf43fd6b Use msbuild for .NET Framework 4.8 2022-12-30 11:41:56 -08:00
Matt Nadareski
bb2b2f668b Use msbuild for .NET Framework 4.8 2022-12-30 11:37:14 -08:00
Matt Nadareski
ecca27e012 More strict when custom parameters editing 2022-12-30 11:24:51 -08:00
Matt Nadareski
fe0699ca48 Tweak AppVeyor, show Check 6.0 builds 2022-12-30 11:20:34 -08:00
Matt Nadareski
73b2f0921f Address some UI concerns 2022-12-30 10:59:32 -08:00
fuzzball
c56230c3af Skip during detection (#445) 2022-12-30 09:55:23 -08:00
Matt Nadareski
919b62822d Fix AppVeyor pathing 2022-12-29 22:15:27 -08:00
Matt Nadareski
21b0c9a08d Update options loader with sane defaults (fixes #442) 2022-12-24 12:59:58 -08:00
Matt Nadareski
63fafd05b3 Update to Aaru v5.3.2 LTS 2022-12-23 09:19:01 -08:00
Matt Nadareski
0a2493a953 Fix redumper error count parsing 2022-12-20 23:21:29 -08:00
Matt Nadareski
87ab750714 Fix typo in ToInternalProgram 2022-12-19 22:16:47 -08:00
Matt Nadareski
5cf3eca9eb Fix XGD media type outputs (fixes #441) 2022-12-19 12:38:18 -08:00
Matt Nadareski
b4a079b65f Remove x86 requirement for build 2022-12-19 09:41:59 -08:00
Matt Nadareski
7f2d501edf Output security sectors to info (fixes #440) 2022-12-15 22:14:31 -08:00
Matt Nadareski
c981f94092 Update AppVeyor version 2022-12-15 22:13:01 -08:00
Matt Nadareski
afba46b8b0 Fix a couple redumper things 2022-12-13 20:12:18 -08:00
Matt Nadareski
4e416df3c8 Fix incorrect SetParameters 2022-12-13 20:04:20 -08:00
Matt Nadareski
1b54e52351 Force a filename for redumper 2022-12-13 17:20:45 -08:00
Matt Nadareski
5e1568a148 Add missing redumper output file 2022-12-13 16:39:31 -08:00
Matt Nadareski
8f0ac56cf8 Reenable write offset for all CDs (fixes #439) 2022-12-13 16:16:42 -08:00
Matt Nadareski
37f0f9d4a4 Update README 2022-12-13 15:46:07 -08:00
Matt Nadareski
a48f75c704 Initial attempt at parsing redumper outputs 2022-12-13 15:35:12 -08:00
Matt Nadareski
58a683e3c9 Fix incorrect naming in Options window 2022-12-13 14:15:38 -08:00
Matt Nadareski
907637b128 Update redumper to build 81 2022-12-13 13:52:57 -08:00
Matt Nadareski
85f3e97a44 Add redumper to the UI 2022-12-13 13:47:15 -08:00
Matt Nadareski
beae9691fd Add new parameter and mode validation 2022-12-13 13:25:19 -08:00
Matt Nadareski
b7876d54cc Update redumper strings 2022-12-13 12:09:47 -08:00
Matt Nadareski
5b24223cb5 Merge branch 'master' of https://github.com/SabreTools/MPF 2022-12-13 11:57:06 -08:00
Matt Nadareski
88cadff9ef General UI Cleanup (#438)
* Update Nuget packages to newest stable

* Simplify path selection in UI

* Update changelog

* Fix broken normalization test

* Update drive info before dumping
2022-12-13 11:48:26 -08:00
Matt Nadareski
b92b39e7eb Update Nuget packages to newest stable 2022-12-12 14:45:07 -08:00
Matt Nadareski
8d29a29591 Update changelog 2022-12-04 00:08:53 -08:00
Terry Janas
daf516bf9c Populate internal serial and version from PS3 disc (#432) 2022-12-04 00:03:29 -08:00
Matt Nadareski
115d9857af Add HD-DVD to speed definitions (fixes #429) 2022-12-02 14:39:17 -08:00
Matt Nadareski
b322146e9e Add .NET 6.0 to tests, remove msbuild args 2022-11-19 23:03:26 -08:00
Matt Nadareski
b6e3c9da82 Remove .NET 6.0 from tests, add TODO 2022-11-19 22:39:42 -08:00
Matt Nadareski
6abdc632dc Remove windows from test target 2022-11-19 20:49:59 -08:00
Matt Nadareski
335ca6d5ac Add Xbox Series X short name to list 2022-11-17 18:45:16 -08:00
Matt Nadareski
8752426694 Update changelog 2022-11-17 16:24:45 -08:00
Matt Nadareski
5357ba5900 Add Xbox Series X and PS5 to list, fix Acorn 2022-11-17 16:16:05 -08:00
Matt Nadareski
f2686096bd Add _drive file to zip for UIC (fixes #425) 2022-11-07 09:03:45 -08:00
Matt Nadareski
c4ef14ea3c Bump version to 2.4 2022-10-26 13:08:40 -07:00
Matt Nadareski
03668bd6af Update changelog 2022-10-25 21:11:16 -07:00
fuzzball
2d90a63ca7 Add + to positive offsets in a better way (#422) 2022-10-25 21:07:51 -07:00
Matt Nadareski
11e6e37331 Update changelog 2022-10-24 22:49:09 -07:00
Terry Janas
b229a2d59e Populate internal serial from PS5 disc (#423) 2022-10-24 21:06:57 -07:00
Matt Nadareski
c61af9316f Move to unused Chime class 2022-10-21 23:06:07 -07:00
Matt Nadareski
02e3040e1b Add unused notification method 2022-10-21 22:41:23 -07:00
Matt Nadareski
60bbe29435 Update changelog 2022-10-21 11:42:15 -07:00
Matt Nadareski
3274ea08aa Add PS4 version finding (tjanas) 2022-10-21 11:34:14 -07:00
Terry Janas
97a61dea32 Populate internal serial from PS4 disc (#421)
* Populate internal serial from PS4 disc

* Move GetPlayStation4Serial to that it precedes GetPlayStation4Version
2022-10-21 11:32:35 -07:00
Matt Nadareski
6cccf20b03 Fix layerbreak-based checks (fixes #399) 2022-10-21 11:06:27 -07:00
Matt Nadareski
0a7e17ed00 Fix readonly Filename info display 2022-10-20 14:21:09 -07:00
Matt Nadareski
706f75c0eb Fix readonly Filename info display 2022-10-20 14:21:03 -07:00
Matt Nadareski
022e87c4bb Fix NRE with offsets 2022-10-20 13:03:07 -07:00
Matt Nadareski
8b29ac7e47 Update issue templates to be more accurate 2022-10-20 13:00:07 -07:00
Matt Nadareski
4d5b8baf6f Add logging to !submissionInfo formatting failure 2022-10-20 12:45:01 -07:00
Matt Nadareski
e199e5a08c Add logging to !submissionInfo writing failure 2022-10-20 12:23:35 -07:00
Matt Nadareski
6cc2351bf7 Fix multiple DiscType* for DIC 2022-10-20 12:17:05 -07:00
Matt Nadareski
c391dbd3c8 Fix multiple DiscType for DIC 2022-10-19 23:23:04 -07:00
Matt Nadareski
709d980b67 Add disc type parsing for Aaru and DIC 2022-10-19 12:57:46 -07:00
Matt Nadareski
0903855d5c Add framework for reported disc type 2022-10-19 12:34:40 -07:00
Matt Nadareski
6ad2505bf8 Put Redump limitations behind existing flag 2022-10-18 17:03:21 -07:00
Matt Nadareski
5db8756639 Disable XGD1 PVD reporting 2022-10-18 16:18:49 -07:00
Matt Nadareski
5d176408a2 Disable XGD layerbreak reporting 2022-10-18 16:16:40 -07:00
Matt Nadareski
ab0b569798 Disable XGD version reporting 2022-10-18 16:12:40 -07:00
Matt Nadareski
ee76d49e56 Disable layerbreak generation for BD 2022-10-18 16:08:38 -07:00
Matt Nadareski
c75d2dcae2 Add + to positive offsets 2022-10-18 11:49:57 -07:00
Matt Nadareski
7c411d36db Add MS ZipFile package to MPF.Library 2022-10-17 21:04:58 -07:00
Matt Nadareski
ca767cf576 Change location of dumping info (fixes #415) 2022-10-17 20:56:28 -07:00
Matt Nadareski
b57e0bb97e Remove extraneous packages 2022-10-17 16:58:27 -07:00
Matt Nadareski
5f059253a4 Add CodePages package to MPF.Library 2022-10-17 16:42:04 -07:00
Matt Nadareski
e0f8443653 Add System.Memory package to MPF.Library 2022-10-17 16:20:41 -07:00
Matt Nadareski
4c23a4bbf3 Add compression result reason to log 2022-10-17 15:41:00 -07:00
Matt Nadareski
0c1486bbce Update BurnOutSharp to 2.3.4 2022-10-17 13:41:21 -07:00
Matt Nadareski
6f41c9a331 Remove deprecated protection setting 2022-10-17 11:14:41 -07:00
Matt Nadareski
2879dd29d6 Update Nuget packages 2022-10-17 11:00:51 -07:00
Matt Nadareski
42e1ef45b4 Add multi-language helper for filter 2022-10-16 23:15:09 -07:00
Matt Nadareski
19493fdf0c Add language filtering to formatter 2022-10-16 22:59:54 -07:00
Matt Nadareski
5870ad0673 Add unused article formatter 2022-10-16 21:21:56 -07:00
Matt Nadareski
cbd2850d1b Add specialized CDS/SafeDisc filter 2022-10-16 14:27:26 -07:00
Matt Nadareski
e7c36c104a Fix hardware info 2022-10-13 00:04:28 -07:00
Matt Nadareski
960840d9ba Add hardware info to DIC and Aaru 2022-10-12 21:40:38 -07:00
Matt Nadareski
b8ac1bc9d4 Fix missing info in Aaru 2022-10-12 21:27:58 -07:00
Matt Nadareski
89edf9a8f6 Create MPF log helper and filter for deletion 2022-10-11 13:19:06 -07:00
Matt Nadareski
eb8db0b311 Try adding MPF logs to zip 2022-10-11 12:54:11 -07:00
Matt Nadareski
b10cf8b78a Enable separated protection info output by default 2022-10-11 10:11:48 -07:00
Matt Nadareski
1dd5c0d6d0 Fix missing info reference change 2022-10-06 14:24:47 -07:00
Matt Nadareski
a1e00d23a4 Update Aaru submodules 2022-10-06 11:57:05 -07:00
Matt Nadareski
1a9d38dd0e Add dumping info section skeleton 2022-10-06 11:11:23 -07:00
Matt Nadareski
2f3e7d105d Add dumping info section skeleton 2022-10-06 10:25:27 -07:00
Matt Nadareski
a72b3c32b1 Report specific DIC version, if possible 2022-10-06 10:04:56 -07:00
Matt Nadareski
a479b16ae2 Add initial framework for reporting dumping program 2022-10-05 15:43:02 -07:00
Matt Nadareski
a9e7b6f5b3 Add unused command filename parser 2022-10-05 12:08:11 -07:00
Matt Nadareski
60605d7d00 Merge branch 'master' of https://github.com/SabreTools/MPF 2022-10-04 20:50:38 -07:00
Matt Nadareski
9dc7f726e9 Use default directory for folder browsing, if possible (fixes #412) 2022-10-04 20:45:28 -07:00
Whovian9369
46134032d6 Add a check for the PS4 Update file, and add some file info to the comments. (#411) 2022-10-04 20:14:50 -07:00
Markus Persson
9847c8f351 Update Drive.cs (#410)
Fixed console return typo.
2022-10-04 13:50:37 -07:00
Matt Nadareski
7b506586cd Add PS3 folder/file checks for detection (fixes #409) 2022-10-04 13:36:50 -07:00
Matt Nadareski
40bbd422b7 Possibly fix PIC parsing 2022-09-28 13:38:50 -07:00
Matt Nadareski
285fd69ab4 Update to DIC 20220909 2022-09-28 13:15:05 -07:00
Matt Nadareski
b436e19bbb Add important Redumper note 2022-09-28 13:04:17 -07:00
Matt Nadareski
bf6e079289 Minor Redumper cleanup 2022-09-28 12:49:17 -07:00
Matt Nadareski
b623866b6e Create Redumper extensions class 2022-09-28 12:43:40 -07:00
Matt Nadareski
df7046723c Add Redumper command generation 2022-09-28 12:38:23 -07:00
Matt Nadareski
3cd3047790 Add Redumper command validation 2022-09-28 12:22:14 -07:00
Matt Nadareski
abd60612c5 Add Redumper dumping command 2022-09-28 11:52:56 -07:00
Matt Nadareski
02292acee1 Add Redumper command support and reset 2022-09-28 11:48:25 -07:00
Matt Nadareski
c923899898 Add Redumper parameter values 2022-09-28 11:33:59 -07:00
Matt Nadareski
fcdd2ad036 Add Redumper constants 2022-09-28 11:23:04 -07:00
Matt Nadareski
02d3af0ac1 Download Redumper with AppVeyor 2022-09-28 11:12:03 -07:00
Matt Nadareski
0516bccece Add skeleton for Redumper 2022-09-27 23:08:12 -07:00
Matt Nadareski
2d6389d54d Fix ringcode guide images (fixes #407) 2022-09-27 22:54:23 -07:00
Matt Nadareski
60d5a117b5 Electronic not Electric (fixes #402) 2022-08-30 10:42:04 -07:00
Matt Nadareski
9b7e2e35f5 Verify GD-ROM outputs, finally (fixes #401) 2022-08-29 19:49:31 -07:00
Matt Nadareski
ddfb383f23 Add Sony Electronic Book system (fixes #400) 2022-08-29 10:42:20 -07:00
Matt Nadareski
a1707486f4 Update Aaru submodule to latest devel 2022-08-29 10:36:27 -07:00
Matt Nadareski
451101ec67 Update PSX content check 2022-08-25 14:38:28 -07:00
Matt Nadareski
83c583b7e6 Update to new constructor 2022-08-25 11:54:55 -07:00
Matt Nadareski
33cb3d3c97 Fix missing assignment 2022-08-25 11:36:42 -07:00
Matt Nadareski
3d98f345c1 Fix psxt001z namespace 2022-08-25 10:45:22 -07:00
Matt Nadareski
de8ce5c110 Add internal name for Cleanrip outputs (fixes #398) 2022-08-25 10:38:20 -07:00
Matt Nadareski
fd9ed77316 Fix missing parenthesis 2022-08-25 10:23:28 -07:00
Matt Nadareski
d974b73cce Fix serial parsing for Dreamcast (fixes #397) 2022-08-25 10:18:35 -07:00
Matt Nadareski
da8a67fcad Update to BurnOutSharp 2.3.1 (nw) 2022-08-25 10:11:28 -07:00
Matt Nadareski
471bc60ed7 Add Mattel Fisher-Price iXL detection 2022-08-25 10:07:15 -07:00
Matt Nadareski
fef46be34c Update to BurnOutSharp 2.3.0 (nw) 2022-08-25 09:48:37 -07:00
Matt Nadareski
9a92dbdedb Give .NET 6 priority for web calls 2022-07-26 13:47:19 -07:00
Matt Nadareski
d6be0a4154 Trim leading file paths for XBONE (fixes #394) 2022-07-25 09:38:02 -07:00
Matt Nadareski
d3ae372903 Disable nonstandard BD-ROM sizes 2022-07-08 22:05:24 -07:00
Matt Nadareski
7621ef1a13 Fix .bin file paths; update internal filename generation 2022-07-08 14:03:44 -07:00
Matt Nadareski
148fdd0590 Update to DIC 20220707 (possibly nw) 2022-07-08 13:37:51 -07:00
Matt Nadareski
232256310a Update changelog 2022-07-05 22:51:21 -07:00
Matt Nadareski
5e938791ef Add files for XBONE (fixes #390) 2022-07-05 22:43:28 -07:00
Matt Nadareski
08405dd9b4 Framework for XBONE filenames 2022-07-05 22:11:21 -07:00
Matt Nadareski
512c637ea3 Add Bandai Playdia QIS detection (fixes #393) 2022-07-05 22:06:04 -07:00
Matt Nadareski
909ebd72a1 Add Sharp X68k detection (fixes #387) 2022-07-05 22:02:31 -07:00
Matt Nadareski
123136e90e Fix incomplete system name detection 2022-05-29 14:07:38 -07:00
Matt Nadareski
299d25af27 Implement Drive.Create for safety 2022-04-20 13:47:55 -07:00
Matt Nadareski
9eee2f6444 Update changelog 2022-04-20 12:36:11 -07:00
Matt Nadareski
2afb10b73b Organize projects in solution 2022-04-20 12:33:47 -07:00
Matt Nadareski
1b016e5915 Add PIC.bin to log zip 2022-04-19 22:50:43 -07:00
Matt Nadareski
1c403e1748 Possibly fix tab regex replacement 2022-04-19 22:40:08 -07:00
Matt Nadareski
a372a133ca Reorganize GetMediaType 2022-04-19 21:07:09 -07:00
Matt Nadareski
08a7df504b Simplify IsOptical (.NET 6) 2022-04-19 20:39:42 -07:00
Matt Nadareski
39f9d9a86d Add optical media support method (.NET 6) 2022-04-19 20:25:36 -07:00
Matt Nadareski
bdd5af65ce Better get drive list (.NET 6) 2022-04-19 20:19:22 -07:00
Matt Nadareski
92d7d2ab91 Fix CD-R multisession info (fixes #384) 2022-04-19 17:12:37 -07:00
Matt Nadareski
8d4d7ce449 Update changelog 2022-04-19 16:53:58 -07:00
Matt Nadareski
d2d650cace Use Aaru for media type retrival (.NET 6) 2022-04-19 16:53:13 -07:00
Matt Nadareski
772cefd700 Multisession is multi-line 2022-04-19 12:49:18 -07:00
Matt Nadareski
e20350160b Add Aaru as a submodule for .NET 6 2022-04-18 22:59:07 -07:00
Matt Nadareski
08f4e91b27 Update solution file for VS2022 2022-04-18 21:53:20 -07:00
Matt Nadareski
021237bc38 Sync to newest CICM 2022-04-18 21:34:48 -07:00
Matt Nadareski
78c36db2f9 Avoid whitespace changes for PVD, Header, and Cuesheet 2022-04-18 21:20:12 -07:00
Matt Nadareski
7fd2562cb5 Add filesystem logging for .NET 6 2022-04-18 12:42:18 -07:00
Matt Nadareski
15a3be2e66 Update changelist 2022-04-18 11:03:34 -07:00
Matt Nadareski
9b6a540ec6 Remove .NET Core 3.1 entirely 2022-04-18 11:03:21 -07:00
Matt Nadareski
2b51085bc2 Remove .NET Core 3.1 from test project for now 2022-04-17 22:53:07 -07:00
Matt Nadareski
822134070b .NET 6.0 and Cleanup 2022-04-17 22:39:39 -07:00
Matt Nadareski
26cd874779 Update to BurnOutSharp 2.1.0 2022-04-17 22:14:13 -07:00
Matt Nadareski
9f21b68541 Use built-in NETFRAMEWORK directive 2022-04-17 21:54:04 -07:00
Matt Nadareski
e49d95663b Gate ManagmentObject use further 2022-04-17 21:30:04 -07:00
Matt Nadareski
2c70392ada Add size-based media type detection for non-Framework 2022-04-17 21:00:02 -07:00
Matt Nadareski
1b2248b1e7 Revert AppVeyor to VS2019 for now 2022-04-17 16:34:33 -07:00
Matt Nadareski
a322dc6353 Update copyright date to 2022 2022-04-17 16:29:28 -07:00
Matt Nadareski
7c78ae47c6 Remove needless csproj constants 2022-04-17 16:28:09 -07:00
Matt Nadareski
a14dec1b7e Update Nuget packages 2022-04-17 16:22:11 -07:00
Matt Nadareski
53b5862697 Update AppVeyor to VS2022 2022-04-17 16:19:33 -07:00
Matt Nadareski
83d379c7b5 Convert internal libraries to .NET Standard 2.0 2022-04-17 16:18:40 -07:00
Matt Nadareski
be33db8339 Sanitize whitespace around tabs 2022-04-16 12:15:23 -07:00
Matt Nadareski
97e9924a0b Be more picky about multisession 2022-04-12 22:04:55 -07:00
Matt Nadareski
7daab55639 Fix clone issue with copy protection 2022-04-12 21:22:49 -07:00
Matt Nadareski
9d70b7469a Convert triple space to tab 2022-04-12 17:03:32 -07:00
Matt Nadareski
b5504902c4 Parse and format CD multisession data (fixes #370) 2022-04-12 16:09:18 -07:00
Matt Nadareski
f5e82ccd75 Separate common arguments to new helper 2022-04-12 12:06:45 -07:00
Matt Nadareski
f4c4c21a10 Consolidate Redump login testing 2022-04-12 12:01:26 -07:00
Matt Nadareski
661d2440f2 Move helper methods around 2022-04-12 11:51:05 -07:00
Matt Nadareski
f4af8097f6 Move and update options loader; clean up Check 2022-04-12 11:27:10 -07:00
Matt Nadareski
e1822905e7 Add multisession helper method skeleton 2022-04-12 10:18:52 -07:00
Matt Nadareski
e5154dad5b Add multisession pseudo-tag 2022-04-12 10:10:07 -07:00
Matt Nadareski
30f8932039 Rename MPF.GUI to MPF.UI 2022-04-11 12:01:16 -07:00
Matt Nadareski
c4f0792c77 Create core UI library 2022-04-11 10:32:03 -07:00
Matt Nadareski
79c7f13ff9 Add warning to tooltip 2022-04-10 22:27:05 -07:00
Matt Nadareski
dbeeb0c69b Make protection field user-editable (fixes #340) 2022-04-10 22:23:15 -07:00
Matt Nadareski
58c53ff5e2 Add option for copy protection file output (fixes #372) 2022-04-10 22:12:20 -07:00
Matt Nadareski
87c441887a Convert status label to TextBlock (fixes #382) 2022-04-10 21:11:50 -07:00
Matt Nadareski
8ee4dab239 Combine cases in protection scan 2022-04-10 16:14:13 -07:00
Matt Nadareski
e01ebf8d8e Explicitly sanitize '?' from path 2022-04-09 13:21:31 -07:00
Matt Nadareski
e92bcd378c Disable PVD creation for Aaru 2022-04-08 20:55:33 -07:00
Matt Nadareski
80156e73d1 Even even stricter copy protection output 2022-04-07 20:56:28 -07:00
Matt Nadareski
97803cd860 Report dictionary to InfoTool 2022-04-04 22:44:15 -07:00
Matt Nadareski
9a5feee095 Even stricter output for copy protection section 2022-04-04 22:25:07 -07:00
Matt Nadareski
84410056bd Compress JSON for artifacts alone (fixes #379) 2022-04-04 22:15:50 -07:00
Matt Nadareski
acd0e41703 Further separate out protection scan outputs 2022-04-04 22:06:56 -07:00
Matt Nadareski
c7dfb9dca7 Increase JSON accuracy for disc types (fixes #381) 2022-04-04 21:46:13 -07:00
Matt Nadareski
0efd82bd59 Normalize newlines in comments and contents (fixes #380) 2022-04-04 21:12:50 -07:00
John Veness
426ceff451 Fix RingCodeGuideWindow.xaml so text matches images (#378)
* Fix RingCodeGuideWindow.xaml so text matches image

* Fix RingCodeGuideWindow.xaml so text matches img 2
2022-04-01 09:57:07 -07:00
Matt Nadareski
f2be7ed34c Update Nuget packages 2022-03-27 20:57:42 -07:00
Matt Nadareski
5dcc783b95 Fix a couple Redump URL-related things 2022-03-25 09:28:11 -07:00
Matt Nadareski
d1c641e934 Fix ring serialization (fixes #376) 2022-03-25 09:00:16 -07:00
Wilson
59be63785d Windows 7 UI Fix (#375)
* Updated the Main Menu grid width setting so that the Help menu now appears proprely on Windows 7.

* Changed the Secret log level color from Blue to Teal so that the text is much more readable.

* Undid the Secret color change.
2022-03-15 16:25:43 -07:00
Matt Nadareski
0bf85ec729 Refine copy protection section showing 2022-03-13 13:14:37 -07:00
Matt Nadareski
b54c2dc254 Clear out fully matched IDs from the partial list 2022-03-12 22:19:03 -08:00
Matt Nadareski
021fcd0641 Fix submission info clone 2022-03-12 22:06:04 -08:00
Matt Nadareski
f2dadae7a3 Add both fully and partially matching to info file 2022-03-12 21:27:23 -08:00
Matt Nadareski
7ce7df2625 Explicitly clear list, just in case 2022-03-12 21:14:26 -08:00
Matt Nadareski
09fcd384ab Make fully and partially matching IDs more apparent
Add write offset as read-only field
2022-03-12 21:09:51 -08:00
Matt Nadareski
5f8625a384 Fix tabs in Games and Videos boxes (fixes #373) 2022-03-09 15:34:44 -08:00
Matt Nadareski
621011af7a Remove redundant check around volume label 2022-03-09 14:25:01 -08:00
Matt Nadareski
a0b81941d1 Return faster on empty protection sets 2022-03-08 22:37:12 -08:00
Matt Nadareski
e735335773 Update Aaru Nuget package 2022-03-08 09:13:37 -08:00
Matt Nadareski
7b62572a56 Handle sanitized protections edge case 2022-03-06 22:19:04 -08:00
Matt Nadareski
0f921c926b Reorder event handers 2022-03-06 00:04:23 -08:00
Matt Nadareski
4d8a4d23c0 Add upper case <TAB> processing 2022-03-05 23:20:13 -08:00
Matt Nadareski
9d7eaa46fd Update to Aaru v5.3.1 LTS 2022-03-05 21:53:52 -08:00
Matt Nadareski
cc9664f7d6 Track last used drive on refresh; Clean up pre-dump validation 2022-03-05 21:50:18 -08:00
Matt Nadareski
573b3e9d1c Fix "missing" option in window 2022-03-05 21:05:34 -08:00
Matt Nadareski
9808694d89 Update changelog 2022-03-01 23:04:43 -08:00
Wilson
d70d8f5b6e Added a button to quickly update the volume label and dump path. (#369)
* Added a button to quickly update the volume label and dump path.
Behaves identically to switching the selected drive combo box. (Calls the InitializeUIValues method with rescanDrives set to false.)

* Typo fixed the odd w.
2022-03-01 21:43:05 -08:00
Matt Nadareski
b75c2d80bf Force internal drive refresh 2022-03-01 16:41:54 -08:00
Matt Nadareski
aa747ff651 Update to DIC 20220301 2022-03-01 13:27:31 -08:00
Matt Nadareski
bcbf5daf0d Add Xbox One system detection (fixes #368) 2022-02-24 11:22:04 -08:00
Matt Nadareski
aee1c05a45 Update Nuget packages to newest stable 2022-02-24 10:58:36 -08:00
Matt Nadareski
0bb96a8dd3 Specifically include Unsafe Nuget package 2022-02-22 09:08:29 -08:00
Matt Nadareski
1e1d2c7b63 Move path normalization to better place 2022-02-13 22:49:33 -08:00
Matt Nadareski
f12375cddc Assign normalized path to parameters 2022-02-12 23:25:34 -08:00
Matt Nadareski
ed26e6611a Cap X360 directory check to 500MB (fixes #362) 2022-02-11 12:59:37 -08:00
Matt Nadareski
98f77eca07 Add option to limit region and language selections (fixes #361) 2022-02-11 09:55:00 -08:00
Matt Nadareski
1b2b560f8f Fix failing module tests 2022-02-10 13:40:07 -08:00
Matt Nadareski
b49cc0c9bd Fix small DVD layer finding corner case (fixes #363) 2022-02-10 12:02:54 -08:00
Matt Nadareski
4ba58ea861 Make FillFromRedump private again 2022-02-10 11:54:25 -08:00
Matt Nadareski
3f52a20c90 Add /mr default flag options (fixes #360) 2022-02-10 11:52:13 -08:00
Matt Nadareski
580089d06e Fix Redump disc title pulling (fixes #359) 2022-02-10 11:37:36 -08:00
Matt Nadareski
1397ab0fa6 Update to DIC 20211001
Note that there are some code changes that could affect how things like offsets are parsed. Testing is needed.
2022-02-10 11:21:38 -08:00
88 changed files with 17102 additions and 1729 deletions

View File

@@ -10,7 +10,7 @@ assignees: mnadareski
**Before You Submit**
- Remember to try the [latest WIP build](https://ci.appveyor.com/project/mnadareski/mpf/build/artifacts) to see if the feature already exists.
- Is it copy protection related? If so, report the issue [here](https://github.com/mnadareski/BurnOutSharp/issues) instead.
- .NET Core 3.1 and .NET 5.0 have known limitations, so make sure that what you're asking for isn't already in another build.
- .NET 6.0 has known limitations, so make sure that what you're asking for isn't already in another build.
- Check [previous issues](https://github.com/SabreTools/MPF/issues) to see if any of those are related to what you're about to ask for.
If none of those apply, then continue...

View File

@@ -10,7 +10,7 @@ assignees: mnadareski
**Before You Submit**
- Remember to try the [latest WIP build](https://ci.appveyor.com/project/mnadareski/mpf/build/artifacts) to see if the feature already exists.
- Is it copy protection related? If so, report the issue [here](https://github.com/mnadareski/BurnOutSharp/issues) instead.
- .NET Core 3.1 and .NET 5.0 have known limitations, so make sure that what you're giving information on isn't already in another build.
- .NET 6.0 has known limitations, so make sure that what you're giving information on isn't already in another build.
- Check [previous issues](https://github.com/SabreTools/MPF/issues) to see if any of those are related to what you're about to ask for.
If none of those apply, then continue...

View File

@@ -10,7 +10,7 @@ assignees: mnadareski
**Before You Submit**
- Remember to try the [latest WIP build](https://ci.appveyor.com/project/mnadareski/mpf/build/artifacts) to see if the issue has already been addressed.
- Is it copy protection related? If so, report the issue [here](https://github.com/mnadareski/BurnOutSharp/issues) instead.
- .NET Core 3.1 and .NET 5.0 have known issues, please try using another build to reproduce the error
- .NET 6.0 has known issues, please try using another build to reproduce the error
- Check multiple discs to help narrow down the issue
- Check the Options to see if changing any of those affects your issue.
@@ -25,9 +25,8 @@ What version are you using?
**Build**
What runtime version are you using?
- [ ] .NET Framework 4.7.2 running on (Operating System)
- [ ] .NET Framework 4.8 running on (Operating System)
- [ ] .NET Core 3.1 running on (Operating System)
- [ ] .NET 6.0 running on (Operating System)
**Describe the issue**
A clear and concise description of what the bug is.

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "MPF.Library/Aaru/CICMMetadata"]
path = CICMMetadata
url = https://github.com/claunia/CICMMetadata

4
.vscode/launch.json vendored
View File

@@ -10,9 +10,9 @@
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/MPF/bin/Debug/netcoreapp3.1/MPF.dll",
"program": "${workspaceFolder}/MPF.Check/bin/Debug/net6.0/MPF.Check.dll",
"args": [],
"cwd": "${workspaceFolder}/MPF",
"cwd": "${workspaceFolder}/MPF.Check",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"omnisharp.projectLoadTimeout": 480
}

15
.vscode/tasks.json vendored
View File

@@ -3,25 +3,22 @@
"tasks": [
{
"label": "build",
"command": "dotnet",
"command": "msbuild",
"type": "process",
"args": [
"build",
"${workspaceFolder}/MPF/MPF.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
"${workspaceFolder}/MPF.sln",
"-property:RuntimeIdentifiers=win7-x64"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"command": "msbuild",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/MPF/MPF.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
"-target:Publish",
"-property:RuntimeIdentifiers=win7-x64"
],
"problemMatcher": "$msCompile"
},

View File

@@ -1,4 +1,405 @@
### 2.6.2 (2023-07-25)
- Ensure custom parameters properly set
- Universal hash only for audio discs
- Support LibCrypt data from Redumper
- Always show extension for Redumper
- Normalize old universal hash text
- Skip extra tracks during checking
- Modify the track count on checking
- Attempt to match universal hash
- Fix .NET Framework 4.8 build
- Fix universal hash URL generation
- Add Windows publish script
- Add *nix publish script
- Add build instructions to README
- Clarify build instructions
### 2.6.1 (2023-07-19)
- Simplify Redumper error value extraction
- Don't pull comment fields that auto-populate
- Set best compression levels for log files
- Be more explicit about .NET 6 limitation
- Set extensions for Redumper in UI
- Fix comment field pulling again
### 2.6 (2023-07-14)
- Update README
- Add warning to login tab
- Pull hardware info from redumper log (fuzz6001)
- Increase the version of AppVeyor (fuzz6001)
- Add Windows 7 note to README
- Update redumper to build 113
- Split MMI invocation in drive listing
- Update README
- Add Hasbro iON
- Get the write offset from the latest redumper (fuzz6001)
- Update redumper to build 115
- Update to DIC 20230401
- Add DIC `.` notice to README
- Resync with Redump
- Update redumper to build 118
- Clarify non-Redump systems
- Add UltraCade
- Re-enable BD33 and BD66
- Add PIC models for BD (unused)
- Handle PIC based on disc type
- UMDs always have "2 layers"
- Add dumping program selection to main UI
- Update to DIC 20230413
- Comment out `.` handling for DIC
- Ensure dumping program box can enable/disable
- Disable special SmartE handling for DIC
- Remove path from PS1/PS2 serial
- Make TOC file optional for CD/GD
- Add datafile models
- Add datafile helper method
- Start migrating to datafile serialization
- Prepare for future DIC changes
- Add suppl support to Xbox
- Support single digit subs
- Fix info tool hash finding
- Fix missing size for ISO data
- Attempt to more accurately parse layerbreaks
- Fix upcoming suppl DAT parsing
- Ensure blank lines don't interfere
- De-indent ringcode data
- Be more specific with runtime identifiers
- Fix subdump output path in AV config
- Fix subdump mkdir path in AV config
- Single file packing for .NET 6 again
- Add missing BD disc type identifier string
- Truncate PIC data for PS4/PS5
- Add internal theme support with class
- Add PIC identifier to SubmissionInfo
- Fix other media type method
- Fix non-zero offset text
- Add executable listing for XSX
- Update redumper to build 151
- Add more safety to DAT generation
- Get write offset from redumper 119 (fuzz6001)
- Update hardware information pull from redumper (fuzz6001)
- Add MCD/SS header support for Redumper
- Fix MCD region(s) parsing
- Update to DIC 20230606
- Update redumper to build 166
- Unblock Redumper DVD support
- Support Redumper DVD layerbreak
- Add placeholder and TODOs for Redumper
- Add TODO with notes to Redumper
- Fix 2-layer DVD support in Redumper
- Fix VSCode build
- Fix Redumper DAT/layer parsing
- Update Redumper PS1 output parsing
- Fix previous commit, clean up helpers
- Update redumper to build 173
- Initial support for Redumper CSS outputs
- Hook up CSS output for testing
- Update redumper to build 174
- Add support for redumper CD synonyms
- Adjust CSS title key parsing
- Fix non-reading loop
- Normalize Redumper CSS outputs
- Normalize multi-instance site tags
- Add missing Aaru error log to zip
- Check Redumper dat section for completeness
- Update redumper to build 176
- UMDs are Sony discs
- Strip colons from Redumper disc key
- Use `HashSet` for disc or book type
- Add ordering to disc or book type
- Update redumper to build 183
- Parse and format Redumper CD multisession data
- New layerbreak takes precedence
- Reduce pulled information for Xbox and X360
- Ensure we found the tags we're skipping
- Omit pulling universal hash
- Update Nuget packages to newest stable
### 2.5 (2023-03-12)
- Add _drive file to zip for UIC
- Add Xbox Series X and PS5 to list, fix Acorn
- Add Xbox Series X short name to list
- Remove windows from test target
- Remove .NET 6.0 from tests, add TODO
- Add .NET 6.0 to tests, remove msbuild args
- Add HD-DVD to speed definitions
- Add PS3 internal serial and version parsing (tjanas)
- Update Nuget packages to newest stable
- Simplify path selection in UI
- Fix broken normalization test
- Update drive info before dumping
- Update redumper strings
- Add new parameter and mode validation
- Add redumper to the UI
- Update redumper to build 81
- Fix incorrect naming in Options window
- Initial attempt at parsing redumper outputs
- Update README
- Reenable write offset for all CDs
- Add missing redumper output file
- Force a filename for redumper
- Fix incorrect SetParameters
- Fix a couple redumper things
- Update AppVeyor version
- Output security sectors to info
- Remove x86 requirement for build
- Fix XGD media type outputs
- Fix typo in ToInternalProgram
- Fix redumper error count parsing
- Update to Aaru v5.3.2 LTS
- Update options loader with sane defaults
- Fix AppVeyor pathing
- Skip during detection
- Address some UI concerns
- Tweak AppVeyor, show Check 6.0 builds
- More strict when custom parameters editing
- Use msbuild for .NET Framework 4.8
- Update nuget packages
- ReadAllText not ReadAllLines
- Add drive format (fs) to log
- Go back to pre .NET 7 Aaru
- Be smarter about old paths
- Fix relative paths for DIC
- Add nicer failure message
- Update to DIC 20230201
- Use relative path output for DIC
- Remove usage of Aaru
- Remove Aaru as submodule
- Fix Aaru removal
- Enable .NET 6 Windows builds
- Update Redumper to build_106
- Reformat CICM for old .NET versions
- Attempt to handle no drives
- Handle no drives better
- Handle no drives betterer
- Packaging requires `-windows` for framework
- Fix other `-windows` places for .NET 6
- Fix typo in DICMultiSectorReadValue
- Semi-unify drive finding
- Introduce cross-platform MMI
- Remove System.Management
- Add Redumper Universal Hash support
- Fix Redumper write offset support
- Add Redumper non-zero data start
- Use media size for type detection on .NET 6
- Trim PIC for PS3
- Get the version of redumper (fuzz6001)
- Update VSCode config files
- Can't publish single file for UI
- Handle missing extension gracefully
- Fix incorrect option slider display
- Handle undetected discs on refresh
- Originally intended behaviour of the Update Label button (IcySon55)
- Update to BurnOutSharp 2.7.0
- Get error count from recent redumper log (fuzz6001)
- Minor cosmetic changes
- Set saner defaults for dumping speeds
- Attempt to support Windows 7
- Add `win7-x64` to identifier list
- Remove unsupported identifiers
- Add identifiers in more places
- Move drive finding inside of the try/catch
- Update to DIC 20230309
- Fix errant forward slashes
- Add TOC back as optional file
- Fix Redumper path generation
- Use and trim quotes for Redumper
- Fix incorrect image name setting
- Ensure Redumper parameters are set
- Ensure min values are taken care of
- Update parameters with `=` handling
- Ensure drive and speed are set
- Handle quotes embedded
- Return list of missing files for Redumper
- Readd accidentally deleted line
- Detect EOF during the search for error counts (fuzz6001)
### 2.4 (2022-10-26)
- Update to DIC 20211001
- Fix Redump disc title pulling
- Add /mr default flag options
- Make FillFromRedump private again
- Fix DVD layer finding corner case
- Fix failing module tests
- Add option to limit region and language selections
- Cap X360 directory check to 500MB
- Assign normalized path to parameters
- Move path normalization to better place
- Specifically include Unsafe Nuget package
- Update Nuget packages to newest stable
- Add Xbox One system detection
- Update to DIC 20220301
- Force internal drive refresh
- Add single drive refresh button (IcySon55)
- Fix "missing" option in window
- Track last used drive on refresh
- Clean up pre-dump validation
- Update to Aaru v5.3.1 LTS
- Add upper case `<TAB>` processing
- Reorder event handers
- Handle sanitized protections edge case
- Update Aaru Nuget package
- Return faster on empty protection sets
- Remove redundant check around volume label
- Fix tabs in Games and Videos boxes
- Make fully and partially matching IDs more apparent
- Add write offset as read-only field
- Explicitly clear list, just in case
- Add both fully and partially matching to info file
- Fix submission info clone
- Clear out fully matched IDs from the partial list
- Refine copy protection section showing
- Update Nuget packages
- Normalize newlines in comments and contents
- Increase JSON accuracy for disc types
- Further separate out protection scan outputs
- Compress JSON for artifacts alone
- Even stricter output for copy protection section
- Report dictionary to InfoTool
- Even even stricter copy protection output
- Disable PVD creation for Aaru
- Explicitly sanitize '?' from path
- Combine cases in protection scan
- Convert status label to TextBlock
- Add option for copy protection file output
- Make protection field user-editable
- Add warning to tooltip
- Create core UI library
- Rename MPF.GUI to MPF.UI
- Add multisession pseudo-tag
- Add multisession helper method skeleton
- Move and update options loader; clean up Check
- Move helper methods around
- Consolidate Redump login testing
- Separate common arguments to new helper
- Parse and format CD multisession data
- Convert triple space to tab
- Fix clone issue with copy protection
- Be more picky about multisession
- Sanitize whitespace around tabs
- Convert internal libraries to .NET Standard 2.0
- Update AppVeyor to VS2022
- Update Nuget packages
- Remove needless csproj constants
- Update copyright date to 2022
- Revert AppVeyor to VS2019 for now
- Add size-based media type detection for non-Framework
- Gate ManagmentObject use further
- Use built-in NETFRAMEWORK directive
- Update to BurnOutSharp 2.1.0
- .NET 6.0 and Cleanup
- Remove .NET Core 3.1 from test project for now
- Remove .NET Core 3.1 entirely
- Add filesystem logging for .NET 6
- Avoid whitespace changes for PVD, Header, and Cuesheet
- Sync to newest CICM
- Update solution file for VS2022
- Add Aaru as a submodule for .NET 6
- Multisession is multi-line
- Use Aaru for media type retrival (.NET 6)
- Fix CD-R multisession info
- Better get drive list (.NET 6)
- Add optical media support method (.NET 6)
- Simplify IsOptical (.NET 6)
- Reorganize GetMediaType
- Possibly fix tab regex replacement
- Add PIC.bin to log zip
- Organize projects in solution
- Implement Drive.Create for safety
- Fix incomplete system name detection
- Add Sharp X68k detection
- Add Bandai Playdia QIS detection
- Framework for XBONE filenames
- Add files for XBONE
- Update to DIC 20220707
- Fix .bin file paths; update internal filename generation
- Disable nonstandard BD-ROM sizes
- Trim leading file paths for XBONE
- Give .NET 6 priority for web calls
- Update to BurnOutSharp 2.3.0 (nw)
- Add Mattel Fisher-Price iXL detection
- Update to BurnOutSharp 2.3.1 (nw)
- Fix serial parsing for Dreamcast
- Fix missing parenthesis
- Add internal name for Cleanrip outputs
- Fix psxt001z namespace
- Fix missing assignment
- Update to new constructor
- Update PSX content check
- Update Aaru submodule to latest devel
- Add Sony Electronic Book system
- Verify GD-ROM outputs, finally
- Electronic not Electric
- Fix ringcode guide images
- Add skeleton for Redumper
- Download Redumper with AppVeyor
- Add Redumper constants
- Add Redumper parameter values
- Add Redumper command support and reset
- Add Redumper dumping command
- Add Redumper command validation
- Add Redumper command generation
- Create Redumper extensions class
- Minor Redumper cleanup
- Add important Redumper note
- Update to DIC 20220909
- Possibly fix PIC parsing
- Add PS3 folder/file checks for detection
- Use default directory for folder browsing, if possible
- Add unused command filename parser
- Add initial framework for reporting dumping program
- Report specific DIC version, if possible
- Add dumping info section skeleton
- Update Aaru submodules
- Fix missing info reference change
- Enable separated protection info output by default
- Try adding MPF logs to zip
- Create MPF log helper and filter for deletion
- Fix missing info in Aaru
- Add hardware info to DIC and Aaru
- Fix hardware info
- Add specialized CDS/SafeDisc filter
- Add unused article formatter
- Add language filtering to formatter
- Add multi-language helper for filter
- Update Nuget packages
- Remove deprecated protection setting
- Update BurnOutSharp to 2.3.4
- Add compression result reason to log
- Add System.Memory package to MPF.Library
- Add CodePages package to MPF.Library
- Remove extraneous packages
- Change location of dumping info
- Add MS ZipFile package to MPF.Library
- Add + to positive offsets
- Disable layerbreak generation for BD
- Disable XGD version reporting
- Disable XGD layerbreak reporting
- Disable XGD1 PVD reporting
- Put Redump limitations behind existing flag
- Add framework for reported disc type
- Add disc type parsing for Aaru and DIC
- Fix multiple DiscType for DIC
- Fix multiple DiscType* for DIC
- Add logging to !submissionInfo writing failure
- Add logging to !submissionInfo formatting failure
- Update issue templates to be more accurate
- Fix NRE with offsets
- Fix readonly Filename info display
- Fix layerbreak-based checks
- Add PS4 serial finding (tjanas)
- Add unused notification method
- Move to unused Chime class
- Add PS5 serial finding (tjanas)
- Fix offset formatting (fuzz6001)
### 2.3 (2022-02-05)
- Start overhauling Redump information pulling, again
- Add internal structure for special site codes
- Add new tabs for special site information
@@ -83,6 +484,7 @@
- Adjust paths for DIC just before dumping
### 2.2 (2021-12-30)
- Fix Saturn header finding
- Add Pocket PC support
- Add HD-DVD-Video support
@@ -134,6 +536,7 @@
- Add safety around volume labels
### 2.1 (2021-07-22)
- Enum, no more
- Sony works backward
- Add experimental dark mode
@@ -163,6 +566,7 @@
- Update to BurnOutSharp 1.7.0
### 2.0 (2021-04-23)
- Rename DICUI to Media Preservation Frontend (MPF)
- Add handling for BEh drive _mainInfo.txt changes
- Fix multiline regex fields during info pulling
@@ -217,6 +621,7 @@
- Update to BurnOutSharp 1.6.1
### 1.18 (2020-11-10)
- Add more information extraction and generation for Aaru
- Remove instances of CD Check from copy protection (again, sorry)
- Fix multiline submission info outputs
@@ -241,6 +646,7 @@
- Added HD-DVD-Video detection
### 1.17.1 (2020-09-14)
- Shuffled some shared, internal UI variables
- Synced WPF and Avalonia UI internals
- Made the disc information window less prone to bugs
@@ -248,6 +654,7 @@
- Added support for old(?) DIC flags: `/fix` and `/re`
### 1.17 (2020-09-12)
- Updated to Aaru version 5.1
- Updated to BurnOutSharp version 1.4.0
- Updated to DIC version 20200716

Submodule CICMMetadata deleted from 7944bca8e6

View File

@@ -1,16 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;netcoreapp3.1;net5.0</TargetFrameworks>
<PlatformTarget>x86</PlatformTarget>
<TargetFrameworks>net48;net6.0</TargetFrameworks>
<RuntimeIdentifiers>win7-x64;win8-x64;win81-x64;win10-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<OutputType>Exe</OutputType>
<Title>MPF Check</Title>
<AssemblyName>MPF.Check</AssemblyName>
<Description>Validator for various dumping programs</Description>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2021</Copyright>
<Copyright>Copyright (c)2019-2023</Copyright>
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
<Version>2.3</Version>
<Version>2.6.2</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<FileVersion>$(Version)</FileVersion>
<IncludeSource>true</IncludeSource>
@@ -28,10 +28,10 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="1.8.0" GeneratePathProperty="true">
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="2.8.0" GeneratePathProperty="true">
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.1">
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
@@ -42,10 +42,8 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj">
<Project>{51ab0928-13f9-44bf-a407-b6957a43a056}</Project>
<Name>MPF.Library</Name>
</ProjectReference>
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj" />
<ProjectReference Include="..\RedumpLib\RedumpLib.csproj" />
</ItemGroup>

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Linq;
using BurnOutSharp;
using MPF.Core.Converters;
using MPF.Core.Data;
@@ -15,126 +14,17 @@ namespace MPF.Check
{
public static void Main(string[] args)
{
// Help options
if (args.Length == 0 || args[0] == "-h" || args[0] == "-?")
{
DisplayHelp();
// Try processing the standalone arguments
if (ProcessStandaloneArguments(args))
return;
}
// List options
if (args[0] == "-lm" || args[0] == "--listmedia")
{
ListMediaTypes();
Console.ReadLine();
// Try processing the common arguments
(bool success, MediaType mediaType, RedumpSystem? knownSystem) = ProcessCommonArguments(args);
if (!success)
return;
}
else if (args[0] == "-lp" || args[0] == "--listprograms")
{
ListPrograms();
Console.ReadLine();
return;
}
else if (args[0] == "-ls" || args[0] == "--listsystems")
{
ListSystems();
Console.ReadLine();
return;
}
// Normal operation check
if (args.Length < 3)
{
DisplayHelp("Invalid number of arguments");
return;
}
// Check the MediaType
var mediaType = EnumConverter.ToMediaType(args[0].Trim('"'));
if (mediaType == MediaType.NONE)
{
DisplayHelp($"{args[0]} is not a recognized media type");
return;
}
// Check the RedumpSystem
var knownSystem = Extensions.ToRedumpSystem(args[1].Trim('"'));
if (knownSystem == null)
{
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, json = 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].Equals("-s") || args[startIndex].Equals("--scan"))
{
scan = true;
}
// Output submission JSON
else if (args[startIndex].Equals("-j") || args[startIndex].Equals("--json"))
{
json = true;
}
// Compress log and extraneous files
else if (args[startIndex].Equals("-z") || args[startIndex].Equals("--zip"))
{
compress = true;
}
// Default, we fall out
else
{
break;
}
}
(Core.Data.Options options, string path, int startIndex) = OptionsLoader.LoadFromArguments(args, startIndex: 2);
// Make new Progress objects
var resultProgress = new Progress<Result>();
@@ -142,20 +32,14 @@ namespace MPF.Check
var protectionProgress = new Progress<ProtectionProgress>();
protectionProgress.ProgressChanged += ProgressUpdated;
// If credentials are invalid, alert the user
if (!string.IsNullOrWhiteSpace(username) && !string.IsNullOrWhiteSpace(password))
{
using (RedumpWebClient wc = new RedumpWebClient())
{
bool? loggedIn = wc.Login(username, password);
if (loggedIn == true)
Console.WriteLine("Redump username and password accepted!");
else if (loggedIn == false)
Console.WriteLine("Redump username and password denied!");
else
Console.WriteLine("An error occurred validating your crendentials!");
}
}
// Validate the supplied credentials
#if NET48 || NETSTANDARD2_1
(bool? _, string message) = RedumpWebClient.ValidateCredentials(options?.RedumpUsername, options?.RedumpPassword);
#else
(bool? _, string message) = RedumpHttpClient.ValidateCredentials(options?.RedumpUsername, options?.RedumpPassword).ConfigureAwait(false).GetAwaiter().GetResult();
#endif
if (!string.IsNullOrWhiteSpace(message))
Console.WriteLine(message);
// Loop through all the rest of the args
for (int i = startIndex; i < args.Length; i++)
@@ -171,24 +55,11 @@ namespace MPF.Check
string filepath = Path.GetFullPath(args[i].Trim('"'));
// Now populate an environment
var options = new Options
{
InternalProgram = EnumConverter.ToInternalProgram(internalProgram),
ScanForProtection = scan && !string.IsNullOrWhiteSpace(path),
PromptForDiscInformation = false,
ShowDiscEjectReminder = false,
OutputSubmissionJSON = json,
CompressLogFiles = compress,
RedumpUsername = username,
RedumpPassword = password,
};
Drive drive = null;
if (!string.IsNullOrWhiteSpace(path))
drive = new Drive(null, new DriveInfo(path));
drive = Drive.Create(null, path);
var env = new DumpEnvironment(options, "", filepath, drive, knownSystem, mediaType, null);
var env = new DumpEnvironment(options, filepath, drive, knownSystem, mediaType, internalProgram: null, parameters: null);
// Finally, attempt to do the output dance
var result = env.VerifyAndSaveDumpOutput(resultProgress, protectionProgress).ConfigureAwait(false).GetAwaiter().GetResult();
@@ -214,61 +85,94 @@ namespace MPF.Check
Console.WriteLine("-ls, --listsystems List supported system types");
Console.WriteLine("-lp, --listprograms List supported dumping program outputs");
Console.WriteLine();
Console.WriteLine("Check Options:");
Console.WriteLine("-c, --credentials <user> <pw> Redump username and password");
Console.WriteLine("-u, --use <program> Dumping program output type");
Console.WriteLine("-p, --path <drivepath> Physical drive path for additional checks");
Console.WriteLine("-s, --scan Enable copy protection scan (requires --path)");
Console.WriteLine("-j, --json Enable submission JSON output");
Console.WriteLine("-z, --zip Enable log file compression");
var supportedArguments = OptionsLoader.PrintSupportedArguments();
foreach (string argument in supportedArguments)
{
Console.WriteLine(argument);
}
Console.WriteLine();
}
/// <summary>
/// List all media types with their short usable names
/// Process common arguments for all functionality
/// </summary>
private static void ListMediaTypes()
/// <returns>True if all arguments pass, false otherwise</returns>
private static (bool, MediaType, RedumpSystem?) ProcessCommonArguments(string[] args)
{
Console.WriteLine("Supported Media Types:");
foreach (var val in Enum.GetValues(typeof(MediaType)))
// All other use requires at least 3 arguments
if (args.Length < 3)
{
if (((MediaType)val) == MediaType.NONE)
continue;
Console.WriteLine($"{((MediaType?)val).ShortName()} - {((MediaType?)val).LongName()}");
DisplayHelp("Invalid number of arguments");
return (false, MediaType.NONE, null);
}
// Check the MediaType
var mediaType = EnumConverter.ToMediaType(args[0].Trim('"'));
if (mediaType == MediaType.NONE)
{
DisplayHelp($"{args[0]} is not a recognized media type");
return (false, MediaType.NONE, null);
}
// Check the RedumpSystem
var knownSystem = Extensions.ToRedumpSystem(args[1].Trim('"'));
if (knownSystem == null)
{
DisplayHelp($"{args[1]} is not a recognized system");
return (false, MediaType.NONE, null);
}
return (true, mediaType, knownSystem);
}
/// <summary>
/// List all programs with their short usable names
/// Process any standalone arguments for the program
/// </summary>
private static void ListPrograms()
/// <returns>True if one of the arguments was processed, false otherwise</returns>
private static bool ProcessStandaloneArguments(string[] args)
{
Console.WriteLine("Supported Programs:");
foreach (var val in Enum.GetValues(typeof(InternalProgram)))
// Help options
if (args.Length == 0 || args[0] == "-h" || args[0] == "-?")
{
if (((InternalProgram)val) == InternalProgram.NONE)
continue;
Console.WriteLine($"{((InternalProgram?)val).LongName()}");
DisplayHelp();
return true;
}
}
/// <summary>
/// List all systems with their short usable names
/// </summary>
private static void ListSystems()
{
Console.WriteLine("Supported Known Systems:");
var knownSystems = Enum.GetValues(typeof(RedumpSystem))
.OfType<RedumpSystem?>()
.Where(s => s != null && !s.IsMarker() && s.GetCategory() != SystemCategory.NONE)
.OrderBy(s => s.LongName() ?? string.Empty);
foreach (var val in knownSystems)
// List options
if (args[0] == "-lm" || args[0] == "--listmedia")
{
Console.WriteLine($"{val.ShortName()} - {val.LongName()}");
Console.WriteLine("Supported Media Types:");
foreach (string mediaType in Extensions.ListMediaTypes())
{
Console.WriteLine(mediaType);
}
Console.ReadLine();
return true;
}
else if (args[0] == "-lp" || args[0] == "--listprograms")
{
Console.WriteLine("Supported Programs:");
foreach (string program in EnumExtensions.ListPrograms())
{
Console.WriteLine(program);
}
Console.ReadLine();
return true;
}
else if (args[0] == "-ls" || args[0] == "--listsystems")
{
Console.WriteLine("Supported Systems:");
foreach (string system in Extensions.ListSystems())
{
Console.WriteLine(system);
}
Console.ReadLine();
return true;
}
return false;
}
/// <summary>

View File

@@ -2,7 +2,7 @@
using System.Collections.Concurrent;
using System.IO;
using System.Reflection;
#if NET_FRAMEWORK
#if NETFRAMEWORK
using IMAPI2;
#endif
using MPF.Core.Data;
@@ -34,7 +34,7 @@ namespace MPF.Core.Converters
}
}
#if NET_FRAMEWORK
#if NETFRAMEWORK
/// <summary>
/// Convert IMAPI physical media type to a MediaType
/// </summary>
@@ -98,7 +98,6 @@ namespace MPF.Core.Converters
if (!LongNameMethods.TryGetValue(sourceType, out MethodInfo method))
{
method = typeof(RedumpLib.Data.Extensions).GetMethod("LongName", new[] { typeof(Nullable<>).MakeGenericType(sourceType) });
if (method == null)
method = typeof(EnumConverter).GetMethod("LongName", new[] { typeof(Nullable<>).MakeGenericType(sourceType) });
@@ -135,6 +134,8 @@ namespace MPF.Core.Converters
return "dd";
case InternalProgram.DiscImageCreator:
return "DiscImageCreator";
case InternalProgram.Redumper:
return "redumper";
#endregion
@@ -183,6 +184,9 @@ namespace MPF.Core.Converters
return InternalProgram.DiscImageCreator;
case "dd":
return InternalProgram.DD;
case "rd":
case "redumper":
return InternalProgram.Redumper;
// Verification support only
case "cleanrip":

View File

@@ -19,6 +19,7 @@ namespace MPF.Core.Data
// Private lists of known drive speed ranges
private static IReadOnlyList<int> CD { get; } = new List<int> { 1, 2, 3, 4, 6, 8, 12, 16, 20, 24, 32, 40, 44, 48, 52, 56, 72 };
private static IReadOnlyList<int> DVD { get; } = CD.Where(s => s <= 24).ToList();
private static IReadOnlyList<int> HDDVD { get; } = CD.Where(s => s <= 24).ToList();
private static IReadOnlyList<int> BD { get; } = CD.Where(s => s <= 16).ToList();
private static IReadOnlyList<int> Unknown { get; } = new List<int> { 1 };
@@ -35,10 +36,11 @@ namespace MPF.Core.Data
case MediaType.GDROM:
return CD;
case MediaType.DVD:
case MediaType.HDDVD:
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
return DVD;
case MediaType.HDDVD:
return HDDVD;
case MediaType.BluRay:
return BD;
default:
@@ -82,13 +84,19 @@ namespace MPF.Core.Data
// Automatic Information
public const string DumpingProgramField = "Dumping Program";
public const string DumpingDriveManufacturer = "Manufacturer";
public const string DumpingDriveModel = "Model";
public const string DumpingDriveFirmware = "Firmware";
public const string ReportedDiscType = "Reported Disc Type";
public const string PVDField = "Primary Volume Descriptor (PVD)";
public const string DATField = "DAT";
public const string SizeField = "Size";
public const string CRC32Field = "CRC32";
public const string MD5Field = "MD5";
public const string SHA1Field = "SHA1";
public const string MatchingIDsField = "Matching IDs";
public const string FullyMatchingIDField = "Fully Matching ID";
public const string PartiallyMatchingIDsField = "Partially Matching IDs";
public const string ErrorCountField = "Error Count";
public const string CuesheetField = "Cuesheet";
public const string SubIntentionField = "SubIntention Data (SecuROM/LibCrypt)";

View File

@@ -2,15 +2,13 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Management;
using Microsoft.Management.Infrastructure;
using Microsoft.Management.Infrastructure.Generic;
using MPF.Core.Converters;
using MPF.Core.Utilities;
using RedumpLib.Data;
#if NET_FRAMEWORK
#if NETFRAMEWORK
using IMAPI2;
#else
using Aaru.CommonTypes.Enums;
using AaruDevices = Aaru.Devices;
#endif
namespace MPF.Core.Data
@@ -18,8 +16,14 @@ namespace MPF.Core.Data
/// <summary>
/// Represents information for a single drive
/// </summary>
/// <remarks>
/// TODO: This needs to be less Windows-centric. Devices do not always have a single letter that can be used.
/// TODO: Can the Aaru models be used instead of the ones I've created here?
/// </remarks>
public class Drive
{
#region Fields
/// <summary>
/// Represents drive type
/// </summary>
@@ -28,41 +32,32 @@ namespace MPF.Core.Data
/// <summary>
/// Drive partition format
/// </summary>
public string DriveFormat => driveInfo?.DriveFormat;
/// <summary>
/// Windows drive letter
/// </summary>
public char Letter => driveInfo?.Name[0] ?? '\0';
public string DriveFormat { get; private set; } = null;
/// <summary>
/// Windows drive path
/// </summary>
public string Name => driveInfo?.Name;
public string Name { get; private set; } = null;
/// <summary>
/// Represents if Windows has marked the drive as active
/// </summary>
public bool MarkedActive => driveInfo?.IsReady ?? false;
public bool MarkedActive { get; private set; } = false;
/// <summary>
/// Represents the total size of the drive
/// </summary>
public long TotalSize { get; private set; } = default;
/// <summary>
/// Media label as read by Windows
/// </summary>
/// <remarks>The try/catch is needed because Windows will throw an exception if the drive is not marked as active</remarks>
public string VolumeLabel
{
get
{
try
{
return driveInfo?.VolumeLabel;
}
catch
{
return null;
}
}
}
public string VolumeLabel { get; private set; } = null;
#endregion
#region Derived Fields
/// <summary>
/// Media label as read by Windows, formatted to avoid odd outputs
@@ -72,12 +67,12 @@ namespace MPF.Core.Data
get
{
string volumeLabel = Template.DiscNotDetected;
if (driveInfo.IsReady)
if (this.MarkedActive)
{
if (string.IsNullOrWhiteSpace(driveInfo.VolumeLabel))
if (string.IsNullOrWhiteSpace(this.VolumeLabel))
volumeLabel = "track";
else
volumeLabel = driveInfo.VolumeLabel;
volumeLabel = this.VolumeLabel;
}
foreach (char c in Path.GetInvalidFileNameChars())
@@ -88,80 +83,94 @@ namespace MPF.Core.Data
}
/// <summary>
/// DriveInfo object representing the drive, if possible
/// Windows drive letter
/// </summary>
private readonly DriveInfo driveInfo;
public char Letter => this.Name == null || this.Name.Length == 0 ? '\0' : this.Name[0];
public Drive(InternalDriveType? driveType, DriveInfo driveInfo)
#endregion
/// <summary>
/// Protected constructor
/// </summary>
protected Drive() { }
/// <summary>
/// Create a new Drive object from a drive type and device path
/// </summary>
/// <param name="driveType">InternalDriveType value representing the drive type</param>
/// <param name="devicePath">Path to the device according to the local machine</param>
public static Drive Create(InternalDriveType? driveType, string devicePath)
{
this.InternalDriveType = driveType;
this.driveInfo = driveInfo;
// Create a new, empty drive object
var drive = new Drive()
{
InternalDriveType = driveType,
};
// If we have an invalid device path, return null
if (string.IsNullOrWhiteSpace(devicePath))
return null;
// Sanitize a Windows-formatted long device path
if (devicePath.StartsWith("\\\\.\\"))
devicePath = devicePath.Substring("\\\\.\\".Length);
// Create and validate the drive info object
var driveInfo = new DriveInfo(devicePath);
if (driveInfo == null || driveInfo == default)
return null;
// Fill in the rest of the data
drive.PopulateFromDriveInfo(driveInfo);
return drive;
}
/// <summary>
/// Populate all fields from a DriveInfo object
/// </summary>
/// <param name="driveInfo">DriveInfo object to populate from</param>
private void PopulateFromDriveInfo(DriveInfo driveInfo)
{
// If we have an invalid DriveInfo, just return
if (driveInfo == null || driveInfo == default)
return;
// Populate the data fields
this.Name = driveInfo.Name;
this.MarkedActive = driveInfo.IsReady;
if (this.MarkedActive)
{
this.DriveFormat = driveInfo.DriveFormat;
this.TotalSize = driveInfo.TotalSize;
this.VolumeLabel = driveInfo.VolumeLabel;
}
else
{
this.DriveFormat = string.Empty;
this.TotalSize = default;
this.VolumeLabel = string.Empty;
}
}
#region Public Functionality
/// <summary>
/// Create a list of active drives matched to their volume labels
/// </summary>
/// <param name="ignoreFixedDrives">Ture to ignore fixed drives from population, false otherwise</param>
/// <param name="ignoreFixedDrives">True to ignore fixed drives from population, false otherwise</param>
/// <returns>Active drives, matched to labels, if possible</returns>
/// <remarks>
/// https://stackoverflow.com/questions/3060796/how-to-distinguish-between-usb-and-floppy-devices?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
/// https://msdn.microsoft.com/en-us/library/aa394173(v=vs.85).aspx
/// </remarks>
public static List<Drive> CreateListOfDrives(bool ignoreFixedDrives)
{
var desiredDriveTypes = new List<DriveType>() { DriveType.CDRom };
if (!ignoreFixedDrives)
{
desiredDriveTypes.Add(DriveType.Fixed);
desiredDriveTypes.Add(DriveType.Removable);
}
// Get all supported drive types
var drives = DriveInfo.GetDrives()
.Where(d => desiredDriveTypes.Contains(d.DriveType))
.Select(d => new Drive(EnumConverter.ToInternalDriveType(d.DriveType), d))
.ToList();
// TODO: Management searcher stuff is not supported on other platforms
// Get the floppy drives and set the flag from removable
try
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\CIMV2",
"SELECT * FROM Win32_LogicalDisk");
var collection = searcher.Get();
foreach (ManagementObject queryObj in collection)
{
uint? mediaType = (uint?)queryObj["MediaType"];
if (mediaType != null && ((mediaType > 0 && mediaType < 11) || (mediaType > 12 && mediaType < 22)))
{
char devId = queryObj["DeviceID"].ToString()[0];
drives.ForEach(d => { if (d.Letter == devId) { d.InternalDriveType = Data.InternalDriveType.Floppy; } });
}
}
}
catch
{
// No-op
}
// Order the drives by drive letter
drives = drives.OrderBy(i => i.Letter).ToList();
var drives = GetDriveList(ignoreFixedDrives);
drives = drives?.OrderBy(i => i.Letter)?.ToList();
return drives;
}
/// <summary>
/// Get the current media type from drive letter
/// </summary>
/// <param name="drive"></param>
/// <returns></returns>
/// <remarks>
/// 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 (MediaType?, string) GetMediaType()
{
// Take care of the non-optical stuff first
@@ -172,22 +181,25 @@ namespace MPF.Core.Data
return (MediaType.HardDisk, null);
else if (this.InternalDriveType == Data.InternalDriveType.Removable)
return (MediaType.FlashDrive, null);
#if NET6_0_OR_GREATER
else
return GetMediaTypeFromSize();
#endif
#if NET_FRAMEWORK
// Get the current drive information
string deviceId = null;
bool loaded = false;
try
{
// Get the device ID first
var searcher = new ManagementObjectSearcher(
"root\\CIMV2",
$"SELECT * FROM Win32_CDROMDrive WHERE Id = '{this.Letter}:\'");
CimSession session = CimSession.Create(null);
var collection = session.QueryInstances("root\\CIMV2", "WQL", $"SELECT * FROM Win32_CDROMDrive WHERE Id = '{this.Letter}:\'");
foreach (ManagementObject queryObj in searcher.Get())
foreach (CimInstance instance in collection)
{
deviceId = (string)queryObj["DeviceID"];
loaded = (bool)queryObj["MediaLoaded"];
CimKeyedCollection<CimProperty> properties = instance.CimInstanceProperties;
deviceId = (string)properties["DeviceID"]?.Value;
loaded = (bool)properties["MediaLoaded"]?.Value;
}
// If we got no valid device, we don't care and just return
@@ -196,6 +208,8 @@ namespace MPF.Core.Data
else if (!loaded)
return (null, "Device is not reporting media loaded");
#if NETFRAMEWORK
MsftDiscMaster2 discMaster = new MsftDiscMaster2();
deviceId = deviceId.ToLower().Replace('\\', '#').Replace('/', '#');
string id = null;
@@ -223,31 +237,17 @@ namespace MPF.Core.Data
var media = dataWriter.CurrentPhysicalMediaType;
return (media.IMAPIToMediaType(), null);
}
catch (Exception ex)
{
return (null, ex.Message);
}
#else
try
{
var device = new AaruDevices.Device(this.Name);
if (device.Error)
return (null, "Could not open device");
else if (device.Type != DeviceType.ATAPI && device.Type != DeviceType.SCSI)
return (null, "Device does not support media type detection");
// TODO: In order to get the disc type, Aaru.Core will need to be included as a
// package. Unfortunately, it currently has a conflict with one of the required libraries:
// System.Text.Encoding.CodePages (BOS uses >= 5.0.0, DotNetZip uses >= 4.5.0 && < 5.0.0)
return (null, "IMAPI2 recorder not supported");
#endif
}
catch (Exception ex)
{
return (null, ex.Message);
}
return (null, "Media detection only supported on .NET Framework");
#endif
}
/// <summary>
@@ -273,19 +273,51 @@ namespace MPF.Core.Data
if (systemFromLabel != null)
return systemFromLabel;
// Get a list of files for quicker checking
#region Consoles
// Bandai Playdia Quick Interactive System
try
{
List<string> files = Directory.EnumerateFiles(drivePath, "*", SearchOption.TopDirectoryOnly).ToList();
if (files.Any(f => f.EndsWith(".AJS", StringComparison.OrdinalIgnoreCase))
&& files.Any(f => f.EndsWith(".GLB", StringComparison.OrdinalIgnoreCase)))
{
return RedumpSystem.BandaiPlaydiaQuickInteractiveSystem;
}
}
catch { }
// Mattel Fisher-Price iXL
if (File.Exists(Path.Combine(drivePath, "iXL", "iXLUpdater.exe")))
{
return RedumpSystem.MattelFisherPriceiXL;
}
// Microsoft Xbox 360
try
{
if (Directory.Exists(Path.Combine(drivePath, "$SystemUpdate"))
&& Directory.EnumerateFiles(Path.Combine(drivePath, "$SystemUpdate")).Any())
&& Directory.EnumerateFiles(Path.Combine(drivePath, "$SystemUpdate")).Any()
&& this.TotalSize <= 500_000_000)
{
return RedumpSystem.MicrosoftXbox360;
}
}
catch { }
// Microsoft Xbox One
try
{
if (Directory.Exists(Path.Combine(drivePath, "MSXC"))
&& Directory.EnumerateFiles(Path.Combine(drivePath, "MSXC")).Any())
{
return RedumpSystem.MicrosoftXboxOne;
}
}
catch { }
// Sega Dreamcast
if (File.Exists(Path.Combine(drivePath, "IP.BIN")))
{
@@ -330,6 +362,35 @@ namespace MPF.Core.Data
return RedumpSystem.SonyPlayStation;
}
// Sony PlayStation 3
try
{
if (Directory.Exists(Path.Combine(drivePath, "PS3_GAME"))
|| Directory.Exists(Path.Combine(drivePath, "PS3_UPDATE"))
|| File.Exists(Path.Combine(drivePath, "PS3_DISC.SFB")))
{
return RedumpSystem.SonyPlayStation3;
}
}
catch { }
// Sony PlayStation 4
// There are more possible paths that could be checked.
// There are some entries that can be found on most PS4 discs:
// "/app/GAME_SERIAL/app.pkg"
// "/bd/param.sfo"
// "/license/rif"
// There are also extra files that can be found on some discs:
// "/patch/GAME_SERIAL/patch.pkg" can be found in Redump entry 66816.
// Originally on disc as "/patch/CUSA11302/patch.pkg".
// Is used as an on-disc update for the base game app without needing to get update from the internet.
// "/addcont/GAME_SERIAL/CONTENT_ID/ac.pkg" can be found in Redump entry 97619.
// Originally on disc as "/addcont/CUSA00288/FFXIVEXPS400001A/ac.pkg".
if (File.Exists(Path.Combine(drivePath, "PS4", "UPDATE", "PS4UPDATE.PUP")))
{
return RedumpSystem.SonyPlayStation4;
}
// V.Tech V.Flash / V.Smile Pro
if (File.Exists(Path.Combine(drivePath, "0SYSTEM")))
{
@@ -338,6 +399,16 @@ namespace MPF.Core.Data
#endregion
#region Computers
// Sharp X68000
if (File.Exists(Path.Combine(drivePath, "COMMAND.X")))
{
return RedumpSystem.SharpX68000;
}
#endregion
#region Video Formats
// BD-Video
@@ -424,6 +495,10 @@ namespace MPF.Core.Data
//if (this.VolumeLabel.Equals("DVD_ROM", StringComparison.OrdinalIgnoreCase))
// return RedumpSystem.MicrosoftXbox360;
// Sega Mega-CD / Sega-CD
if (this.VolumeLabel.Equals("Sega_CD", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.SegaMegaCDSegaCD;
// Sony PlayStation 3
if (this.VolumeLabel.Equals("PS3VOLUME", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.SonyPlayStation3;
@@ -448,7 +523,7 @@ namespace MPF.Core.Data
public byte[] ReadSector(long num, int size = 2048)
{
// Missing drive leter is not supported
if (string.IsNullOrEmpty(this.driveInfo?.Name))
if (string.IsNullOrEmpty(this.Name))
return null;
// We don't support negative sectors
@@ -480,5 +555,96 @@ namespace MPF.Core.Data
fs?.Dispose();
}
}
/// <summary>
/// Refresh the current drive information based on path
/// </summary>
public void RefreshDrive()
{
var driveInfo = DriveInfo.GetDrives().FirstOrDefault(d => d?.Name == this.Name);
this.PopulateFromDriveInfo(driveInfo);
}
#endregion
#region Helpers
/// <summary>
/// Get the media type for a device path based on size
/// </summary>
/// <returns>MediaType, null on error</returns>
private (MediaType?, string) GetMediaTypeFromSize()
{
if (this.TotalSize >= 0 && this.TotalSize < 800_000_000 && this.DriveFormat == "CDFS")
return (MediaType.CDROM, null);
else if (this.TotalSize >= 400_000_000 && this.TotalSize <= 8_540_000_000 && this.DriveFormat == "UDF")
return (MediaType.DVD, null);
else
return (MediaType.BluRay, null);
}
/// <summary>
/// Get all current attached Drives
/// </summary>
/// <param name="ignoreFixedDrives">True to ignore fixed drives from population, false otherwise</param>
/// <returns>List of drives, null on error</returns>
/// <remarks>
/// https://stackoverflow.com/questions/3060796/how-to-distinguish-between-usb-and-floppy-devices?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
/// https://msdn.microsoft.com/en-us/library/aa394173(v=vs.85).aspx
/// </remarks>
private static List<Drive> GetDriveList(bool ignoreFixedDrives)
{
var desiredDriveTypes = new List<DriveType>() { DriveType.CDRom };
if (!ignoreFixedDrives)
{
desiredDriveTypes.Add(DriveType.Fixed);
desiredDriveTypes.Add(DriveType.Removable);
}
// TODO: Reduce reliance on `DriveInfo`
// https://github.com/aaru-dps/Aaru/blob/5164a154e2145941472f2ee0aeb2eff3338ecbb3/Aaru.Devices/Windows/ListDevices.cs#L66
// Create an output drive list
List<Drive> drives = new List<Drive>();
// Get all standard supported drive types
try
{
drives = DriveInfo.GetDrives()
.Where(d => desiredDriveTypes.Contains(d.DriveType))
.Select(d => Create(EnumConverter.ToInternalDriveType(d.DriveType), d.Name))
.ToList();
}
catch
{
return drives;
}
// Find and update all floppy drives
try
{
CimSession session = CimSession.Create(null);
var collection = session.QueryInstances("root\\CIMV2", "WQL", "SELECT * FROM Win32_LogicalDisk");
foreach (CimInstance instance in collection)
{
CimKeyedCollection<CimProperty> properties = instance.CimInstanceProperties;
uint? mediaType = properties["MediaType"]?.Value as uint?;
if (mediaType != null && ((mediaType > 0 && mediaType < 11) || (mediaType > 12 && mediaType < 22)))
{
char devId = (properties["Caption"].Value as string)[0];
drives.ForEach(d => { if (d.Letter == devId) { d.InternalDriveType = Data.InternalDriveType.Floppy; } });
}
}
}
catch
{
// No-op
}
return drives;
}
#endregion
}
}

View File

@@ -22,6 +22,7 @@
Aaru,
DD,
DiscImageCreator,
Redumper,
// Verification support only
CleanRip,

View File

@@ -39,6 +39,15 @@ namespace MPF.Core.Data
set { _settings["DDPath"] = value; }
}
/// <summary>
/// Path to Redumper
/// </summary>
public string RedumperPath
{
get { return GetStringSetting(_settings, "RedumperPath", "Programs\\Redumper\\redumper.exe"); }
set { _settings["RedumperPath"] = value; }
}
/// <summary>
/// Currently selected dumping program
/// </summary>
@@ -78,6 +87,15 @@ namespace MPF.Core.Data
set { _settings["CheckForUpdatesOnStartup"] = value.ToString(); }
}
/// <summary>
/// Fast update label - Skips disc checks and updates path only
/// </summary>
public bool FastUpdateLabel
{
get { return GetBooleanSetting(_settings, "FastUpdateLabel", false); }
set { _settings["FastUpdateLabel"] = value.ToString(); }
}
/// <summary>
/// Default output path for dumps
/// </summary>
@@ -123,7 +141,7 @@ namespace MPF.Core.Data
/// </summary>
public int PreferredDumpSpeedCD
{
get { return GetInt32Setting(_settings, "PreferredDumpSpeedCD", 72); }
get { return GetInt32Setting(_settings, "PreferredDumpSpeedCD", 24); }
set { _settings["PreferredDumpSpeedCD"] = value.ToString(); }
}
@@ -132,16 +150,25 @@ namespace MPF.Core.Data
/// </summary>
public int PreferredDumpSpeedDVD
{
get { return GetInt32Setting(_settings, "PreferredDumpSpeedDVD", 24); }
get { return GetInt32Setting(_settings, "PreferredDumpSpeedDVD", 16); }
set { _settings["PreferredDumpSpeedDVD"] = value.ToString(); }
}
/// <summary>
/// Default HD-DVD dumping speed
/// </summary>
public int PreferredDumpSpeedHDDVD
{
get { return GetInt32Setting(_settings, "PreferredDumpSpeedHDDVD", 8); }
set { _settings["PreferredDumpSpeedHDDVD"] = value.ToString(); }
}
/// <summary>
/// Default BD dumping speed
/// </summary>
public int PreferredDumpSpeedBD
{
get { return GetInt32Setting(_settings, "PreferredDumpSpeedBD", 16); }
get { return GetInt32Setting(_settings, "PreferredDumpSpeedBD", 8); }
set { _settings["PreferredDumpSpeedBD"] = value.ToString(); }
}
@@ -198,6 +225,24 @@ namespace MPF.Core.Data
#region DiscImageCreator
/// <summary>
/// Enable multi-sector read flag by default
/// </summary>
public bool DICMultiSectorRead
{
get { return GetBooleanSetting(_settings, "DICMultiSectorRead", false); }
set { _settings["DICMultiSectorRead"] = value.ToString(); }
}
/// <summary>
/// Include a default multi-sector read value
/// </summary>
public int DICMultiSectorReadValue
{
get { return GetInt32Setting(_settings, "DICMultiSectorReadValue", 0); }
set { _settings["DICMultiSectorReadValue"] = value.ToString(); }
}
/// <summary>
/// Enable overly-secure dumping flags by default
/// </summary>
@@ -230,6 +275,15 @@ namespace MPF.Core.Data
set { _settings["DICRereadCount"] = value.ToString(); }
}
/// <summary>
/// Default number of DVD/HD-DVD/BD rereads
/// </summary>
public int DICDVDRereadCount
{
get { return GetInt32Setting(_settings, "DICDVDRereadCount", 10); }
set { _settings["DICDVDRereadCount"] = value.ToString(); }
}
/// <summary>
/// Reset drive after dumping (useful for older drives)
/// </summary>
@@ -250,6 +304,37 @@ namespace MPF.Core.Data
#endregion
#region Redumper
/// <summary>
/// Enable debug output while dumping by default
/// </summary>
public bool RedumperEnableDebug
{
get { return GetBooleanSetting(_settings, "RedumperEnableDebug", false); }
set { _settings["RedumperEnableDebug"] = value.ToString(); }
}
/// <summary>
/// Enable verbose output while dumping by default
/// </summary>
public bool RedumperEnableVerbose
{
get { return GetBooleanSetting(_settings, "RedumperEnableVerbose", false); }
set { _settings["RedumperEnableVerbose"] = value.ToString(); }
}
/// <summary>
/// Default number of rereads
/// </summary>
public int RedumperRereadCount
{
get { return GetInt32Setting(_settings, "RedumperRereadCount", 20); }
set { _settings["RedumperRereadCount"] = value.ToString(); }
}
#endregion
#region Extra Dumping Options
/// <summary>
@@ -261,6 +346,15 @@ namespace MPF.Core.Data
set { _settings["ScanForProtection"] = value.ToString(); }
}
/// <summary>
/// Output all found protections to a separate file in the directory
/// </summary>
public bool OutputSeparateProtectionFile
{
get { return GetBooleanSetting(_settings, "OutputSeparateProtectionFile", true); }
set { _settings["OutputSeparateProtectionFile"] = value.ToString(); }
}
/// <summary>
/// Add placeholder values in the submission info
/// </summary>
@@ -288,6 +382,15 @@ namespace MPF.Core.Data
set { _settings["EnableTabsInInputFields"] = value.ToString(); }
}
/// <summary>
/// Limit outputs to Redump-supported values only
/// </summary>
public bool EnableRedumpCompatibility
{
get { return GetBooleanSetting(_settings, "EnableRedumpCompatibility", true); }
set { _settings["EnableRedumpCompatibility"] = value.ToString(); }
}
/// <summary>
/// Show disc eject reminder before the disc information window is shown
/// </summary>
@@ -395,15 +498,6 @@ namespace MPF.Core.Data
set { _settings["ScanPackersForProtection"] = value.ToString(); }
}
/// <summary>
/// Force scanning all files for protection
/// </summary>
public bool ForceScanningForProtection
{
get { return GetBooleanSetting(_settings, "ForceScanningForProtection", false); }
set { _settings["ForceScanningForProtection"] = value.ToString(); }
}
/// <summary>
/// Include debug information with scan results
/// </summary>

View File

@@ -0,0 +1,38 @@
namespace MPF.Core.Data
{
/// <summary>
/// Disc Information and Emergency Brake data shall be read from the PIC zone. DI units that
/// contain physical information shall be returned.Emergency Brake data shall be returned.The
/// information shall be collected from the layer specified in the Layer field of the CDB. If any data
/// can be returned, 4 100 bytes shall be returned.
/// </summary>
/// <see href="https://www.t10.org/ftp/t10/document.05/05-206r0.pdf"/>
/// <see href="https://github.com/aaru-dps/Aaru.Decoders/blob/devel/Bluray/DI.cs"/>
public class PICDiscInformation
{
#region Fields
/// <summary>
/// 2048 bytes for BD-ROM, 3584 bytes for BD-R/RE
/// </summary>
/// <remarks>Big-endian format</remarks>
public ushort DataStructureLength { get; set; }
/// <summary>
/// Should be 0x00
/// </summary>
public byte Reserved0 { get; set; }
/// <summary>
/// Should be 0x00
/// </summary>
public byte Reserved1 { get; set; }
/// <summary>
/// Disc information and emergency brake units
/// </summary>
public PICDiscInformationUnit[] Units { get; set; }
#endregion
}
}

View File

@@ -0,0 +1,114 @@
namespace MPF.Core.Data
{
/// <see href="https://www.t10.org/ftp/t10/document.05/05-206r0.pdf"/>
/// <see href="https://github.com/aaru-dps/Aaru.Decoders/blob/devel/Bluray/DI.cs"/>
public class PICDiscInformationUnit
{
#region Fields
#region Header
/// <summary>
/// Disc Information Identifier "DI"
/// Emergency Brake Identifier "EB"
/// </summary>
public string DiscInformationIdentifier { get; set; }
/// <summary>
/// Disc Information Format
/// </summary>
public byte DiscInformationFormat { get; set; }
/// <summary>
/// Number of DI units in each DI block
/// </summary>
public byte NumberOfUnitsInBlock { get; set; }
/// <summary>
/// Should be 0x00
/// </summary>
public byte Reserved0 { get; set; }
/// <summary>
/// DI unit Sequence Number
/// </summary>
public byte SequenceNumber { get; set; }
/// <summary>
/// Number of bytes in use in this DI unit
/// </summary>
public byte BytesInUse { get; set; }
/// <summary>
/// Should be 0x00
/// </summary>
public byte Reserved1 { get; set; }
#endregion
// TODO: Write models for the dependent contents, if possible
#region Body
/// <summary>
/// Disc Type Identifier
/// = "BDO" for BD-ROM
/// = "BDU" for BD-ROM Ultra
/// = "BDW" for BD-RE
/// = "BDR" for BD-R
/// </summary>
public string DiscTypeIdentifier { get; set; }
/// <summary>
/// Disc Size/Class/Version
/// </summary>
public byte DiscSizeClassVersion { get; set; }
/// <summary>
/// DI Unit Format dependent contents
/// </summary>
/// <remarks>52 bytes for BD-ROM, 100 bytes for BD-R/RE</remarks>
public byte[] FormatDependentContents { get; set; }
#endregion
#region Trailer (BD-R/RE only)
/// <summary>
/// Disc Manufacturer ID
/// </summary>
/// <remarks>6 bytes</remarks>
public byte[] DiscManufacturerID { get; set; }
/// <summary>
/// Media Type ID
/// </summary>
/// <remarks>3 bytes</remarks>
public byte[] MediaTypeID { get; set; }
/// <summary>
/// Time Stamp
/// </summary>
public ushort TimeStamp { get; set; }
/// <summary>
/// Product Revision Number
/// </summary>
public byte ProductRevisionNumber { get; set; }
#endregion
#endregion
#region Constants
public const string DiscTypeIdentifierROM = "BDO";
public const string DiscTypeIdentifierROMUltra = "BDU";
public const string DiscTypeIdentifierReWritable = "BDW";
public const string DiscTypeIdentifierRecordable = "BDR";
#endregion
}
}

View File

@@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;netcoreapp3.1;net5.0</TargetFrameworks>
<PlatformTarget>x86</PlatformTarget>
<TargetFrameworks>net48;net6.0</TargetFrameworks>
<RuntimeIdentifiers>win7-x64;win8-x64;win81-x64;win10-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2021</Copyright>
<Copyright>Copyright (c)2019-2023</Copyright>
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
<Version>2.3</Version>
<Version>2.6.2</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<FileVersion>$(Version)</FileVersion>
<IncludeSource>true</IncludeSource>
@@ -20,10 +20,6 @@
<NrtShowRevision>false</NrtShowRevision>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)'=='net48'">
<DefineConstants>NET_FRAMEWORK</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net48'">
<COMReference Include="IMAPI2">
<Guid>{2735412F-7F64-5B0F-8F00-5D77AFBE261E}</Guid>
@@ -50,16 +46,10 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="System.Management" Version="6.0.0-rc.1.21451.13" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'!='net48'">
<PackageReference Include="Aaru.Devices" Version="5.3.0-rc2" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Management" />
<PackageReference Include="Microsoft.Management.Infrastructure" Version="2.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="7.0.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
</ItemGroup>
</Project>

396
MPF.Core/Utilities/Chime.cs Normal file
View File

@@ -0,0 +1,396 @@
using System;
namespace MPF.Core.Utilities
{
/// <summary>
/// Methods to deal with outputting tones to the PC speaker
/// </summary>
public class Chime
{
/// <summary>
/// Standard duration to play a single tone
/// </summary>
private const int standardDurationMs = 200;
#region Octave 0
/// <summary>
/// Frequency representing C(0)
/// </summary>
private const int noteC0 = 16; // 16.35
/// <summary>
/// Frequency representing D(0)
/// </summary>
private const int noteD0 = 18; // 18.35
/// <summary>
/// Frequency representing E(0)
/// </summary>
private const int noteE0 = 21; // 20.60
/// <summary>
/// Frequency representing F(0)
/// </summary>
private const int noteF0 = 22; // 21.83
/// <summary>
/// Frequency representing G(0)
/// </summary>
private const int noteG0 = 25; // 24.50
/// <summary>
/// Frequency representing A(0)
/// </summary>
private const int noteA0 = 28; // 27.50
/// <summary>
/// Frequency representing B(0)
/// </summary>
private const int noteB0 = 31; // 30.87
#endregion
#region Octave 1
/// <summary>
/// Frequency representing C(1)
/// </summary>
private const int noteC1 = 33; // 32.70
/// <summary>
/// Frequency representing D(1)
/// </summary>
private const int noteD1 = 37; // 36.71
/// <summary>
/// Frequency representing E(1)
/// </summary>
private const int noteE1 = 41; // 41.20
/// <summary>
/// Frequency representing F(1)
/// </summary>
private const int noteF1 = 44; // 43.65
/// <summary>
/// Frequency representing G(1)
/// </summary>
private const int noteG1 = 49; // 49.00
/// <summary>
/// Frequency representing A(1)
/// </summary>
private const int noteA1 = 55; // 55.00
/// <summary>
/// Frequency representing B(1)
/// </summary>
private const int noteB1 = 62; // 61.74
#endregion
#region Octave 2
/// <summary>
/// Frequency representing C(2)
/// </summary>
private const int noteC2 = 65; // 65.41
/// <summary>
/// Frequency representing D(2)
/// </summary>
private const int noteD2 = 73; // 73.42
/// <summary>
/// Frequency representing E(2)
/// </summary>
private const int noteE2 = 82; // 82.41
/// <summary>
/// Frequency representing F(2)
/// </summary>
private const int noteF2 = 87; // 87.31
/// <summary>
/// Frequency representing G(2)
/// </summary>
private const int noteG2 = 98; // 98.00
/// <summary>
/// Frequency representing A(2)
/// </summary>
private const int noteA2 = 110; // 110.00
/// <summary>
/// Frequency representing B(2)
/// </summary>
private const int noteB2 = 123; // 123.47
#endregion
#region Octave 3
/// <summary>
/// Frequency representing C(3)
/// </summary>
private const int noteC3 = 131; // 130.81
/// <summary>
/// Frequency representing D(3)
/// </summary>
private const int noteD3 = 147; // 146.83
/// <summary>
/// Frequency representing E(3)
/// </summary>
private const int noteE3 = 165; // 164.81
/// <summary>
/// Frequency representing F(3)
/// </summary>
private const int noteF3 = 175; // 174.61
/// <summary>
/// Frequency representing G(3)
/// </summary>
private const int noteG3 = 196; // 196.00
/// <summary>
/// Frequency representing A(3)
/// </summary>
private const int noteA3 = 220; // 220.00
/// <summary>
/// Frequency representing B(3)
/// </summary>
private const int noteB3 = 247; // 246.94
#endregion
#region Octave 4
/// <summary>
/// Frequency representing C(4)
/// </summary>
private const int noteC4 = 262; // 261.63
/// <summary>
/// Frequency representing D(4)
/// </summary>
private const int noteD4 = 294; // 293.66
/// <summary>
/// Frequency representing E(4)
/// </summary>
private const int noteE4 = 330; // 329.63
/// <summary>
/// Frequency representing F(4)
/// </summary>
private const int noteF4 = 349; // 349.23
/// <summary>
/// Frequency representing G(4)
/// </summary>
private const int noteG4 = 392; // 392.00
/// <summary>
/// Frequency representing A(4)
/// </summary>
private const int noteA4 = 440; // 440.00
/// <summary>
/// Frequency representing B(4)
/// </summary>
private const int noteB4 = 494; // 493.88
#endregion
#region Octave 5
/// <summary>
/// Frequency representing C(5)
/// </summary>
private const int noteC5 = 523; // 523.25
/// <summary>
/// Frequency representing D(5)
/// </summary>
private const int noteD5 = 587; // 587.33
/// <summary>
/// Frequency representing E(5)
/// </summary>
private const int noteE5 = 659; // 659.25
/// <summary>
/// Frequency representing F(5)
/// </summary>
private const int noteF5 = 698; // 698.46
/// <summary>
/// Frequency representing G(5)
/// </summary>
private const int noteG5 = 783; // 783.99
/// <summary>
/// Frequency representing A(5)
/// </summary>
private const int noteA5 = 880; // 880.00
/// <summary>
/// Frequency representing B(5)
/// </summary>
private const int noteB5 = 988; // 987.77
#endregion
#region Octave 6
/// <summary>
/// Frequency representing C(6)
/// </summary>
private const int noteC6 = 1047; // 1046.50
/// <summary>
/// Frequency representing D(6)
/// </summary>
private const int noteD6 = 1175; // 1174.66
/// <summary>
/// Frequency representing E(6)
/// </summary>
private const int noteE6 = 1319; // 1318.51
/// <summary>
/// Frequency representing F(6)
/// </summary>
private const int noteF6 = 1397; // 1396.91
/// <summary>
/// Frequency representing G(6)
/// </summary>
private const int noteG6 = 1568; // 1567.98
/// <summary>
/// Frequency representing A(6)
/// </summary>
private const int noteA6 = 1760; // 1760.00
/// <summary>
/// Frequency representing B(6)
/// </summary>
private const int noteB6 = 1976; // 1975.53
#endregion
#region Octave 7
/// <summary>
/// Frequency representing C(7)
/// </summary>
private const int noteC7 = 2093; // 2093.00
/// <summary>
/// Frequency representing D(7)
/// </summary>
private const int noteD7 = 2349; // 2349.32
/// <summary>
/// Frequency representing E(7)
/// </summary>
private const int noteE7 = 2637; // 2637.02
/// <summary>
/// Frequency representing F(7)
/// </summary>
private const int noteF7 = 2794; // 2793.83
/// <summary>
/// Frequency representing G(7)
/// </summary>
private const int noteG7 = 3136; // 3135.96
/// <summary>
/// Frequency representing A(7)
/// </summary>
private const int noteA7 = 3520; // 3520.00
/// <summary>
/// Frequency representing B(7)
/// </summary>
private const int noteB7 = 3951; // 3951.07
#endregion
#region Octave 8
/// <summary>
/// Frequency representing C(8)
/// </summary>
private const int noteC8 = 4186; // 4186.01
/// <summary>
/// Frequency representing D(8)
/// </summary>
private const int noteD8 = 4699; // 4698.63
/// <summary>
/// Frequency representing E(8)
/// </summary>
private const int noteE8 = 5274; // 5274.04
/// <summary>
/// Frequency representing F(8)
/// </summary>
private const int noteF8 = 5588; // 5587.65
/// <summary>
/// Frequency representing G(8)
/// </summary>
private const int noteG8 = 6272; // 6271.93
/// <summary>
/// Frequency representing A(8)
/// </summary>
private const int noteA8 = 7040; // 7040.00
/// <summary>
/// Frequency representing B(8)
/// </summary>
private const int noteB8 = 7902; // 7902.13
#endregion
/// <summary>
/// Output a series of beeps for completion, similar to DiscImageCreator
/// </summary>
/// <param name="success">True if the upward series should play, false otherwise</param>
public static void StandardCompletion(bool success)
{
if (success)
{
Console.Beep(noteC4, standardDurationMs);
Console.Beep(noteD4, standardDurationMs);
Console.Beep(noteE4, standardDurationMs);
Console.Beep(noteF4, standardDurationMs);
Console.Beep(noteG4, standardDurationMs);
Console.Beep(noteA4, standardDurationMs);
Console.Beep(noteB4, standardDurationMs);
Console.Beep(noteC5, standardDurationMs);
}
else
{
Console.Beep(noteC5, standardDurationMs);
Console.Beep(noteB4, standardDurationMs);
Console.Beep(noteA4, standardDurationMs);
Console.Beep(noteG4, standardDurationMs);
Console.Beep(noteF4, standardDurationMs);
Console.Beep(noteE4, standardDurationMs);
Console.Beep(noteD4, standardDurationMs);
Console.Beep(noteC4, standardDurationMs);
}
}
}
}

View File

@@ -1,4 +1,8 @@
using RedumpLib.Data;
using System;
using System.Collections.Generic;
using MPF.Core.Converters;
using MPF.Core.Data;
using RedumpLib.Data;
namespace MPF.Core.Utilities
{
@@ -68,6 +72,7 @@ namespace MPF.Core.Utilities
case RedumpSystem.SonyPlayStation3:
case RedumpSystem.SonyPlayStation4:
//case RedumpSystem.SonyPlayStation5:
case RedumpSystem.SonyPlayStationPortable:
return true;
default:
return false;
@@ -90,11 +95,13 @@ namespace MPF.Core.Utilities
case RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem:
case RedumpSystem.AudioCD:
case RedumpSystem.DVDAudio:
case RedumpSystem.HasbroiONEducationalGamingSystem:
case RedumpSystem.HasbroVideoNow:
case RedumpSystem.HasbroVideoNowColor:
case RedumpSystem.HasbroVideoNowJr:
case RedumpSystem.HasbroVideoNowXP:
case RedumpSystem.PhilipsCDi:
case RedumpSystem.PlayStationGameSharkUpdates:
case RedumpSystem.SuperAudioCD:
return true;
default:
@@ -102,26 +109,6 @@ namespace MPF.Core.Utilities
}
}
/// <summary>
/// Determine if a system is a marker value
/// </summary>
/// <param name="system">RedumpSystem value to check</param>
/// <returns>True if the system is a marker value, false otherwise</returns>
public static bool IsMarker(this RedumpSystem? system)
{
switch (system)
{
case RedumpSystem.MarkerArcadeEnd:
case RedumpSystem.MarkerComputerEnd:
case RedumpSystem.MarkerDiscBasedConsoleEnd:
// case RedumpSystem.MarkerOtherConsoleEnd:
case RedumpSystem.MarkerOtherEnd:
return true;
default:
return false;
}
}
/// <summary>
/// Determine if a system is considered XGD
/// </summary>
@@ -140,5 +127,23 @@ namespace MPF.Core.Utilities
return false;
}
}
/// <summary>
/// List all programs with their short usable names
/// </summary>
public static List<string> ListPrograms()
{
var programs = new List<string>();
foreach (var val in Enum.GetValues(typeof(InternalProgram)))
{
if (((InternalProgram)val) == InternalProgram.NONE)
continue;
programs.Add($"{((InternalProgram?)val).LongName()}");
}
return programs;
}
}
}

View File

@@ -0,0 +1,182 @@
using System.Collections.Generic;
using System.Configuration;
using MPF.Core.Converters;
using MPF.Core.Data;
namespace MPF.Core.Utilities
{
public static class OptionsLoader
{
#region Arguments
/// <summary>
/// Load the current set of options from application arguments
/// </summary>
public static (Options, string, int) LoadFromArguments(string[] args, int startIndex = 0)
{
// Create the output values with defaults
var options = new Options()
{
RedumpUsername = null,
RedumpPassword = null,
InternalProgram = InternalProgram.NONE,
OutputSubmissionJSON = false,
CompressLogFiles = false,
};
string parsedPath = null;
// These values require multiple parts to be active
bool scan = false, protectFile = false;
// If we have no arguments, just return
if (args == null || args.Length == 0)
return (options, null, 0);
// If we have an invalid start index, just return
if (startIndex < 0 || startIndex >= args.Length)
return (options, null, startIndex);
// Loop through the arguments and parse out values
for (; startIndex < args.Length; startIndex++)
{
// Redump login
if (args[startIndex].StartsWith("-c=") || args[startIndex].StartsWith("--credentials="))
{
string[] credentials = args[startIndex].Split('=')[1].Split(';');
options.RedumpUsername = credentials[0];
options.RedumpPassword = credentials[1];
}
else if (args[startIndex] == "-c" || args[startIndex] == "--credentials")
{
options.RedumpUsername = args[startIndex + 1];
options.RedumpPassword = args[startIndex + 2];
startIndex += 2;
}
// Use specific program
else if (args[startIndex].StartsWith("-u=") || args[startIndex].StartsWith("--use="))
{
string internalProgram = args[startIndex].Split('=')[1];
options.InternalProgram = EnumConverter.ToInternalProgram(internalProgram);
}
else if (args[startIndex] == "-u" || args[startIndex] == "--use")
{
string internalProgram = args[startIndex + 1];
options.InternalProgram = EnumConverter.ToInternalProgram(internalProgram);
startIndex++;
}
// Use a device path for physical checks
else if (args[startIndex].StartsWith("-p=") || args[startIndex].StartsWith("--path="))
{
parsedPath = args[startIndex].Split('=')[1];
}
else if (args[startIndex] == "-p" || args[startIndex] == "--path")
{
parsedPath = args[startIndex + 1];
startIndex++;
}
// Scan for protection (requires device path)
else if (args[startIndex].Equals("-s") || args[startIndex].Equals("--scan"))
{
scan = true;
}
// Output protection to separate file (requires scan for protection)
else if (args[startIndex].Equals("-f") || args[startIndex].Equals("--protect-file"))
{
protectFile = true;
}
// Output submission JSON
else if (args[startIndex].Equals("-j") || args[startIndex].Equals("--json"))
{
options.OutputSubmissionJSON = true;
}
// Compress log and extraneous files
else if (args[startIndex].Equals("-z") || args[startIndex].Equals("--zip"))
{
options.CompressLogFiles = true;
}
// Default, we fall out
else
{
break;
}
}
// We default to DiscImageCreator currently
if (options.InternalProgram == InternalProgram.NONE)
options.InternalProgram = InternalProgram.DiscImageCreator;
// Now deal with the complex options
options.ScanForProtection = scan && !string.IsNullOrWhiteSpace(parsedPath);
options.OutputSeparateProtectionFile = scan && protectFile && !string.IsNullOrWhiteSpace(parsedPath);
return (options, parsedPath, startIndex);
}
/// <summary>
/// Return a list of supported arguments and descriptions
/// </summary>
public static List<string> PrintSupportedArguments()
{
var supportedArguments = new List<string>();
supportedArguments.Add("-c, --credentials <user> <pw> Redump username and password");
supportedArguments.Add("-u, --use <program> Dumping program output type");
supportedArguments.Add("-p, --path <drivepath> Physical drive path for additional checks");
supportedArguments.Add("-s, --scan Enable copy protection scan (requires --path)");
supportedArguments.Add("-f, --protect-file Output protection to separate file (requires --scan)");
supportedArguments.Add("-j, --json Enable submission JSON output");
supportedArguments.Add("-z, --zip Enable log file compression");
return supportedArguments;
}
#endregion
#region Configuration
/// <summary>
/// Load the current set of options from the application configuration
/// </summary>
public static Options LoadFromConfig()
{
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var settings = configFile.AppSettings.Settings;
var dict = new Dictionary<string, string>();
foreach (string key in settings.AllKeys)
{
dict[key] = settings[key]?.Value ?? string.Empty;
}
return new Options(dict);
}
/// <summary>
/// Save the current set of options to the application configuration
/// </summary>
public static void SaveToConfig(Options options)
{
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
// Loop through all settings in Options and save them, overwriting existing settings
foreach (var kvp in options)
{
configFile.AppSettings.Settings.Remove(kvp.Key);
configFile.AppSettings.Settings.Add(kvp.Key, kvp.Value);
}
configFile.Save(ConfigurationSaveMode.Modified);
}
#endregion
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Net;
using System.Reflection;
using MPF.Core.Data;
using Newtonsoft.Json.Linq;
@@ -162,8 +161,15 @@ namespace MPF.Core.Utilities
/// </summary>
public static string GetCurrentVersion()
{
var assemblyVersion = Attribute.GetCustomAttribute(Assembly.GetEntryAssembly(), typeof(AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute;
return assemblyVersion.InformationalVersion;
try
{
var assemblyVersion = Attribute.GetCustomAttribute(Assembly.GetEntryAssembly(), typeof(AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute;
return assemblyVersion.InformationalVersion;
}
catch (Exception ex)
{
return ex.ToString();
}
}
/// <summary>
@@ -171,7 +177,8 @@ namespace MPF.Core.Utilities
/// </summary>
private static (string tag, string url) GetRemoteVersionAndUrl()
{
using (WebClient wc = new WebClient())
#if NETFRAMEWORK
using (System.Net.WebClient wc = new System.Net.WebClient())
{
wc.Headers["User-Agent"] = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0";
@@ -184,6 +191,21 @@ namespace MPF.Core.Utilities
return (latestTag, releaseUrl);
}
#else
using (System.Net.Http.HttpClient hc = new System.Net.Http.HttpClient())
{
// TODO: Figure out a better way than having this hardcoded...
string url = "https://api.github.com/repos/SabreTools/MPF/releases/latest";
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, url);
message.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0");
string latestReleaseJsonString = hc.Send(message)?.Content?.ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult();
var latestReleaseJson = JObject.Parse(latestReleaseJsonString);
string latestTag = latestReleaseJson["tag_name"].ToString();
string releaseUrl = latestReleaseJson["html_url"].ToString();
return (latestTag, releaseUrl);
}
#endif
}
#endregion

View File

@@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;netcoreapp3.1;net5.0</TargetFrameworks>
<PlatformTarget>x86</PlatformTarget>
<TargetFrameworks>net48;net6.0</TargetFrameworks>
<RuntimeIdentifiers>win7-x64;win8-x64;win81-x64;win10-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2021</Copyright>
<Copyright>Copyright (c)2019-2023</Copyright>
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
<Version>2.3</Version>
<Version>2.6.2</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<FileVersion>$(Version)</FileVersion>
<IncludeSource>true</IncludeSource>
@@ -21,7 +21,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.1">
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -19,14 +19,9 @@ namespace MPF.Library
#region Output paths
/// <summary>
/// Base output directory to write files to
/// Base output file path to write files to
/// </summary>
public string OutputDirectory { get; private set; }
/// <summary>
/// Base output filename for output
/// </summary>
public string OutputFilename { get; private set; }
public string OutputPath { get; private set; }
#endregion
@@ -47,10 +42,15 @@ namespace MPF.Library
/// </summary>
public MediaType? Type { get; private set; }
/// <summary>
/// Currently selected dumping program
/// </summary>
public InternalProgram InternalProgram { get; private set; }
/// <summary>
/// Options object representing user-defined options
/// </summary>
public Options Options { get; private set; }
public Core.Data.Options Options { get; private set; }
/// <summary>
/// Parameters object representing what to send to the internal program
@@ -87,30 +87,31 @@ namespace MPF.Library
/// Constructor for a full DumpEnvironment object from user information
/// </summary>
/// <param name="options"></param>
/// <param name="outputDirectory"></param>
/// <param name="outputFilename"></param>
/// <param name="outputPath"></param>
/// <param name="drive"></param>
/// <param name="system"></param>
/// <param name="type"></param>
/// <param name="internalProgram"></param>
/// <param name="parameters"></param>
public DumpEnvironment(Options options,
string outputDirectory,
string outputFilename,
public DumpEnvironment(Core.Data.Options options,
string outputPath,
Drive drive,
RedumpSystem? system,
MediaType? type,
InternalProgram? internalProgram,
string parameters)
{
// Set options object
this.Options = options;
// Output paths
(this.OutputDirectory, this.OutputFilename) = InfoTool.NormalizeOutputPaths(outputDirectory, outputFilename);
this.OutputPath = InfoTool.NormalizeOutputPaths(outputPath);
// UI information
this.Drive = drive;
this.System = system ?? options.DefaultSystem;
this.Type = type ?? MediaType.NONE;
this.InternalProgram = internalProgram ?? options.InternalProgram;
// Dumping program
SetParameters(parameters);
@@ -127,17 +128,32 @@ namespace MPF.Library
if (this.Parameters.InternalProgram != InternalProgram.DiscImageCreator)
return;
// Replace all instances in the output directory
this.OutputDirectory = this.OutputDirectory.Replace('.', '_');
try
{
// Normalize the output path
string outputPath = InfoTool.NormalizeOutputPaths(this.OutputPath);
// Currently, only periods in directories matter
// Leave the following code commented in case filename handling breaks again
// Replace all instances in the output directory
string outputDirectory = Path.GetDirectoryName(outputPath);
outputDirectory = outputDirectory.Replace(".", "_");
// Replace all instances in the output filename, except the extension
//string tempFilename = Path.GetFileNameWithoutExtension(this.OutputFilename)
// .Replace('.', '_');
//string tempExtension = Path.GetExtension(this.OutputFilename)?.TrimStart('.');
//this.OutputFilename = $"{tempFilename}.{tempExtension}";
// Replace all instances in the output filename
string outputFilename = Path.GetFileNameWithoutExtension(outputPath);
outputFilename = outputFilename.Replace(".", "_");
// Get the extension for recreating the path
string outputExtension = Path.GetExtension(outputPath).TrimStart('.');
// Rebuild the output path
if (!string.IsNullOrWhiteSpace(outputExtension))
this.OutputPath = Path.Combine(outputDirectory, $"{outputFilename}.{outputExtension}");
else
this.OutputPath = Path.Combine(outputDirectory, outputFilename);
// Assign the path to the filename as well for dumping
((Modules.DiscImageCreator.Parameters)this.Parameters).Filename = this.OutputPath;
}
catch { }
}
/// <summary>
@@ -146,7 +162,7 @@ namespace MPF.Library
/// <param name="parameters">String representation of the parameters</param>
public void SetParameters(string parameters)
{
switch (Options.InternalProgram)
switch (this.InternalProgram)
{
// Dumping support
case InternalProgram.Aaru:
@@ -161,6 +177,10 @@ namespace MPF.Library
this.Parameters = new Modules.DiscImageCreator.Parameters(parameters) { ExecutablePath = Options.DiscImageCreatorPath };
break;
case InternalProgram.Redumper:
this.Parameters = new Modules.Redumper.Parameters(parameters) { ExecutablePath = Options.RedumperPath };
break;
// Verification support only
case InternalProgram.CleanRip:
this.Parameters = new Modules.CleanRip.Parameters(parameters) { ExecutablePath = null };
@@ -200,24 +220,27 @@ namespace MPF.Library
return null;
// Set the proper parameters
string filename = OutputDirectory + Path.DirectorySeparatorChar + OutputFilename;
switch (Options.InternalProgram)
switch (this.InternalProgram)
{
case InternalProgram.Aaru:
Parameters = new Modules.Aaru.Parameters(System, Type, Drive.Letter, filename, driveSpeed, Options);
Parameters = new Modules.Aaru.Parameters(System, Type, Drive.Letter, this.OutputPath, driveSpeed, Options);
break;
case InternalProgram.DD:
Parameters = new Modules.DD.Parameters(System, Type, Drive.Letter, filename, driveSpeed, Options);
Parameters = new Modules.DD.Parameters(System, Type, Drive.Letter, this.OutputPath, driveSpeed, Options);
break;
case InternalProgram.DiscImageCreator:
Parameters = new Modules.DiscImageCreator.Parameters(System, Type, Drive.Letter, filename, driveSpeed, Options);
Parameters = new Modules.DiscImageCreator.Parameters(System, Type, Drive.Letter, this.OutputPath, driveSpeed, Options);
break;
case InternalProgram.Redumper:
Parameters = new Modules.Redumper.Parameters(System, Type, Drive.Letter, this.OutputPath, driveSpeed, Options);
break;
// This should never happen, but it needs a fallback
default:
Parameters = new Modules.DiscImageCreator.Parameters(System, Type, Drive.Letter, filename, driveSpeed, Options);
Parameters = new Modules.DiscImageCreator.Parameters(System, Type, Drive.Letter, this.OutputPath, driveSpeed, Options);
break;
}
@@ -268,10 +291,10 @@ namespace MPF.Library
}
// Execute internal tool
progress?.Report(Result.Success($"Executing {Options.InternalProgram}... {(Options.ToolsInSeparateWindow ? "please wait!" : "see log for output!")}"));
Directory.CreateDirectory(OutputDirectory);
progress?.Report(Result.Success($"Executing {this.InternalProgram}... {(Options.ToolsInSeparateWindow ? "please wait!" : "see log for output!")}"));
Directory.CreateDirectory(Path.GetDirectoryName(this.OutputPath));
await Task.Run(() => Parameters.ExecuteInternalProgram(Options.ToolsInSeparateWindow));
progress?.Report(Result.Success($"{Options.InternalProgram} has finished!"));
progress?.Report(Result.Success($"{this.InternalProgram} has finished!"));
// Execute additional tools
progress?.Report(Result.Success("Running any additional tools... see log for output!"));
@@ -302,8 +325,12 @@ namespace MPF.Library
{
resultProgress?.Report(Result.Success("Gathering submission information... please wait!"));
// Get the output directory and filename separately
string outputDirectory = Path.GetDirectoryName(this.OutputPath);
string outputFilename = Path.GetFileName(this.OutputPath);
// Check to make sure that the output had all the correct files
(bool foundFiles, List<string> missingFiles) = InfoTool.FoundAllFiles(this.OutputDirectory, this.OutputFilename, this.Parameters, false);
(bool foundFiles, List<string> missingFiles) = InfoTool.FoundAllFiles(outputDirectory, outputFilename, this.Parameters, false);
if (!foundFiles)
{
resultProgress?.Report(Result.Failure($"There were files missing from the output:\n{string.Join("\n", missingFiles)}"));
@@ -313,8 +340,7 @@ namespace MPF.Library
// Extract the information from the output files
resultProgress?.Report(Result.Success("Extracting output information from output files..."));
SubmissionInfo submissionInfo = await InfoTool.ExtractOutputInformation(
this.OutputDirectory,
this.OutputFilename,
this.OutputPath,
this.Drive,
this.System,
this.Type,
@@ -332,7 +358,7 @@ namespace MPF.Library
}
// Reset the drive automatically if configured to
if (Options.InternalProgram == InternalProgram.DiscImageCreator && Options.DICResetDriveAfterDump)
if (this.InternalProgram == InternalProgram.DiscImageCreator && Options.DICResetDriveAfterDump)
{
resultProgress?.Report(Result.Success($"Resetting drive {Drive.Letter}"));
await ResetDrive();
@@ -359,37 +385,51 @@ namespace MPF.Library
// Format the information for the text output
resultProgress?.Report(Result.Success("Formatting information..."));
List<string> formattedValues = InfoTool.FormatOutputData(submissionInfo);
resultProgress?.Report(Result.Success("Formatting complete!"));
(List<string> formattedValues, string formatResult) = InfoTool.FormatOutputData(submissionInfo, this.Options);
if (formattedValues == null)
resultProgress?.Report(Result.Success(formatResult));
else
resultProgress?.Report(Result.Failure(formatResult));
// Write the text output
resultProgress?.Report(Result.Success("Writing information to !submissionInfo.txt..."));
bool success = InfoTool.WriteOutputData(this.OutputDirectory, formattedValues);
if (success)
resultProgress?.Report(Result.Success("Writing complete!"));
(bool txtSuccess, string txtResult) = InfoTool.WriteOutputData(outputDirectory, formattedValues);
if (txtSuccess)
resultProgress?.Report(Result.Success(txtResult));
else
resultProgress?.Report(Result.Failure("Writing could not complete!"));
resultProgress?.Report(Result.Failure(txtResult));
// Write the JSON output, if required
if (Options.OutputSubmissionJSON)
// Write the copy protection output
if (Options.ScanForProtection && Options.OutputSeparateProtectionFile)
{
resultProgress?.Report(Result.Success("Writing information to !submissionInfo.json.gz..."));
success = InfoTool.WriteOutputData(this.OutputDirectory, submissionInfo);
if (success)
resultProgress?.Report(Result.Success("Writing protection to !protectionInfo.txt..."));
bool scanSuccess = InfoTool.WriteProtectionData(outputDirectory, submissionInfo);
if (scanSuccess)
resultProgress?.Report(Result.Success("Writing complete!"));
else
resultProgress?.Report(Result.Failure("Writing could not complete!"));
}
// Conpress the logs, if required
// Write the JSON output, if required
if (Options.OutputSubmissionJSON)
{
resultProgress?.Report(Result.Success($"Writing information to !submissionInfo.json{(Options.IncludeArtifacts ? ".gz" : string.Empty)}..."));
bool jsonSuccess = InfoTool.WriteOutputData(outputDirectory, submissionInfo, Options.IncludeArtifacts);
if (jsonSuccess)
resultProgress?.Report(Result.Success("Writing complete!"));
else
resultProgress?.Report(Result.Failure("Writing could not complete!"));
}
// Compress the logs, if required
if (Options.CompressLogFiles)
{
resultProgress?.Report(Result.Success("Compressing log files..."));
success = InfoTool.CompressLogFiles(this.OutputDirectory, this.OutputFilename, this.Parameters);
if (success)
resultProgress?.Report(Result.Success("Compression complete!"));
(bool compressSuccess, string compressResult) = InfoTool.CompressLogFiles(outputDirectory, outputFilename, this.Parameters);
if (compressSuccess)
resultProgress?.Report(Result.Success(compressResult));
else
resultProgress?.Report(Result.Failure("Compression could not complete!"));
resultProgress?.Report(Result.Failure(compressResult));
}
resultProgress?.Report(Result.Success("Submission information process complete!"));
@@ -466,12 +506,11 @@ namespace MPF.Library
return Result.Failure("Error! Current configuration is not supported!");
// Fix the output paths, just in case
(OutputDirectory, OutputFilename) = InfoTool.NormalizeOutputPaths(OutputDirectory, OutputFilename);
this.OutputPath = InfoTool.NormalizeOutputPaths(this.OutputPath);
// Validate that the output path isn't on the dumping drive
string fullOutputPath = Path.GetFullPath(Path.Combine(OutputDirectory, OutputFilename));
if (fullOutputPath[0] == Drive.Letter)
return Result.Failure($"Error! Cannot output to same drive that is being dumped!");
if (this.OutputPath[0] == Drive.Letter)
return Result.Failure("Error! Cannot output to same drive that is being dumped!");
// Validate that the required program exists
if (!File.Exists(Parameters.ExecutablePath))
@@ -480,7 +519,7 @@ namespace MPF.Library
// Validate that the dumping drive doesn't contain the executable
string fullExecutablePath = Path.GetFullPath(Parameters.ExecutablePath);
if (fullExecutablePath[0] == Drive.Letter)
return Result.Failure("$Error! Cannot dump same drive that executable resides on!");
return Result.Failure("Error! Cannot dump same drive that executable resides on!");
// Validate that the current configuration is supported
return Tools.GetSupportStatus(System, Type);

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;netcoreapp3.1;net5.0</TargetFrameworks>
<PlatformTarget>x86</PlatformTarget>
<TargetFrameworks>net48;net6.0</TargetFrameworks>
<RuntimeIdentifiers>win7-x64;win8-x64;win81-x64;win10-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<AssemblyName>MPF.Library</AssemblyName>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2021</Copyright>
<Copyright>Copyright (c)2019-2023</Copyright>
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
<Version>2.3</Version>
<Version>2.6.2</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<FileVersion>$(Version)</FileVersion>
<IncludeSource>true</IncludeSource>
@@ -21,10 +21,6 @@
<NrtShowRevision>false</NrtShowRevision>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)'=='net48'">
<DefineConstants>NET_FRAMEWORK</DefineConstants>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
<ProjectReference Include="..\MPF.Modules\MPF.Modules.csproj" />
@@ -32,12 +28,14 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="1.8.0" GeneratePathProperty="true">
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="2.8.0" GeneratePathProperty="true">
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.1">
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -4,58 +4,84 @@ using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BinaryObjectScanner.Protection;
using BurnOutSharp;
using BurnOutSharp.External.psxt001z;
using BurnOutSharp.ProtectionType;
using MPF.Core.Data;
using psxt001z;
namespace MPF.Library
{
public static class Protection
{
/// <summary>
/// Run protection scan on a given dump environment
/// Run protection scan on a given path
/// </summary>
/// <param name="path">Path to scan for protection</param>
/// <param name="options">Options object that determines what to scan</param>
/// <param name="progress">Optional progress callback</param>
/// <returns>TCopy protection detected in the envirionment, if any</returns>
public static async Task<(bool, string)> RunProtectionScanOnPath(string path, Options options, IProgress<ProtectionProgress> progress = null)
/// <returns>Set of all detected copy protections with an optional error string</returns>
public static async Task<(Dictionary<string, List<string>>, string)> RunProtectionScanOnPath(string path, Core.Data.Options options, IProgress<ProtectionProgress> progress = null)
{
try
{
var found = await Task.Run(() =>
{
var scanner = new Scanner(progress)
{
IncludeDebug = options.IncludeDebugProtectionInformation,
ScanAllFiles = options.ForceScanningForProtection,
ScanArchives = options.ScanArchivesForProtection,
ScanPackers = options.ScanPackersForProtection,
};
var scanner = new Scanner(
options.ScanArchivesForProtection,
scanContents: true, // Hardcoded value to avoid issues
scanGameEngines: false, // Hardcoded value to avoid issues
options.ScanPackersForProtection,
scanPaths: true, // Hardcoded value to avoid issues
options.IncludeDebugProtectionInformation,
progress);
return scanner.GetProtections(path);
});
if (found == null || found.Count() == 0)
return (true, "None found");
// If nothing was returned, return
if (found == null || !found.Any())
return (null, null);
// Get an ordered list of distinct found protections
var orderedDistinctProtections = found
// Filter out any empty protections
var filteredProtections = found
.Where(kvp => kvp.Value != null && kvp.Value.Any())
.SelectMany(kvp => kvp.Value)
.Distinct()
.OrderBy(p => p);
.ToDictionary(
kvp => kvp.Key,
kvp => kvp.Value.OrderBy(s => s).ToList());
// Sanitize and join protections for writing
string protections = SanitizeFoundProtections(orderedDistinctProtections);
return (true, protections);
// Return the filtered set of protections
return (filteredProtections, null);
}
catch (Exception ex)
{
return (false, ex.ToString());
return (null, ex.ToString());
}
}
/// <summary>
/// Format found protections to a deduplicated, ordered string
/// </summary>
/// <param name="protections">Dictionary of file to list of protection mappings</param>
/// <returns>Detected protections, if any</returns>
public static string FormatProtections(Dictionary<string, List<string>> protections)
{
// If the filtered list is empty in some way, return
if (protections == null || !protections.Any())
return "None found";
// Get an ordered list of distinct found protections
var orderedDistinctProtections = protections
.SelectMany(kvp => kvp.Value)
.Distinct()
.OrderBy(p => p);
// Sanitize and join protections for writing
string protectionString = SanitizeFoundProtections(orderedDistinctProtections);
if (string.IsNullOrWhiteSpace(protectionString))
return "None found";
return protectionString;
}
/// <summary>
/// Get the existence of an anti-modchip string from a PlayStation disc, if possible
/// </summary>
@@ -73,7 +99,7 @@ namespace MPF.Library
try
{
byte[] fileContent = File.ReadAllBytes(file);
string protection = antiModchip.CheckContents(file, fileContent, false, null, null);
string protection = antiModchip.CheckContents(file, fileContent, false);
if (!string.IsNullOrWhiteSpace(protection))
return true;
}
@@ -177,7 +203,18 @@ namespace MPF.Library
// SafeCast
// TODO: Figure this one out
// Cactus Data Shield / SafeDisc
if (foundProtections.Any(p => p == "Cactus Data Shield 300 (Confirm presence of other CDS-300 files)"))
{
foundProtections = foundProtections
.Where(p => p != "Cactus Data Shield 300 (Confirm presence of other CDS-300 files)");
if (foundProtections.Any(p => !p.StartsWith("SafeDisc")))
foundProtections = foundProtections.Append("Cactus Data Shield 300");
}
// SafeDisc
// TODO: Update based on new internal naming schemes
if (foundProtections.Any(p => p.StartsWith("SafeDisc")))
{
if (foundProtections.Any(p => Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}")))

View File

@@ -7,6 +7,7 @@ using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using MPF.Core.Converters;
using MPF.Core.Data;
using MPF.CueSheets;
using RedumpLib.Data;
@@ -191,22 +192,52 @@ namespace MPF.Modules.Aaru
}
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive, bool includeArtifacts)
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive drive, bool includeArtifacts)
{
// TODO: Fill in submission info specifics for Aaru
string outputDirectory = Path.GetDirectoryName(basePath);
// TODO: Determine if there's an Aaru version anywhere
info.DumpingInfo.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
// Deserialize the sidecar, if possible
var sidecar = GenerateSidecar(basePath + ".cicm.xml");
// Fill in the hardware data
if (GetHardwareInfo(sidecar, out string manufacturer, out string model, out string firmware))
{
info.DumpingInfo.Manufacturer = manufacturer;
info.DumpingInfo.Model = model;
info.DumpingInfo.Firmware = firmware;
}
// Fill in the disc type data
if (GetDiscType(sidecar, out string discType, out string discSubType))
{
string fullDiscType = string.Empty;
if (!string.IsNullOrWhiteSpace(discType) && !string.IsNullOrWhiteSpace(discSubType))
fullDiscType = $"{discType} ({discSubType})";
else if (!string.IsNullOrWhiteSpace(discType) && string.IsNullOrWhiteSpace(discSubType))
fullDiscType = discType;
else if (string.IsNullOrWhiteSpace(discType) && !string.IsNullOrWhiteSpace(discSubType))
fullDiscType = discSubType;
info.DumpingInfo.ReportedDiscType = fullDiscType;
}
// Get the Datafile information
Datafile datafile = GenerateDatafile(sidecar, basePath);
// Fill in the hash data
info.TracksAndWriteOffsets.ClrMameProData = GenerateDatfile(sidecar, basePath);
info.TracksAndWriteOffsets.ClrMameProData = GenerateDatfile(datafile);
switch (this.Type)
{
// TODO: Can this do GD-ROM?
case MediaType.CDROM:
// TODO: Can this do GD-ROM?
info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD";
// TODO: Re-enable once PVD generation / finding is fixed
// Generate / obtain the PVD
//info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD";
long errorCount = -1;
if (File.Exists(basePath + ".resume.xml"))
@@ -214,9 +245,9 @@ namespace MPF.Modules.Aaru
info.CommonDiscInfo.ErrorsCount = (errorCount == -1 ? "Error retrieving error count" : errorCount.ToString());
info.TracksAndWriteOffsets.Cuesheet = GenerateCuesheet(sidecar, basePath) ?? "";
info.TracksAndWriteOffsets.Cuesheet = GenerateCuesheet(sidecar, basePath) ?? string.Empty;
string cdWriteOffset = GetWriteOffset(sidecar) ?? "";
string cdWriteOffset = GetWriteOffset(sidecar) ?? string.Empty;
info.CommonDiscInfo.RingWriteOffset = cdWriteOffset;
info.TracksAndWriteOffsets.OtherWriteOffsets = cdWriteOffset;
break;
@@ -225,7 +256,7 @@ namespace MPF.Modules.Aaru
case MediaType.HDDVD:
case MediaType.BluRay:
// Get the individual hash data, as per internal
if (GetISOHashValues(info.TracksAndWriteOffsets.ClrMameProData, out long size, out string crc32, out string md5, out string sha1))
if (GetISOHashValues(datafile, out long size, out string crc32, out string md5, out string sha1))
{
info.SizeAndChecksums.Size = size;
info.SizeAndChecksums.CRC32 = crc32;
@@ -233,22 +264,25 @@ namespace MPF.Modules.Aaru
info.SizeAndChecksums.SHA1 = sha1;
}
// TODO: Re-enable once PVD generation / finding is fixed
// Generate / obtain the PVD
//info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD";
// Deal with the layerbreak
string layerbreak = null;
if (this.Type == MediaType.DVD)
layerbreak = GetLayerbreak(sidecar) ?? "";
layerbreak = GetLayerbreak(sidecar) ?? string.Empty;
else if (this.Type == MediaType.BluRay)
layerbreak = info.SizeAndChecksums.Size > 25_025_314_816 ? "25025314816" : null;
// If we have a single-layer disc
if (string.IsNullOrWhiteSpace(layerbreak))
{
info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD";
// Currently no-op
}
// If we have a dual-layer disc
else
{
info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD";
info.SizeAndChecksums.Layerbreak = Int64.Parse(layerbreak);
}
@@ -269,7 +303,7 @@ namespace MPF.Modules.Aaru
case RedumpSystem.DVDAudio:
case RedumpSystem.DVDVideo:
info.CopyProtection.Protection = GetDVDProtection(sidecar) ?? "";
info.CopyProtection.Protection = GetDVDProtection(sidecar) ?? string.Empty;
break;
case RedumpSystem.KonamiPython2:
@@ -281,7 +315,7 @@ namespace MPF.Modules.Aaru
info.CommonDiscInfo.EXEDateBuildDate = pythonTwoDate;
}
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? "";
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? string.Empty;
break;
case RedumpSystem.MicrosoftXbox:
@@ -291,13 +325,13 @@ namespace MPF.Modules.Aaru
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash] = xgd1PFIHash;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash] = xgd1SSHash;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSVersion] = xgd1SSVer;
info.Extras.SecuritySectorRanges = ss ?? "";
info.Extras.SecuritySectorRanges = ss ?? string.Empty;
}
if (GetXboxDMIInfo(sidecar, out string serial, out string version, out Region? region))
{
info.CommonDiscInfo.Serial = serial ?? "";
info.VersionAndEditions.Version = version ?? "";
info.CommonDiscInfo.Serial = serial ?? string.Empty;
info.VersionAndEditions.Version = version ?? string.Empty;
info.CommonDiscInfo.Region = region;
}
@@ -310,13 +344,13 @@ namespace MPF.Modules.Aaru
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash] = xgd23PFIHash;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash] = xgd23SSHash;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSVersion] = xgd23SSVer;
info.Extras.SecuritySectorRanges = ss360 ?? "";
info.Extras.SecuritySectorRanges = ss360 ?? string.Empty;
}
if (GetXbox360DMIInfo(sidecar, out string serial360, out string version360, out Region? region360))
{
info.CommonDiscInfo.Serial = serial360 ?? "";
info.VersionAndEditions.Version = version360 ?? "";
info.CommonDiscInfo.Serial = serial360 ?? string.Empty;
info.VersionAndEditions.Version = version360 ?? string.Empty;
info.CommonDiscInfo.Region = region360;
}
break;
@@ -341,15 +375,22 @@ namespace MPF.Modules.Aaru
info.CommonDiscInfo.EXEDateBuildDate = playstationTwoDate;
}
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? "";
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? string.Empty;
break;
case RedumpSystem.SonyPlayStation3:
info.VersionAndEditions.Version = GetPlayStation3Version(drive?.Letter) ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = GetPlayStation3Serial(drive?.Letter) ?? string.Empty;
break;
case RedumpSystem.SonyPlayStation4:
info.VersionAndEditions.Version = GetPlayStation4Version(drive?.Letter) ?? "";
info.VersionAndEditions.Version = GetPlayStation4Version(drive?.Letter) ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = GetPlayStation4Serial(drive?.Letter) ?? string.Empty;
break;
case RedumpSystem.SonyPlayStation5:
info.VersionAndEditions.Version = GetPlayStation5Version(drive?.Letter) ?? "";
info.VersionAndEditions.Version = GetPlayStation5Version(drive?.Letter) ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = GetPlayStation5Serial(drive?.Letter) ?? string.Empty;
break;
}
@@ -1396,6 +1437,8 @@ namespace MPF.Modules.Aaru
case MediaType.CDROM:
if (File.Exists($"{basePath}.cicm.xml"))
logFiles.Add($"{basePath}.cicm.xml");
if (File.Exists($"{basePath}.error.log"))
logFiles.Add($"{basePath}.error.log");
if (File.Exists($"{basePath}.ibg"))
logFiles.Add($"{basePath}.ibg");
if (File.Exists($"{basePath}.log"))
@@ -1414,6 +1457,8 @@ namespace MPF.Modules.Aaru
case MediaType.BluRay:
if (File.Exists($"{basePath}.cicm.xml"))
logFiles.Add($"{basePath}.cicm.xml");
if (File.Exists($"{basePath}.error.log"))
logFiles.Add($"{basePath}.error.log");
if (File.Exists($"{basePath}.ibg"))
logFiles.Add($"{basePath}.ibg");
if (File.Exists($"{basePath}.log"))
@@ -2603,6 +2648,119 @@ namespace MPF.Modules.Aaru
return datfile;
}
/// <summary>
/// Generate a CMP XML datfile string based on CICM sidecar data
/// </summary>
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
/// <param name="basePath">Base path for determining file names</param>
/// <returns>Datafile containing the hash information, null on error</returns>
private static Datafile GenerateDatafile(CICMMetadataType cicmSidecar, string basePath)
{
// If the object is null, we can't get information from it
if (cicmSidecar == null)
return null;
// Required variables
Datafile datafile = new Datafile();
List<Rom> roms = new List<Rom>();
// Process OpticalDisc, if possible
if (cicmSidecar.OpticalDisc != null && cicmSidecar.OpticalDisc.Length > 0)
{
// Loop through each OpticalDisc in the metadata
foreach (OpticalDiscType opticalDisc in cicmSidecar.OpticalDisc)
{
// Only capture the first total track count
uint totalTracks = 0;
if (opticalDisc.Tracks != null && opticalDisc.Tracks.Length > 0)
totalTracks = opticalDisc.Tracks[0];
// If there are no tracks, we can't get a datfile
if (opticalDisc.Track == null || opticalDisc.Track.Length == 0)
continue;
// Loop through each track
foreach (TrackType track in opticalDisc.Track)
{
uint trackNumber = track.Sequence?.TrackNumber ?? 0;
ulong size = track.Size;
string crc32 = string.Empty;
string md5 = string.Empty;
string sha1 = string.Empty;
// If we don't have any checksums, we can't get a DAT for this track
if (track.Checksums == null || track.Checksums.Length == 0)
continue;
// Extract only relevant checksums
foreach (ChecksumType checksum in track.Checksums)
{
switch (checksum.type)
{
case ChecksumTypeType.crc32:
crc32 = checksum.Value;
break;
case ChecksumTypeType.md5:
md5 = checksum.Value;
break;
case ChecksumTypeType.sha1:
sha1 = checksum.Value;
break;
}
}
// Build the track datfile data and append
string trackName = GenerateTrackName(basePath, (int)totalTracks, (int)trackNumber, opticalDisc.DiscType);
roms.Add(new Rom { Name = trackName, Size = size.ToString(), Crc = crc32, Md5 = md5, Sha1 = sha1 });
}
}
}
// Process BlockMedia, if possible
if (cicmSidecar.BlockMedia != null && cicmSidecar.BlockMedia.Length > 0)
{
// Loop through each BlockMedia in the metadata
foreach (BlockMediaType blockMedia in cicmSidecar.BlockMedia)
{
ulong size = blockMedia.Size;
string crc32 = string.Empty;
string md5 = string.Empty;
string sha1 = string.Empty;
// If we don't have any checksums, we can't get a DAT for this track
if (blockMedia.Checksums == null || blockMedia.Checksums.Length == 0)
continue;
// Extract only relevant checksums
foreach (ChecksumType checksum in blockMedia.Checksums)
{
switch (checksum.type)
{
case ChecksumTypeType.crc32:
crc32 = checksum.Value;
break;
case ChecksumTypeType.md5:
md5 = checksum.Value;
break;
case ChecksumTypeType.sha1:
sha1 = checksum.Value;
break;
}
}
// Build the track datfile data and append
string trackName = $"{basePath}.bin";
roms.Add(new Rom { Name = trackName, Size = size.ToString(), Crc = crc32, Md5 = md5, Sha1 = sha1 });
}
}
// Assign the roms to a new game
datafile.Games = new Game[1];
datafile.Games[0] = new Game { Roms = roms.ToArray() };
return datafile;
}
/// <summary>
/// Generate a track name based on current path and tracks
/// </summary>
@@ -2858,6 +3016,37 @@ namespace MPF.Modules.Aaru
return obj;
}
/// <summary>
/// Get reported disc type information, if possible
/// </summary>
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
/// <returns>True if disc type info was set, false otherwise</returns>
private static bool GetDiscType(CICMMetadataType cicmSidecar, out string discType, out string discSubType)
{
// Set the default values
discType = null; discSubType = null;
// If the object is null, we can't get information from it
if (cicmSidecar == null)
return false;
// Only care about OpticalDisc types
if (cicmSidecar.OpticalDisc == null || cicmSidecar.OpticalDisc.Length == 0)
return false;
// Find and return the hardware info, if possible
foreach (OpticalDiscType opticalDisc in cicmSidecar.OpticalDisc)
{
// Store the first instance of each value
if (string.IsNullOrEmpty(discType) && !string.IsNullOrEmpty(opticalDisc.DiscType))
discType = opticalDisc.DiscType;
if (string.IsNullOrEmpty(discSubType) && !string.IsNullOrEmpty(opticalDisc.DiscSubType))
discSubType = opticalDisc.DiscSubType;
}
return !string.IsNullOrEmpty(discType) || !string.IsNullOrEmpty(discSubType);
}
/// <summary>
/// Get the DVD protection information, if possible
/// </summary>
@@ -2951,6 +3140,50 @@ namespace MPF.Modules.Aaru
}
}
/// <summary>
/// Get hardware information, if possible
/// </summary>
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
/// <returns>True if hardware info was set, false otherwise</returns>
private static bool GetHardwareInfo(CICMMetadataType cicmSidecar, out string manufacturer, out string model, out string firmware)
{
// Set the default values
manufacturer = null; model = null; firmware = null;
// If the object is null, we can't get information from it
if (cicmSidecar == null)
return false;
// Only care about OpticalDisc types
if (cicmSidecar.OpticalDisc == null || cicmSidecar.OpticalDisc.Length == 0)
return false;
// Find and return the hardware info, if possible
foreach (OpticalDiscType opticalDisc in cicmSidecar.OpticalDisc)
{
// If there's no hardware information, skip
if (opticalDisc.DumpHardwareArray == null || !opticalDisc.DumpHardwareArray.Any())
continue;
foreach (DumpHardwareType hardware in opticalDisc.DumpHardwareArray)
{
// If the hardware information is invalid, skip
if (hardware == null)
continue;
// Store the first instance of each value
if (string.IsNullOrEmpty(manufacturer) && !string.IsNullOrEmpty(hardware.Manufacturer))
manufacturer = hardware.Manufacturer;
if (string.IsNullOrEmpty(model) && !string.IsNullOrEmpty(hardware.Model))
model = hardware.Model;
if (string.IsNullOrEmpty(firmware) && !string.IsNullOrEmpty(hardware.Firmware))
firmware = hardware.Firmware;
}
}
return !string.IsNullOrEmpty(manufacturer) || !string.IsNullOrEmpty(model) || !string.IsNullOrEmpty(firmware);
}
/// <summary>
/// Get the layerbreak from the input file, if possible
/// </summary>

7391
MPF.Modules/Aaru/cicm.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@@ -6,6 +6,9 @@ using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Schema;
using System.Xml;
using System.Xml.Serialization;
using MPF.Core.Data;
using MPF.Core.Hashing;
using MPF.Core.Utilities;
@@ -153,10 +156,11 @@ namespace MPF.Modules
/// Generate a SubmissionInfo for the output files
/// </summary>
/// <param name="submissionInfo">Base submission info to fill in specifics for</param>
/// <param name="options">Options object representing user-defined options</param>
/// <param name="basePath">Base filename and path to use for checking</param>
/// <param name="drive">Drive representing the disc to get information from</param>
/// <param name="includeArtifacts">True to include output files as encoded artifacts, false otherwise</param>
public abstract void GenerateSubmissionInfo(SubmissionInfo submissionInfo, string basePath, Drive drive, bool includeArtifacts);
public abstract void GenerateSubmissionInfo(SubmissionInfo submissionInfo, Options options, string basePath, Drive drive, bool includeArtifacts);
#endregion
@@ -241,7 +245,7 @@ namespace MPF.Modules
/// </summary>
/// <param name="parameters">String possibly representing parameters</param>
/// <returns>True if the parameters were set correctly, false otherwise</returns>
protected virtual bool ValidateAndSetParameters(string parameters) => true;
protected virtual bool ValidateAndSetParameters(string parameters) => !string.IsNullOrWhiteSpace(parameters);
#endregion
@@ -343,7 +347,7 @@ namespace MPF.Modules
return BitConverter.ToString(bytes).Replace("-", string.Empty);
}
return string.Join("\n", File.ReadAllLines(filename));
return File.ReadAllText(filename);
}
/// <summary>
@@ -621,6 +625,7 @@ namespace MPF.Modules
string valuePart = commandParts[1];
this[longFlagString] = true;
(string value, long factor) = ExtractFactorFromValue(valuePart);
return (sbyte)(sbyte.Parse(value) * factor);
}
@@ -697,6 +702,7 @@ namespace MPF.Modules
string valuePart = commandParts[1];
this[longFlagString] = true;
(string value, long factor) = ExtractFactorFromValue(valuePart);
return (short)(short.Parse(value) * factor);
}
@@ -773,6 +779,7 @@ namespace MPF.Modules
string valuePart = commandParts[1];
this[longFlagString] = true;
(string value, long factor) = ExtractFactorFromValue(valuePart);
return (int)(int.Parse(value) * factor);
}
@@ -849,6 +856,7 @@ namespace MPF.Modules
string valuePart = commandParts[1];
this[longFlagString] = true;
(string value, long factor) = ExtractFactorFromValue(valuePart);
return long.Parse(value) * factor;
}
@@ -931,6 +939,84 @@ namespace MPF.Modules
return string.Empty;
}
/// <summary>
/// Process a byte parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="flagString">Flag string, if available</param>
/// <param name="i">Reference to the position in the parts</param>
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
/// <returns>Byte value if success, Byte.MinValue if skipped, null on error/returns>
protected byte? ProcessUInt8Parameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
=> ProcessUInt8Parameter(parts, null, flagString, ref i, missingAllowed);
/// <summary>
/// Process a byte parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="shortFlagString">Short flag string, if available</param>
/// <param name="longFlagString">Long flag string, if available</param>
/// <param name="i">Reference to the position in the parts</param>
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
/// <returns>Byte value if success, Byte.MinValue if skipped, null on error/returns>
protected byte? ProcessUInt8Parameter(List<string> parts, string shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
{
if (parts == null)
return null;
if (parts[i] == shortFlagString || parts[i] == longFlagString)
{
if (!IsFlagSupported(longFlagString))
{
return null;
}
else if (!DoesExist(parts, i + 1))
{
if (missingAllowed)
this[longFlagString] = true;
return null;
}
else if (IsFlagSupported(parts[i + 1]))
{
if (missingAllowed)
this[longFlagString] = true;
return null;
}
else if (!IsValidInt8(parts[i + 1]))
{
if (missingAllowed)
this[longFlagString] = true;
return null;
}
this[longFlagString] = true;
i++;
(string value, long factor) = ExtractFactorFromValue(parts[i]);
return (byte)(byte.Parse(value) * factor);
}
else if (parts[i].StartsWith(shortFlagString + "=") || parts[i].StartsWith(longFlagString + "="))
{
if (!IsFlagSupported(longFlagString))
return null;
string[] commandParts = parts[i].Split('=');
if (commandParts.Length != 2)
return null;
string valuePart = commandParts[1];
this[longFlagString] = true;
(string value, long factor) = ExtractFactorFromValue(valuePart);
return (byte)(byte.Parse(value) * factor);
}
return Byte.MinValue;
}
/// <summary>
/// Get yhe trimmed value and multiplication factor from a value
/// </summary>
@@ -997,6 +1083,155 @@ namespace MPF.Modules
#region Common Information Extraction
/// <summary>
/// Generate the proper datfile from the input Datafile, if possible
/// </summary>
/// <param name="datafile">.dat file location</param>
/// <returns>Relevant pieces of the datfile, null on error</returns>
protected static string GenerateDatfile(Datafile datafile)
{
// If we don't have a valid datafile, we can't do anything
if (datafile?.Games == null || datafile.Games.Length == 0 || datafile.Games[0]?.Roms == null || datafile.Games[0].Roms.Length == 0)
return null;
// Otherwise, reconstruct the hash data with only the required info
try
{
var roms = datafile.Games[0].Roms;
string datString = string.Empty;
for (int i = 0; i < roms.Length; i++)
{
var rom = roms[i];
datString += $"<rom name=\"{rom.Name}\" size=\"{rom.Size}\" crc=\"{rom.Crc}\" md5=\"{rom.Md5}\" sha1=\"{rom.Sha1}\" />\n";
}
datString.TrimEnd('\n');
return datString;
}
catch
{
// We don't care what the exception is right now
return null;
}
}
/// <summary>
/// Get Datafile from a standard DAT
/// </summary>
/// <param name="dat">Path to the DAT file to parse</param>
/// <returns>Filled Datafile on success, null on error</returns>
protected static Datafile GetDatafile(string dat)
{
// If there's no path, we can't read the file
if (string.IsNullOrWhiteSpace(dat))
return null;
// If the file doesn't exist, we can't read it
if (!File.Exists(dat))
return null;
try
{
// Open and read in the XML file
XmlReader xtr = XmlReader.Create(dat, new XmlReaderSettings
{
CheckCharacters = false,
DtdProcessing = DtdProcessing.Ignore,
IgnoreComments = true,
IgnoreWhitespace = true,
ValidationFlags = XmlSchemaValidationFlags.None,
ValidationType = ValidationType.None,
});
// If the reader is null for some reason, we can't do anything
if (xtr == null)
return null;
XmlSerializer serializer = new XmlSerializer(typeof(Datafile));
Datafile obj = serializer.Deserialize(xtr) as Datafile;
return obj;
}
catch
{
// We don't care what the exception is right now
return null;
}
}
/// <summary>
/// Gets disc information from a PIC file
/// </summary>
/// <param name="pic">Path to a PIC.bin file</param>
/// <returns>Filled PICDiscInformation on success, null on error</returns>
/// <remarks>This omits the emergency brake information, if it exists</remarks>
protected static PICDiscInformation GetDiscInformation(string pic)
{
try
{
using (BinaryReader br = new BinaryReader(File.OpenRead(pic)))
{
var di = new PICDiscInformation();
// Read the initial disc information
di.DataStructureLength = br.ReadUInt16BigEndian();
di.Reserved0 = br.ReadByte();
di.Reserved1 = br.ReadByte();
// Create a list for the units
var diUnits = new List<PICDiscInformationUnit>();
// Loop and read all available units
for (int i = 0; i < 32; i++)
{
var unit = new PICDiscInformationUnit();
// We only accept Disc Information units, not Emergency Brake or other
unit.DiscInformationIdentifier = Encoding.ASCII.GetString(br.ReadBytes(2));
if (unit.DiscInformationIdentifier != "DI")
break;
unit.DiscInformationFormat = br.ReadByte();
unit.NumberOfUnitsInBlock = br.ReadByte();
unit.Reserved0 = br.ReadByte();
unit.SequenceNumber = br.ReadByte();
unit.BytesInUse = br.ReadByte();
unit.Reserved1 = br.ReadByte();
unit.DiscTypeIdentifier = Encoding.ASCII.GetString(br.ReadBytes(3));
unit.DiscSizeClassVersion = br.ReadByte();
switch (unit.DiscTypeIdentifier)
{
case PICDiscInformationUnit.DiscTypeIdentifierROM:
case PICDiscInformationUnit.DiscTypeIdentifierROMUltra:
unit.FormatDependentContents = br.ReadBytes(52);
break;
case PICDiscInformationUnit.DiscTypeIdentifierReWritable:
case PICDiscInformationUnit.DiscTypeIdentifierRecordable:
unit.FormatDependentContents = br.ReadBytes(100);
unit.DiscManufacturerID = br.ReadBytes(6);
unit.MediaTypeID = br.ReadBytes(3);
unit.TimeStamp = br.ReadUInt16();
unit.ProductRevisionNumber = br.ReadByte();
break;
}
diUnits.Add(unit);
}
// Assign the units and return
di.Units = diUnits.ToArray();
return di;
}
}
catch
{
// We don't care what the error was
return null;
}
}
/// <summary>
/// Get hashes from an input file path
/// </summary>
@@ -1116,6 +1351,8 @@ namespace MPF.Modules
if (string.IsNullOrWhiteSpace(hashData))
return false;
// TODO: Use deserialization to Rom instead of Regex
Regex hashreg = new Regex(@"<rom name="".*?"" size=""(.*?)"" crc=""(.*?)"" md5=""(.*?)"" sha1=""(.*?)""");
Match m = hashreg.Match(hashData);
if (m.Success)
@@ -1132,6 +1369,92 @@ namespace MPF.Modules
}
}
/// <summary>
/// Get the split values for ISO-based media
/// </summary>
/// <param name="datafile">Datafile represenging the hash data</param>
/// <returns>True if extraction was successful, false otherwise</returns>
protected static bool GetISOHashValues(Datafile datafile, out long size, out string crc32, out string md5, out string sha1)
{
size = -1; crc32 = null; md5 = null; sha1 = null;
if (datafile?.Games == null || datafile.Games.Length == 0 || datafile.Games[0].Roms.Length == 0)
return false;
var rom = datafile.Games[0].Roms[0];
Int64.TryParse(rom.Size, out size);
crc32 = rom.Crc;
md5 = rom.Md5;
sha1 = rom.Sha1;
return true;
}
/// <summary>
/// Get the layerbreak info associated from the disc information
/// </summary>
/// <param name="di">Disc information containing unformatted data</param>
/// <returns>True if layerbreak info was set, false otherwise</returns>
protected static bool GetLayerbreaks(PICDiscInformation di, out long? layerbreak1, out long? layerbreak2, out long? layerbreak3)
{
// Set the default values
layerbreak1 = null; layerbreak2 = null; layerbreak3 = null;
// If we don't have valid disc information, we can't do anything
if (di?.Units == null || di.Units.Length <= 1)
return false;
int ReadFromArrayBigEndian(byte[] bytes, int offset)
{
var span = new ReadOnlySpan<byte>(bytes, offset, 0x04);
byte[] rev = span.ToArray();
Array.Reverse(rev);
return BitConverter.ToInt32(rev, 0);
}
// Layerbreak 1 (2+ layers)
if (di.Units.Length >= 2)
{
long offset = ReadFromArrayBigEndian(di.Units[0].FormatDependentContents, 0x0C);
long value = ReadFromArrayBigEndian(di.Units[0].FormatDependentContents, 0x10);
layerbreak1 = value - offset + 2;
}
// Layerbreak 2 (3+ layers)
if (di.Units.Length >= 3)
{
long offset = ReadFromArrayBigEndian(di.Units[1].FormatDependentContents, 0x0C);
long value = ReadFromArrayBigEndian(di.Units[1].FormatDependentContents, 0x10);
layerbreak2 = layerbreak1 + value - offset + 2;
}
// Layerbreak 3 (4 layers)
if (di.Units.Length >= 4)
{
long offset = ReadFromArrayBigEndian(di.Units[2].FormatDependentContents, 0x0C);
long value = ReadFromArrayBigEndian(di.Units[2].FormatDependentContents, 0x10);
layerbreak3 = layerbreak2 + value - offset + 2;
}
return true;
}
/// <summary>
/// Get the PIC identifier from the first disc information unit, if possible
/// </summary>
/// <param name="di">Disc information containing the data</param>
/// <returns>String representing the PIC identifier, null on error</returns>
protected static string GetPICIdentifier(PICDiscInformation di)
{
// If we don't have valid disc information, we can't do anything
if (di?.Units == null || di.Units.Length <= 1)
return null;
// We assume the identifier is consistent across all units
return di.Units[0].DiscTypeIdentifier;
}
/// <summary>
/// Get the EXE date from a PlayStation disc, if possible
/// </summary>
@@ -1188,6 +1511,9 @@ namespace MPF.Modules
serial = exeName
.Replace('_', '-')
.Replace(".", string.Empty);
// Some games may have the EXE in a subfolder
serial = Path.GetFileName(serial);
}
}
@@ -1244,6 +1570,117 @@ namespace MPF.Modules
return null;
}
/// <summary>
/// Get the internal serial from a PlayStation 3 disc, if possible
/// </summary>
/// <param name="driveLetter">Drive letter to use to check</param>
/// <returns>Internal disc serial if possible, null on error</returns>
protected static string GetPlayStation3Serial(char? driveLetter)
{
// If there's no drive letter, we can't do this part
if (driveLetter == null)
return null;
// If the folder no longer exists, we can't do this part
string drivePath = driveLetter + ":\\";
if (!Directory.Exists(drivePath))
return null;
// If we can't find PARAM.SFO, we don't have a PlayStation 3 disc
string paramSfoPath = Path.Combine(drivePath, "PS3_GAME", "PARAM.SFO");
if (!File.Exists(paramSfoPath))
return null;
// Let's try reading PARAM.SFO to find the serial at the end of the file
try
{
using (BinaryReader br = new BinaryReader(File.OpenRead(paramSfoPath)))
{
br.BaseStream.Seek(-0x18, SeekOrigin.End);
return new string(br.ReadChars(9));
}
}
catch
{
// We don't care what the error was
return null;
}
}
/// <summary>
/// Get the version from a PlayStation 3 disc, if possible
/// </summary>
/// <param name="driveLetter">Drive letter to use to check</param>
/// <returns>Game version if possible, null on error</returns>
protected static string GetPlayStation3Version(char? driveLetter)
{
// If there's no drive letter, we can't do this part
if (driveLetter == null)
return null;
// If the folder no longer exists, we can't do this part
string drivePath = driveLetter + ":\\";
if (!Directory.Exists(drivePath))
return null;
// If we can't find PARAM.SFO, we don't have a PlayStation 3 disc
string paramSfoPath = Path.Combine(drivePath, "PS3_GAME", "PARAM.SFO");
if (!File.Exists(paramSfoPath))
return null;
// Let's try reading PARAM.SFO to find the version at the end of the file
try
{
using (BinaryReader br = new BinaryReader(File.OpenRead(paramSfoPath)))
{
br.BaseStream.Seek(-0x08, SeekOrigin.End);
return new string(br.ReadChars(5));
}
}
catch
{
// We don't care what the error was
return null;
}
}
/// <summary>
/// Get the internal serial from a PlayStation 4 disc, if possible
/// </summary>
/// <param name="driveLetter">Drive letter to use to check</param>
/// <returns>Internal disc serial if possible, null on error</returns>
protected static string GetPlayStation4Serial(char? driveLetter)
{
// If there's no drive letter, we can't do this part
if (driveLetter == null)
return null;
// If the folder no longer exists, we can't do this part
string drivePath = driveLetter + ":\\";
if (!Directory.Exists(drivePath))
return null;
// If we can't find param.sfo, we don't have a PlayStation 4 disc
string paramSfoPath = Path.Combine(drivePath, "bd", "param.sfo");
if (!File.Exists(paramSfoPath))
return null;
// Let's try reading param.sfo to find the serial at the end of the file
try
{
using (BinaryReader br = new BinaryReader(File.OpenRead(paramSfoPath)))
{
br.BaseStream.Seek(-0x14, SeekOrigin.End);
return new string(br.ReadChars(9));
}
}
catch
{
// We don't care what the error was
return null;
}
}
/// <summary>
/// Get the version from a PlayStation 4 disc, if possible
/// </summary>
@@ -1281,6 +1718,43 @@ namespace MPF.Modules
}
}
/// <summary>
/// Get the internal serial from a PlayStation 5 disc, if possible
/// </summary>
/// <param name="driveLetter">Drive letter to use to check</param>
/// <returns>Internal disc serial if possible, null on error</returns>
protected static string GetPlayStation5Serial(char? driveLetter)
{
// If there's no drive letter, we can't do this part
if (driveLetter == null)
return null;
// If the folder no longer exists, we can't do this part
string drivePath = driveLetter + ":\\";
if (!Directory.Exists(drivePath))
return null;
// If we can't find param.json, we don't have a PlayStation 5 disc
string paramJsonPath = Path.Combine(drivePath, "bd", "param.json");
if (!File.Exists(paramJsonPath))
return null;
// Let's try reading param.json to find the serial in the unencrypted JSON
try
{
using (BinaryReader br = new BinaryReader(File.OpenRead(paramJsonPath)))
{
br.BaseStream.Seek(0x82E, SeekOrigin.Begin);
return new string(br.ReadChars(9));
}
}
catch
{
// We don't care what the error was
return null;
}
}
/// <summary>
/// Get the version from a PlayStation 5 disc, if possible
/// </summary>
@@ -1391,4 +1865,4 @@ namespace MPF.Modules
#endregion
}
}
}

View File

@@ -2,6 +2,7 @@
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using MPF.Core.Converters;
using MPF.Core.Data;
using RedumpLib.Data;
@@ -58,12 +59,14 @@ namespace MPF.Modules.CleanRip
}
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive, bool includeArtifacts)
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive drive, bool includeArtifacts)
{
info.TracksAndWriteOffsets.ClrMameProData = GetCleanripDatfile(basePath + ".iso", basePath + "-dumpinfo.txt");
// TODO: Determine if there's a CleanRip version anywhere
info.DumpingInfo.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
Datafile datafile = GenerateCleanripDatafile(basePath + ".iso", basePath + "-dumpinfo.txt");
// Get the individual hash data, as per internal
if (GetISOHashValues(info.TracksAndWriteOffsets.ClrMameProData, out long size, out string crc32, out string md5, out string sha1))
if (GetISOHashValues(datafile, out long size, out string crc32, out string md5, out string sha1))
{
info.SizeAndChecksums.Size = size;
info.SizeAndChecksums.CRC32 = crc32;
@@ -84,10 +87,11 @@ namespace MPF.Modules.CleanRip
if (File.Exists(basePath + ".bca"))
info.Extras.BCA = GetBCA(basePath + ".bca");
if (GetGameCubeWiiInformation(basePath + "-dumpinfo.txt", out Region? gcRegion, out string gcVersion))
if (GetGameCubeWiiInformation(basePath + "-dumpinfo.txt", out Region? gcRegion, out string gcVersion, out string gcName))
{
info.CommonDiscInfo.Region = gcRegion ?? info.CommonDiscInfo.Region;
info.VersionAndEditions.Version = gcVersion ?? info.VersionAndEditions.Version;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalName] = gcName ?? string.Empty;
}
break;
@@ -127,6 +131,65 @@ namespace MPF.Modules.CleanRip
#region Information Extraction Methods
/// <summary>
/// Get a formatted datfile from the cleanrip output, if possible
/// </summary>
/// <param name="iso">Path to ISO file</param>
/// <param name="dumpinfo">Path to discinfo file</param>
/// <returns></returns>
private static Datafile GenerateCleanripDatafile(string iso, string dumpinfo)
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(dumpinfo))
return null;
using (StreamReader sr = File.OpenText(dumpinfo))
{
long size = new FileInfo(iso).Length;
string crc = string.Empty;
string md5 = string.Empty;
string sha1 = string.Empty;
try
{
// Make sure this file is a dumpinfo
if (!sr.ReadLine().Contains("--File Generated by CleanRip"))
return null;
// Read all lines and gather dat information
while (!sr.EndOfStream)
{
string line = sr.ReadLine().Trim();
if (line.StartsWith("CRC32"))
crc = line.Substring(7).ToLowerInvariant();
else if (line.StartsWith("MD5"))
md5 = line.Substring(5);
else if (line.StartsWith("SHA-1"))
sha1 = line.Substring(7);
}
return new Datafile
{
Games = new Game[]
{
new Game
{
Roms = new Rom[]
{
new Rom { Name = Path.GetFileName(iso), Size = size.ToString(), Crc = crc, Md5 = md5, Sha1 = sha1 },
}
}
}
};
}
catch
{
// We don't care what the exception is right now
return null;
}
}
}
/// <summary>
/// Get the hex contents of the BCA file
/// </summary>
@@ -204,10 +267,11 @@ namespace MPF.Modules.CleanRip
/// <param name="dumpinfo">Path to discinfo file</param>
/// <param name="region">Output region, if possible</param>
/// <param name="version">Output internal version of the game</param>
/// <param name="name">Output internal name of the game</param>
/// <returns></returns>
private static bool GetGameCubeWiiInformation(string dumpinfo, out Region? region, out string version)
private static bool GetGameCubeWiiInformation(string dumpinfo, out Region? region, out string version, out string name)
{
region = null; version = null;
region = null; version = null; name = null;
// If the file doesn't exist, we can't get info from it
if (!File.Exists(dumpinfo))
@@ -227,11 +291,15 @@ namespace MPF.Modules.CleanRip
string line = sr.ReadLine().Trim();
if (line.StartsWith("Version"))
{
version = line.Substring(9);
version = line.Substring("Version: ".Length);
}
else if (line.StartsWith("Internal Name"))
{
name = line.Substring("Internal Name: ".Length);
}
else if (line.StartsWith("Filename"))
{
string serial = line.Substring(10);
string serial = line.Substring("Filename: ".Length);
// char gameType = serial[0];
// string gameid = serial[1] + serial[2];

View File

@@ -2,6 +2,7 @@
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using MPF.Core.Converters;
using MPF.Core.Data;
using RedumpLib.Data;
@@ -75,11 +76,14 @@ namespace MPF.Modules.DD
}
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive, bool includeArtifacts)
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive drive, bool includeArtifacts)
{
// TODO: Fill in submission info specifics for DD
string outputDirectory = Path.GetDirectoryName(basePath);
// TODO: Determine if there's a DD version anywhere
info.DumpingInfo.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
switch (this.Type)
{
// Determine type-specific differences
@@ -96,7 +100,7 @@ namespace MPF.Modules.DD
info.CommonDiscInfo.EXEDateBuildDate = pythonTwoDate;
}
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? "";
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? string.Empty;
break;
case RedumpSystem.SonyPlayStation:
@@ -119,15 +123,22 @@ namespace MPF.Modules.DD
info.CommonDiscInfo.EXEDateBuildDate = playstationTwoDate;
}
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? "";
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? string.Empty;
break;
case RedumpSystem.SonyPlayStation3:
info.VersionAndEditions.Version = GetPlayStation3Version(drive?.Letter) ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = GetPlayStation3Serial(drive?.Letter) ?? string.Empty;
break;
case RedumpSystem.SonyPlayStation4:
info.VersionAndEditions.Version = GetPlayStation4Version(drive?.Letter) ?? "";
info.VersionAndEditions.Version = GetPlayStation4Version(drive?.Letter) ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = GetPlayStation4Serial(drive?.Letter) ?? string.Empty;
break;
case RedumpSystem.SonyPlayStation5:
info.VersionAndEditions.Version = GetPlayStation5Version(drive?.Letter) ?? "";
info.VersionAndEditions.Version = GetPlayStation5Version(drive?.Letter) ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = GetPlayStation5Serial(drive?.Letter) ?? string.Empty;
break;
}
}

73
MPF.Modules/Datafile.cs Normal file
View File

@@ -0,0 +1,73 @@
using System.Xml.Serialization;
namespace MPF.Modules
{
[XmlRoot("datafile")]
public class Datafile
{
[XmlElement("header")]
public Header Header;
[XmlElement("game")]
public Game[] Games;
}
public class Header
{
[XmlElement("name")]
public string Name;
[XmlElement("description")]
public string Description;
[XmlElement("version")]
public string Version;
[XmlElement("date")]
public string Date;
[XmlElement("author")]
public string Author;
[XmlElement("homepage")]
public string Homepage;
[XmlElement("url")]
public string Url;
}
public class Game
{
[XmlAttribute("name")]
public string Name;
[XmlElement("category")]
public string Category;
[XmlElement("description")]
public string Description;
[XmlElement("rom")]
public Rom[] Roms;
}
public class Rom
{
[XmlAttribute("name")]
public string Name;
[XmlAttribute("size")]
public string Size;
[XmlAttribute("crc")]
public string Crc;
[XmlAttribute("md5")]
public string Md5;
[XmlAttribute("sha1")]
public string Sha1;
// TODO: Add extended hashes here
}
}

View File

@@ -26,6 +26,7 @@ namespace MPF.Modules.DiscImageCreator
public const string Sub = "sub";
public const string Swap = "swap";
public const string Tape = "tape";
public const string Version = "/v";
public const string XBOX = "xbox";
public const string XBOXSwap = "xboxswap";
public const string XGD2Swap = "xgd2swap";
@@ -44,12 +45,13 @@ namespace MPF.Modules.DiscImageCreator
public const string C2Opcode = "/c2";
public const string CopyrightManagementInformation = "/c";
public const string D8Opcode = "/d8";
public const string DatExpand = "/d";
public const string DisableBeep = "/q";
public const string DVDReread = "/rr";
public const string ExtractMicroSoftCabFile = "/mscf";
public const string Fix = "/fix";
public const string ForceUnitAccess = "/f";
public const string MultiSectorRead = "/mr";
public const string MultiSession = "/ms";
public const string NoFixSubP = "/np";
public const string NoFixSubQ = "/nq";
public const string NoFixSubQLibCrypt = "/nl";
@@ -57,6 +59,7 @@ namespace MPF.Modules.DiscImageCreator
public const string NoFixSubQSecuROM = "/ns";
public const string NoSkipSS = "/nss";
public const string PadSector = "/ps";
public const string Range = "/ra";
public const string Raw = "/raw";
public const string Resume = "/re";
public const string Reverse = "/r";

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;netcoreapp3.1;net5.0</TargetFrameworks>
<PlatformTarget>x86</PlatformTarget>
<TargetFrameworks>net48;net6.0</TargetFrameworks>
<RuntimeIdentifiers>win7-x64;win8-x64;win81-x64;win10-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2021</Copyright>
<Copyright>Copyright (c)2019-2023</Copyright>
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
<Version>2.3</Version>
<Version>2.6.2</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<FileVersion>$(Version)</FileVersion>
<IncludeSource>true</IncludeSource>
@@ -20,27 +20,19 @@
<NrtShowRevision>false</NrtShowRevision>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)'=='net48'">
<DefineConstants>NET_FRAMEWORK</DefineConstants>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
<ProjectReference Include="..\MPF.CueSheets\MPF.CueSheets.csproj" />
<ProjectReference Include="..\RedumpLib\RedumpLib.csproj" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net48'">
<ProjectReference Include="..\CICMMetadata\CICMMetadataEditor\CICMMetadataEditor\CICMMetadataEditor.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.4" />
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.1">
<PackageReference Include="System.Memory" Version="4.5.5" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,72 @@
namespace MPF.Modules.Redumper
{
/// <summary>
/// Top-level commands for Redumper
/// </summary>
public static class CommandStrings
{
public const string NONE = "";
public const string CD = "cd";
public const string DVD = "dvd"; // Synonym for CD
public const string BluRay = "bd"; // Synonym for CD
public const string SACD = "sacd"; // Synonym for CD
public const string Dump = "dump";
public const string Info = "info";
public const string Protection = "protection";
public const string Refine = "refine";
public const string Split = "split";
public const string Verify = "verify";
public const string DVDKey = "dvdkey";
}
/// <summary>
/// Dumping flags for Redumper
/// </summary>
public static class FlagStrings
{
// General
public const string HelpLong = "--help";
public const string HelpShort = "-h";
public const string Verbose = "--verbose";
public const string Debug = "--debug";
public const string Drive = "--drive";
public const string Speed = "--speed";
public const string Retries = "--retries";
public const string ImagePath = "--image-path";
public const string ImageName = "--image-name";
public const string Overwrite = "--overwrite";
// Drive Configuration
public const string DriveType = "--drive-type";
public const string DriveReadOffset = "--drive-read-offset";
public const string DriveC2Shift = "--drive-c2-shift";
public const string DrivePregapStart = "--drive-pregap-start";
public const string DriveReadMethod = "--drive-read-method";
public const string DriveSectorOrder = "--drive-sector-order";
// Drive Specific
public const string PlextorLeadinSkip = "--plextor-leadin-skip";
public const string PlextorLeadinRetries = "--plextor-leadin-retries";
public const string AsusSkipLeadout = "--asus-skip-leadout";
// Offset
public const string ForceOffset = "--force-offset";
public const string AudioSilenceThreshold = "--audio-silence-threshold";
public const string CorrectOffsetShift = "--correct-offset-shift";
public const string OffsetShiftRelocate = "--offset-shift-relocate";
// Split
public const string ForceSplit = "--force-split";
public const string LeaveUnchanged = "--leave-unchanged";
public const string ForceQTOC = "--force-qtoc";
public const string SkipFill = "--skip-fill";
public const string ISO9660Trim = "--iso9660-trim";
// Miscellaneous
public const string LBAStart = "--lba-start";
public const string LBAEnd = "--lba-end";
public const string RefineSubchannel = "--refine-subchannel";
public const string Skip = "--skip";
public const string DumpReadSize = "--dump-read-size";
}
}

View File

@@ -0,0 +1,32 @@
using RedumpLib.Data;
namespace MPF.Modules.Redumper
{
public static class Converters
{
#region Cross-enumeration conversions
/// <summary>
/// Get the default extension for a given disc type
/// </summary>
/// <param name="type">MediaType value to check</param>
/// <returns>Valid extension (with leading '.'), null on error</returns>
public static string Extension(MediaType? type)
{
switch (type)
{
case MediaType.CDROM:
return ".bin";
case MediaType.DVD:
case MediaType.HDDVD:
case MediaType.BluRay:
return ".iso";
case MediaType.NONE:
default:
return null;
}
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using MPF.Core.Converters;
using MPF.Core.Data;
using RedumpLib.Data;
@@ -41,6 +42,8 @@ namespace MPF.Modules.UmdImageCreator
{
if (!File.Exists($"{basePath}_disc.txt"))
missingFiles.Add($"{basePath}_disc.txt");
if (!File.Exists($"{basePath}_drive.txt"))
missingFiles.Add($"{basePath}_drive.txt");
if (!File.Exists($"{basePath}_mainError.txt"))
missingFiles.Add($"{basePath}_mainError.txt");
if (!File.Exists($"{basePath}_mainInfo.txt"))
@@ -60,13 +63,16 @@ namespace MPF.Modules.UmdImageCreator
}
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive, bool includeArtifacts)
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive drive, bool includeArtifacts)
{
// TODO: Determine if there's a UMDImageCreator version anywhere
info.DumpingInfo.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
// Extract info based generically on MediaType
switch (this.Type)
{
case MediaType.UMD:
info.Extras.PVD = GetPVD(basePath + "_mainInfo.txt") ?? "";
info.Extras.PVD = GetPVD(basePath + "_mainInfo.txt") ?? string.Empty;
if (GetFileHashes(basePath + ".iso", out long filesize, out string crc32, out string md5, out string sha1))
{
@@ -78,9 +84,9 @@ namespace MPF.Modules.UmdImageCreator
if (GetUMDAuxInfo(basePath + "_disc.txt", out string title, out DiscCategory? umdcat, out string umdversion, out string umdlayer, out long umdsize))
{
info.CommonDiscInfo.Title = title ?? "";
info.CommonDiscInfo.Title = title ?? string.Empty;
info.CommonDiscInfo.Category = umdcat ?? DiscCategory.Games;
info.VersionAndEditions.Version = umdversion ?? "";
info.VersionAndEditions.Version = umdversion ?? string.Empty;
info.SizeAndChecksums.Size = umdsize;
if (!string.IsNullOrWhiteSpace(umdlayer))
@@ -95,6 +101,8 @@ namespace MPF.Modules.UmdImageCreator
{
if (File.Exists(basePath + "_disc.txt"))
info.Artifacts["disc"] = GetBase64(GetFullFile(basePath + "_disc.txt"));
if (File.Exists(basePath + "_drive.txt"))
info.Artifacts["drive"] = GetBase64(GetFullFile(basePath + "_drive.txt"));
if (File.Exists(basePath + "_mainError.txt"))
info.Artifacts["mainError"] = GetBase64(GetFullFile(basePath + "_mainError.txt"));
if (File.Exists(basePath + "_mainInfo.txt"))
@@ -113,6 +121,8 @@ namespace MPF.Modules.UmdImageCreator
case MediaType.UMD:
if (File.Exists($"{basePath}_disc.txt"))
logFiles.Add($"{basePath}_disc.txt");
if (File.Exists($"{basePath}_drive.txt"))
logFiles.Add($"{basePath}_drive.txt");
if (File.Exists($"{basePath}_mainError.txt"))
logFiles.Add($"{basePath}_mainError.txt");
if (File.Exists($"{basePath}_mainInfo.txt"))

View File

@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
#if NET_FRAMEWORK
#if NETFRAMEWORK
using IMAPI2;
#endif
using MPF.Core.Converters;
@@ -25,7 +25,7 @@ namespace MPF.Test.Core.Converters
DriveType.Removable,
};
#if NET_FRAMEWORK
#if NETFRAMEWORK
/// <summary>
/// IMAPI_MEDIA_PHYSICAL_TYPE values that map to MediaType
/// </summary>
@@ -71,7 +71,7 @@ namespace MPF.Test.Core.Converters
Assert.NotNull(actual);
}
#if NET_FRAMEWORK
#if NETFRAMEWORK
/// <summary>
/// Check that every supported IMAPI_MEDIA_PHYSICAL_TYPE maps to an MediaType
/// </summary>
@@ -108,7 +108,7 @@ namespace MPF.Test.Core.Converters
return testData;
}
#if NET_FRAMEWORK
#if NETFRAMEWORK
/// <summary>
/// Generate a test set of IMAPI_MEDIA_PHYSICAL_TYPE values
/// </summary>

View File

@@ -31,6 +31,7 @@ namespace MPF.Test.Core.Utilities
RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem,
RedumpSystem.AudioCD,
RedumpSystem.DVDAudio,
RedumpSystem.HasbroiONEducationalGamingSystem,
RedumpSystem.HasbroVideoNow,
RedumpSystem.HasbroVideoNowColor,
RedumpSystem.HasbroVideoNowJr,
@@ -58,6 +59,7 @@ namespace MPF.Test.Core.Utilities
RedumpSystem.SonyPlayStation2,
RedumpSystem.SonyPlayStation3,
RedumpSystem.SonyPlayStation4,
RedumpSystem.SonyPlayStationPortable,
};
/// <summary>

View File

@@ -18,11 +18,13 @@ namespace MPF.Test.Library
public void ParametersValidTest(string parameters, char letter, bool isFloppy, MediaType? mediaType, bool expected)
{
var options = new Options() { InternalProgram = InternalProgram.DiscImageCreator };
var drive = isFloppy
? new Drive(InternalDriveType.Floppy, new DriveInfo(letter.ToString()))
: new Drive(InternalDriveType.Optical, new DriveInfo(letter.ToString()));
var env = new DumpEnvironment(options, string.Empty, string.Empty, drive, RedumpSystem.IBMPCcompatible, mediaType, parameters);
// TODO: This relies on creating real objects for the drive. Can we mock this out instead?
var drive = isFloppy
? Drive.Create(InternalDriveType.Floppy, letter.ToString())
: Drive.Create(InternalDriveType.Optical, letter.ToString());
var env = new DumpEnvironment(options, string.Empty, drive, RedumpSystem.IBMPCcompatible, mediaType, null, parameters);
bool actual = env.ParametersValid();
Assert.Equal(expected, actual);

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.IO;
using MPF.Library;
using RedumpLib.Data;
using Xunit;
@@ -43,24 +44,27 @@ namespace MPF.Test.Library
long layerbreak3,
string expected)
{
string actual = InfoTool.GetFixedMediaType(mediaType, size, layerbreak, layerbreak2, layerbreak3);
// TODO: Add tests around BDU
string actual = InfoTool.GetFixedMediaType(mediaType, null, size, layerbreak, layerbreak2, layerbreak3);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(null, null, null, null)]
[InlineData(" ", "", " ", "")]
[InlineData("super", "blah.bin", "super", "blah.bin")]
[InlineData("super\\hero", "blah.bin", "super\\hero", "blah.bin")]
[InlineData("super.hero", "blah.bin", "super.hero", "blah.bin")]
[InlineData("superhero", "blah.rev.bin", "superhero", "blah.rev.bin")]
[InlineData("super&hero", "blah.bin", "super&hero", "blah.bin")]
[InlineData("superhero", "blah&foo.bin", "superhero", "blah&foo.bin")]
public void NormalizeOutputPathsTest(string outputDirectory, string outputFilename, string expectedOutputDirectory, string expectedOutputFilename)
[InlineData(null, null)]
[InlineData(" ", " ")]
[InlineData("super\\blah.bin", "super\\blah.bin")]
[InlineData("super\\hero\\blah.bin", "super\\hero\\blah.bin")]
[InlineData("super.hero\\blah.bin", "super.hero\\blah.bin")]
[InlineData("superhero\\blah.rev.bin", "superhero\\blah.rev.bin")]
[InlineData("super&hero\\blah.bin", "super&hero\\blah.bin")]
[InlineData("superhero\\blah&foo.bin", "superhero\\blah&foo.bin")]
public void NormalizeOutputPathsTest(string outputPath, string expectedPath)
{
(string actualOutputDirectory, string actualOutputFilename) = InfoTool.NormalizeOutputPaths(outputDirectory, outputFilename);
Assert.Equal(expectedOutputDirectory, actualOutputDirectory);
Assert.Equal(expectedOutputFilename, actualOutputFilename);
if (!string.IsNullOrWhiteSpace(expectedPath))
expectedPath = Path.GetFullPath(expectedPath);
string actualPath = InfoTool.NormalizeOutputPaths(outputPath);
Assert.Equal(expectedPath, actualPath);
}
[Fact]

View File

@@ -1,15 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;netcoreapp3.1;net5.0-windows</TargetFrameworks>
<PlatformTarget>x86</PlatformTarget>
<TargetFrameworks>net48;net6.0-windows</TargetFrameworks>
<IsPackable>false</IsPackable>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)'=='net48'">
<DefineConstants>NET_FRAMEWORK</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net48'">
<COMReference Include="IMAPI2">
<Guid>{2735412F-7F64-5B0F-8F00-5D77AFBE261E}</Guid>
@@ -39,18 +34,21 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeCoverage" Version="16.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="Microsoft.CodeCoverage" Version="17.6.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="xunit" Version="2.5.0" />
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
<PackageReference Include="xunit.analyzers" Version="0.10.0" />
<PackageReference Include="xunit.assert" Version="2.4.1" />
<PackageReference Include="xunit.core" Version="2.4.1" />
<PackageReference Include="xunit.extensibility.core" Version="2.4.1" />
<PackageReference Include="xunit.extensibility.execution" Version="2.4.1" />
<PackageReference Include="xunit.runner.console" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PackageReference Include="xunit.analyzers" Version="1.2.0" />
<PackageReference Include="xunit.assert" Version="2.5.0" />
<PackageReference Include="xunit.core" Version="2.5.0" />
<PackageReference Include="xunit.extensibility.core" Version="2.5.0" />
<PackageReference Include="xunit.extensibility.execution" Version="2.5.0" />
<PackageReference Include="xunit.runner.console" Version="2.5.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -19,38 +19,122 @@ namespace MPF.Test.Modules
[InlineData(RedumpSystem.RawThrillsVarious, MediaType.GDROM, null)]
public void ParametersFromSystemAndTypeTest(RedumpSystem? knownSystem, MediaType? mediaType, string expected)
{
var options = new Options { };
var options = new Options();
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, options);
Assert.Equal(expected, actual.BaseCommand);
}
[Theory]
[InlineData(RedumpSystem.AppleMacintosh, MediaType.LaserDisc, true, 20, null, null)]
[InlineData(RedumpSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc, false, 20, null, new string[] { FlagStrings.Raw })]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, false, 20, null, new string[] { FlagStrings.CopyrightManagementInformation, FlagStrings.ScanFileProtect })]
/* paranoid mode tests */
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, true, 1000, 2, new string[] { FlagStrings.C2Opcode, FlagStrings.NoFixSubQSecuROM, FlagStrings.ScanFileProtect, FlagStrings.ScanSectorProtect, FlagStrings.SubchannelReadLevel })]
[InlineData(RedumpSystem.AppleMacintosh, MediaType.CDROM, false, 20, null, new string[] { FlagStrings.C2Opcode, FlagStrings.NoFixSubQSecuROM, FlagStrings.ScanFileProtect, FlagStrings.ScanSectorProtect, FlagStrings.SubchannelReadLevel })]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, true, 500, null, new string[] { FlagStrings.CopyrightManagementInformation, FlagStrings.ScanFileProtect })]
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, true, 500, null, new string[] { FlagStrings.CopyrightManagementInformation })]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, false, 500, null, new string[] { FlagStrings.CopyrightManagementInformation, FlagStrings.ScanFileProtect })]
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, false, 500, null, new string[] { FlagStrings.CopyrightManagementInformation })]
/* reread c2 */
[InlineData(RedumpSystem.SegaDreamcast, MediaType.GDROM, false, 1000, null, new string[] { FlagStrings.C2Opcode })]
[InlineData(RedumpSystem.SegaDreamcast, MediaType.GDROM, false, -1, null, new string[] { FlagStrings.C2Opcode })]
public void ParametersFromOptionsTest(RedumpSystem? knownSystem, MediaType? mediaType, bool paranoid, int rereadC2, int? subchannelLevel, string[] expected)
[InlineData(RedumpSystem.AppleMacintosh, MediaType.LaserDisc, null)] // Deliberately unsupported
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, new string[] { FlagStrings.C2Opcode, FlagStrings.NoFixSubQSecuROM, FlagStrings.ScanFileProtect })]
[InlineData(RedumpSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc, new string[] { FlagStrings.Raw })]
public void ParametersFromOptionsSpecialDefaultTest(RedumpSystem? knownSystem, MediaType? mediaType,string[] expected)
{
var options = new Options { DICParanoidMode = paranoid, DICRereadCount = rereadC2 };
var options = new Options();
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, options);
HashSet<string> expectedSet = new HashSet<string>(expected ?? new string[0]);
HashSet<string> actualSet = new HashSet<string>(actual.Keys ?? new string[0]);
HashSet<string> actualSet = GenerateUsedKeys(actual);
Assert.Equal(expectedSet, actualSet);
}
[Theory]
[InlineData(RedumpSystem.SegaDreamcast, MediaType.GDROM, 1000, new string[] { FlagStrings.C2Opcode })]
[InlineData(RedumpSystem.SegaDreamcast, MediaType.GDROM, -1, new string[] { FlagStrings.C2Opcode })]
public void ParametersFromOptionsC2RereadTest(RedumpSystem? knownSystem, MediaType? mediaType, int rereadC2, string[] expected)
{
var options = new Options { DICRereadCount = rereadC2 };
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, options);
HashSet<string> expectedSet = new HashSet<string>(expected ?? new string[0]);
HashSet<string> actualSet = GenerateUsedKeys(actual);
Assert.Equal(expectedSet, actualSet);
if (rereadC2 == -1 || !knownSystem.MediaTypes().Contains(mediaType))
Assert.Null(actual.C2OpcodeValue[0]);
else
Assert.Equal(rereadC2, actual.C2OpcodeValue[0]);
Assert.Equal(subchannelLevel, actual.SubchannelReadLevelValue);
}
[Theory]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, 1000, new string[] { FlagStrings.DVDReread })]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, -1, new string[] { FlagStrings.DVDReread })]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.BluRay, 1000, new string[] { FlagStrings.DVDReread })]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.BluRay, -1, new string[] { FlagStrings.DVDReread })]
public void ParametersFromOptionsDVDRereadTest(RedumpSystem? knownSystem, MediaType? mediaType, int rereadDVDBD, string[] expected)
{
var options = new Options { DICDVDRereadCount = rereadDVDBD };
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, options);
HashSet<string> expectedSet = new HashSet<string>(expected ?? new string[0]);
HashSet<string> actualSet = GenerateUsedKeys(actual);
Assert.Equal(expectedSet, actualSet);
if (rereadDVDBD == -1 || !knownSystem.MediaTypes().Contains(mediaType))
Assert.Null(actual.DVDRereadValue);
else
Assert.Equal(rereadDVDBD, actual.DVDRereadValue);
}
[Theory]
[InlineData(RedumpSystem.BDVideo, MediaType.BluRay, true, new string[] { FlagStrings.DVDReread })]
[InlineData(RedumpSystem.BDVideo, MediaType.BluRay, false, new string[] { FlagStrings.DVDReread })]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, true, new string[] { FlagStrings.C2Opcode, FlagStrings.NoFixSubQSecuROM, FlagStrings.MultiSectorRead, FlagStrings.ScanFileProtect })]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, false, new string[] { FlagStrings.C2Opcode, FlagStrings.NoFixSubQSecuROM, FlagStrings.ScanFileProtect })]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, true, new string[] { FlagStrings.DVDReread })]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, false, new string[] { FlagStrings.DVDReread })]
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, true, new string[] { FlagStrings.DVDReread })]
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, false, new string[] { FlagStrings.DVDReread })]
public void ParametersFromOptionsMultiSectorReadTest(RedumpSystem? knownSystem, MediaType? mediaType, bool multiSectorRead, string[] expected)
{
var options = new Options { DICMultiSectorRead = multiSectorRead };
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, options);
HashSet<string> expectedSet = new HashSet<string>(expected ?? new string[0]);
HashSet<string> actualSet = GenerateUsedKeys(actual);
Assert.Equal(expectedSet, actualSet);
if (expectedSet.Count != 1 && multiSectorRead)
Assert.Equal(0, actual.MultiSectorReadValue);
}
[Theory]
[InlineData(RedumpSystem.BDVideo, MediaType.BluRay, true, new string[] { FlagStrings.DVDReread })]
[InlineData(RedumpSystem.BDVideo, MediaType.BluRay, false, new string[] { FlagStrings.DVDReread })]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, true, new string[] { FlagStrings.C2Opcode, FlagStrings.NoFixSubQSecuROM, FlagStrings.ScanFileProtect, FlagStrings.ScanSectorProtect, FlagStrings.SubchannelReadLevel })]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, false, new string[] { FlagStrings.C2Opcode, FlagStrings.NoFixSubQSecuROM, FlagStrings.ScanFileProtect })]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, true, new string[] { FlagStrings.DVDReread, FlagStrings.ScanFileProtect })]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, false, new string[] { FlagStrings.DVDReread })]
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, true, new string[] { FlagStrings.DVDReread })]
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, false, new string[] { FlagStrings.DVDReread })]
public void ParametersFromOptionsParanoidModeTest(RedumpSystem? knownSystem, MediaType? mediaType, bool paranoidMode, string[] expected)
{
var options = new Options { DICParanoidMode = paranoidMode };
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, options);
HashSet<string> expectedSet = new HashSet<string>(expected ?? new string[0]);
HashSet<string> actualSet = GenerateUsedKeys(actual);
Assert.Equal(expectedSet, actualSet);
if (paranoidMode)
{
if (actualSet.Contains(FlagStrings.ScanSectorProtect))
Assert.True(actual[FlagStrings.ScanSectorProtect]);
if (actualSet.Contains(FlagStrings.SubchannelReadLevel))
{
Assert.True(actual[FlagStrings.SubchannelReadLevel]);
Assert.Equal(2, actual.SubchannelReadLevelValue);
}
}
else
{
if (actualSet.Contains(FlagStrings.ScanSectorProtect))
Assert.False(actual[FlagStrings.ScanSectorProtect]);
if (actualSet.Contains(FlagStrings.SubchannelReadLevel))
Assert.False(actual[FlagStrings.SubchannelReadLevel]);
Assert.Null(actual.SubchannelReadLevelValue);
}
}
[Theory]
@@ -78,7 +162,7 @@ namespace MPF.Test.Modules
[InlineData(MediaType.NONE, null)]
public void MediaTypeToExtensionTest(MediaType? mediaType, string expected)
{
string actual = MPF.Modules.DiscImageCreator.Converters.Extension(mediaType);
string actual = Converters.Extension(mediaType);
Assert.Equal(expected, actual);
}
@@ -102,7 +186,7 @@ namespace MPF.Test.Modules
[InlineData(CommandStrings.XBOX, MediaType.DVD)]
public void BaseCommandToMediaTypeTest(string command, MediaType? expected)
{
MediaType? actual = MPF.Modules.DiscImageCreator.Converters.ToMediaType(command);
MediaType? actual = Converters.ToMediaType(command);
Assert.Equal(expected, actual);
}
@@ -126,7 +210,7 @@ namespace MPF.Test.Modules
[InlineData(CommandStrings.XBOX, RedumpSystem.MicrosoftXbox)]
public void BaseCommandToRedumpSystemTest(string command, RedumpSystem? expected)
{
RedumpSystem? actual = MPF.Modules.DiscImageCreator.Converters.ToRedumpSystem(command);
RedumpSystem? actual = Converters.ToRedumpSystem(command);
Assert.Equal(expected, actual);
}
@@ -161,5 +245,25 @@ namespace MPF.Test.Modules
Assert.NotNull(newParameters);
Assert.Equal(originalParameters, newParameters);
}
/// <summary>
/// Generate a HashSet of keys that are considered to be set
/// </summary>
/// <param name="parameters">Parameters object to get keys from</param>
/// <returns>HashSet representing the strings</returns>
private static HashSet<string> GenerateUsedKeys(Parameters parameters)
{
HashSet<string> usedKeys = new HashSet<string>();
if (parameters?.Keys == null)
return usedKeys;
foreach (string key in parameters.Keys)
{
if (parameters[key] == true)
usedKeys.Add(key);
}
return usedKeys;
}
}
}

View File

@@ -18,12 +18,17 @@ namespace MPF.Test.RedumpLib
private static readonly DiscType?[] _mappableDiscTypes = new DiscType?[]
{
DiscType.BD25,
DiscType.BD33,
DiscType.BD50,
DiscType.BD66,
DiscType.BD100,
DiscType.BD128,
DiscType.CD,
DiscType.DVD5,
DiscType.DVD9,
DiscType.GDROM,
DiscType.HDDVDSL,
DiscType.HDDVDDL,
DiscType.NintendoGameCubeGameDisc,
DiscType.NintendoWiiOpticalDiscSL,
DiscType.NintendoWiiOpticalDiscDL,
@@ -573,17 +578,6 @@ namespace MPF.Test.RedumpLib
#region System
/// <summary>
/// RedumpSystem values that are considered markers and not real systems
/// </summary>
private static readonly RedumpSystem?[] _markerSystemTypes = new RedumpSystem?[]
{
RedumpSystem.MarkerArcadeEnd,
RedumpSystem.MarkerComputerEnd,
RedumpSystem.MarkerDiscBasedConsoleEnd,
RedumpSystem.MarkerOtherEnd,
};
/// <summary>
/// Check that every RedumpSystem has a long name provided
/// </summary>
@@ -634,7 +628,7 @@ namespace MPF.Test.RedumpLib
foreach (RedumpSystem? redumpSystem in Enum.GetValues(typeof(RedumpSystem)))
{
// We want to skip all markers for this
if (_markerSystemTypes.Contains(redumpSystem))
if (redumpSystem.IsMarker())
continue;
testData.Add(new object[] { redumpSystem, false });

View File

@@ -42,7 +42,8 @@ namespace MPF.Test.RedumpLib
var submissionInfo = new SubmissionInfo()
{
SchemaVersion = 1,
MatchedIDs = new List<int> { 0, 1, 2, 3 },
FullyMatchedID = 3,
PartiallyMatchedIDs = new List<int> { 0, 1, 2, 3 },
Added = DateTime.UtcNow,
LastModified = DateTime.UtcNow,
@@ -132,7 +133,7 @@ namespace MPF.Test.RedumpLib
DumpersAndStatus = new DumpersAndStatusSection()
{
Status = DumpStatus.TwoOrMoHumanReadablesGreen,
Status = DumpStatus.TwoOrMoreGreen,
Dumpers = new string[] { "Dumper1", "Dumper2" },
OtherDumpers = "Dumper3",
},
@@ -156,6 +157,15 @@ namespace MPF.Test.RedumpLib
SHA1 = "SHA1",
},
DumpingInfo = new DumpingInfoSection()
{
DumpingProgram = "DiscImageCreator 20500101",
Manufacturer = "ATAPI",
Model = "Optical Drive",
Firmware = "1.23",
ReportedDiscType = "CD-R",
},
Artifacts = new Dictionary<string, string>()
{
["Sample Artifact"] = "Sample Data",

View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using MPF.Core.Converters;
namespace MPF
namespace MPF.UI.Core.ComboBoxItems
{
/// <summary>
/// A generic combo box element

View File

@@ -1,4 +1,4 @@
namespace MPF
namespace MPF.UI.Core.ComboBoxItems
{
public interface IElement
{

View File

Before

Width:  |  Height:  |  Size: 423 KiB

After

Width:  |  Height:  |  Size: 423 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@@ -0,0 +1,62 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFrameworks>net48;net6.0-windows</TargetFrameworks>
<RuntimeIdentifiers>win7-x64;win8-x64;win81-x64;win10-x64</RuntimeIdentifiers>
<UseWindowsForms>true</UseWindowsForms>
<UseWPF>true</UseWPF>
<Title>MPF.UI.Core</Title>
<AssemblyName>MPF.UI.Core</AssemblyName>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2023</Copyright>
<Version>2.6.2</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<FileVersion>$(Version)</FileVersion>
<IncludeSource>true</IncludeSource>
<IncludeSymbols>true</IncludeSymbols>
</PropertyGroup>
<PropertyGroup>
<NrtRevisionFormat>$(Version)-{chash:8}</NrtRevisionFormat>
<NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes>
<NrtShowRevision>false</NrtShowRevision>
<UserSecretsId>27abb4ca-bf7a-431e-932f-49153303d5ff</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Resource Include="Images\ring-code-guide-1-layer.png" />
<Resource Include="Images\ring-code-guide-2-layer.png" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
<ProjectReference Include="..\RedumpLib\RedumpLib.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="PresentationFramework.Aero" />
</ItemGroup>
<ItemGroup>
<Folder Include="Images\" />
</ItemGroup>
<ItemGroup>
<Page Update="UserControls\UserInput.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
</Page>
<Page Update="Windows\DiscInformationWindow.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
</Page>
<Page Update="Windows\RingCodeGuideWindow.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
</Page>
</ItemGroup>
</Project>

400
MPF.UI.Core/Theme.cs Normal file
View File

@@ -0,0 +1,400 @@
using System.Windows;
using System.Windows.Media;
namespace MPF.UI.Core
{
/// <summary>
/// Represents all required mapping values for the UI
/// </summary>
public class Theme
{
#region Application-Wide
/// <summary>
/// SolidColorBrush used to paint the active window's border.
/// </summary>
public SolidColorBrush ActiveBorderBrush { get; set; }
/// <summary>
/// SolidColorBrush that paints the face of a three-dimensional display element.
/// </summary>
public SolidColorBrush ControlBrush { get; set; }
/// <summary>
/// SolidColorBrush that paints text in a three-dimensional display element.
/// </summary>
public SolidColorBrush ControlTextBrush { get; set; }
/// <summary>
/// SolidColorBrush that paints disabled text.
/// </summary>
public SolidColorBrush GrayTextBrush { get; set; }
/// <summary>
/// SolidColorBrush that paints the background of a window's client area.
/// </summary>
public SolidColorBrush WindowBrush { get; set; }
/// <summary>
/// SolidColorBrush that paints the text in the client area of a window.
/// </summary>
public SolidColorBrush WindowTextBrush { get; set; }
#endregion
#region Button
/// <summary>
/// Brush for the Button.Disabled.Background resource
/// </summary>
public Brush Button_Disabled_Background { get; set; }
/// <summary>
/// Brush for the Button.MouseOver.Background resource
/// </summary>
public Brush Button_MouseOver_Background { get; set; }
/// <summary>
/// Brush for the Button.Pressed.Background resource
/// </summary>
public Brush Button_Pressed_Background { get; set; }
/// <summary>
/// Brush for the Button.Static.Background resource
/// </summary>
public Brush Button_Static_Background { get; set; }
#endregion
#region ComboBox
/// <summary>
/// Brush for the ComboBox.Disabled.Background resource
/// </summary>
public Brush ComboBox_Disabled_Background { get; set; }
/// <summary>
/// Brush for the ComboBox.Disabled.Editable.Background resource
/// </summary>
public Brush ComboBox_Disabled_Editable_Background { get; set; }
/// <summary>
/// Brush for the ComboBox.Disabled.Editable.Button.Background resource
/// </summary>
public Brush ComboBox_Disabled_Editable_Button_Background { get; set; }
/// <summary>
/// Brush for the ComboBox.MouseOver.Background resource
/// </summary>
public Brush ComboBox_MouseOver_Background { get; set; }
/// <summary>
/// Brush for the ComboBox.MouseOver.Editable.Background resource
/// </summary>
public Brush ComboBox_MouseOver_Editable_Background { get; set; }
/// <summary>
/// Brush for the ComboBox.MouseOver.Editable.Button.Background resource
/// </summary>
public Brush ComboBox_MouseOver_Editable_Button_Background { get; set; }
/// <summary>
/// Brush for the ComboBox.Pressed.Background resource
/// </summary>
public Brush ComboBox_Pressed_Background { get; set; }
/// <summary>
/// Brush for the ComboBox.Pressed.Editable.Background resource
/// </summary>
public Brush ComboBox_Pressed_Editable_Background { get; set; }
/// <summary>
/// Brush for the ComboBox.Pressed.Editable.Button.Background resource
/// </summary>
public Brush ComboBox_Pressed_Editable_Button_Background { get; set; }
/// <summary>
/// Brush for the ComboBox.Static.Background resource
/// </summary>
public Brush ComboBox_Static_Background { get; set; }
/// <summary>
/// Brush for the ComboBox.Static.Editable.Background resource
/// </summary>
public Brush ComboBox_Static_Editable_Background { get; set; }
/// <summary>
/// Brush for the ComboBox.Static.Editable.Button.Background resource
/// </summary>
public Brush ComboBox_Static_Editable_Button_Background { get; set; }
#endregion
#region CustomMessageBox
/// <summary>
/// Brush for the CustomMessageBox.Static.Background resource
/// </summary>
public Brush CustomMessageBox_Static_Background { get; set; }
#endregion
#region MenuItem
/// <summary>
/// Brush for the MenuItem.SubMenu.Background resource
/// </summary>
public Brush MenuItem_SubMenu_Background { get; set; }
/// <summary>
/// Brush for the MenuItem.SubMenu.Border resource
/// </summary>
public Brush MenuItem_SubMenu_Border { get; set; }
#endregion
#region ProgressBar
/// <summary>
/// Brush for the ProgressBar.Background resource
/// </summary>
public Brush ProgressBar_Background { get; set; }
#endregion
#region ScrollViewer
/// <summary>
/// Brush for the ScrollViewer.ScrollBar.Background resource
/// </summary>
public Brush ScrollViewer_ScrollBar_Background { get; set; }
#endregion
#region TabItem
/// <summary>
/// Brush for the TabItem.Selected.Background resource
/// </summary>
public Brush TabItem_Selected_Background { get; set; }
/// <summary>
/// Brush for the TabItem.Static.Background resource
/// </summary>
public Brush TabItem_Static_Background { get; set; }
/// <summary>
/// Brush for the TabItem.Static.Border resource
/// </summary>
public Brush TabItem_Static_Border { get; set; }
#endregion
#region TextBox
/// <summary>
/// Brush for the TextBox.Static.Background resource
/// </summary>
public Brush TextBox_Static_Background { get; set; }
#endregion
/// <summary>
/// Apply the theme to the current application
/// </summary>
public void Apply()
{
// Handle application-wide resources
Application.Current.Resources[SystemColors.ActiveBorderBrushKey] = this.ActiveBorderBrush;
Application.Current.Resources[SystemColors.ControlBrushKey] = this.ControlBrush;
Application.Current.Resources[SystemColors.ControlTextBrushKey] = this.ControlTextBrush;
Application.Current.Resources[SystemColors.GrayTextBrushKey] = this.GrayTextBrush;
Application.Current.Resources[SystemColors.WindowBrushKey] = this.WindowBrush;
Application.Current.Resources[SystemColors.WindowTextBrushKey] = this.WindowTextBrush;
// Handle Button-specific resources
Application.Current.Resources["Button.Disabled.Background"] = this.Button_Disabled_Background;
Application.Current.Resources["Button.MouseOver.Background"] = this.Button_MouseOver_Background;
Application.Current.Resources["Button.Pressed.Background"] = this.Button_Pressed_Background;
Application.Current.Resources["Button.Static.Background"] = this.Button_Static_Background;
// Handle ComboBox-specific resources
Application.Current.Resources["ComboBox.Disabled.Background"] = this.ComboBox_Disabled_Background;
Application.Current.Resources["ComboBox.Disabled.Editable.Background"] = this.ComboBox_Disabled_Editable_Background;
Application.Current.Resources["ComboBox.Disabled.Editable.Button.Background"] = this.ComboBox_Disabled_Editable_Button_Background;
Application.Current.Resources["ComboBox.MouseOver.Background"] = this.ComboBox_MouseOver_Background;
Application.Current.Resources["ComboBox.MouseOver.Editable.Background"] = this.ComboBox_MouseOver_Editable_Background;
Application.Current.Resources["ComboBox.MouseOver.Editable.Button.Background"] = this.ComboBox_MouseOver_Editable_Button_Background;
Application.Current.Resources["ComboBox.Pressed.Background"] = this.ComboBox_Pressed_Background;
Application.Current.Resources["ComboBox.Pressed.Editable.Background"] = this.ComboBox_Pressed_Editable_Background;
Application.Current.Resources["ComboBox.Pressed.Editable.Button.Background"] = this.ComboBox_Pressed_Editable_Button_Background;
Application.Current.Resources["ComboBox.Static.Background"] = this.ComboBox_Static_Background;
Application.Current.Resources["ComboBox.Static.Editable.Background"] = this.ComboBox_Static_Editable_Background;
Application.Current.Resources["ComboBox.Static.Editable.Button.Background"] = this.ComboBox_Static_Editable_Button_Background;
// Handle CustomMessageBox-specific resources
Application.Current.Resources["CustomMessageBox.Static.Background"] = this.CustomMessageBox_Static_Background;
// Handle MenuItem-specific resources
Application.Current.Resources["MenuItem.SubMenu.Background"] = this.MenuItem_SubMenu_Background;
Application.Current.Resources["MenuItem.SubMenu.Border"] = this.MenuItem_SubMenu_Border;
// Handle ProgressBar-specific resources
Application.Current.Resources["ProgressBar.Background"] = this.ProgressBar_Background;
// Handle ScrollViewer-specific resources
Application.Current.Resources["ScrollViewer.ScrollBar.Background"] = this.ScrollViewer_ScrollBar_Background;
// Handle TabItem-specific resources
Application.Current.Resources["TabItem.Selected.Background"] = this.TabItem_Selected_Background;
Application.Current.Resources["TabItem.Static.Background"] = this.TabItem_Static_Background;
Application.Current.Resources["TabItem.Static.Border"] = this.TabItem_Static_Border;
// Handle TextBox-specific resources
Application.Current.Resources["TextBox.Static.Background"] = this.TextBox_Static_Background;
}
}
/// <summary>
/// Default light-mode theme
/// </summary>
public class LightModeTheme : Theme
{
public LightModeTheme()
{
// Handle application-wide resources
this.ActiveBorderBrush = null;
this.ControlBrush = null;
this.ControlTextBrush = null;
this.GrayTextBrush = null;
this.WindowBrush = null;
this.WindowTextBrush = null;
// Handle Button-specific resources
this.Button_Disabled_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xF4, 0xF4, 0xF4));
this.Button_MouseOver_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xBE, 0xE6, 0xFD));
this.Button_Pressed_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xC4, 0xE5, 0xF6));
this.Button_Static_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xDD, 0xDD, 0xDD));
// Handle ComboBox-specific resources
this.ComboBox_Disabled_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xF0, 0xF0, 0xF0));
this.ComboBox_Disabled_Editable_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF));
this.ComboBox_Disabled_Editable_Button_Background = Brushes.Transparent;
this.ComboBox_MouseOver_Background = new LinearGradientBrush(
Color.FromArgb(0xFF, 0xEC, 0xF4, 0xFC),
Color.FromArgb(0xFF, 0xDC, 0xEC, 0xFC),
new Point(0, 0),
new Point(0, 1));
this.ComboBox_MouseOver_Editable_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF));
this.ComboBox_MouseOver_Editable_Button_Background = new LinearGradientBrush(
Color.FromArgb(0xFF, 0xEB, 0xF4, 0xFC),
Color.FromArgb(0xFF, 0xDC, 0xEC, 0xFC),
new Point(0, 0),
new Point(0, 1));
this.ComboBox_Pressed_Background = new LinearGradientBrush(
Color.FromArgb(0xFF, 0xDA, 0xEC, 0xFC),
Color.FromArgb(0xFF, 0xC4, 0xE0, 0xFC),
new Point(0, 0),
new Point(0, 1));
this.ComboBox_Pressed_Editable_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF));
this.ComboBox_Pressed_Editable_Button_Background = new LinearGradientBrush(
Color.FromArgb(0xFF, 0xDA, 0xEB, 0xFC),
Color.FromArgb(0xFF, 0xC4, 0xE0, 0xFC),
new Point(0, 0),
new Point(0, 1));
this.ComboBox_Static_Background = new LinearGradientBrush(
Color.FromArgb(0xFF, 0xF0, 0xF0, 0xF0),
Color.FromArgb(0xFF, 0xE5, 0xE5, 0xE5),
new Point(0, 0),
new Point(0, 1));
this.ComboBox_Static_Editable_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF));
this.ComboBox_Static_Editable_Button_Background = Brushes.Transparent;
// Handle CustomMessageBox-specific resources
this.CustomMessageBox_Static_Background = null;
// Handle MenuItem-specific resources
this.MenuItem_SubMenu_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xF0, 0xF0, 0xF0));
this.MenuItem_SubMenu_Border = Brushes.DarkGray;
// Handle ProgressBar-specific resources
this.ProgressBar_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xE6, 0xE6, 0xE6));
// Handle ScrollViewer-specific resources
this.ScrollViewer_ScrollBar_Background = Brushes.LightGray;
// Handle TabItem-specific resources
this.TabItem_Selected_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF));
this.TabItem_Static_Background = new LinearGradientBrush(
Color.FromArgb(0xFF, 0xF0, 0xF0, 0xF0),
Color.FromArgb(0xFF, 0xE5, 0xE5, 0xE5),
new Point(0, 0),
new Point(0, 1));
this.TabItem_Static_Border = Brushes.DarkGray;
// Handle TextBox-specific resources
this.TextBox_Static_Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF));
}
}
/// <summary>
/// Default dark-mode theme
/// </summary>
public class DarkModeTheme : Theme
{
public DarkModeTheme()
{
// Setup needed brushes
var darkModeBrush = new SolidColorBrush { Color = Color.FromArgb(0xff, 0x20, 0x20, 0x20) };
// Handle application-wide resources
this.ActiveBorderBrush = Brushes.Black;
this.ControlBrush = darkModeBrush;
this.ControlTextBrush = Brushes.White;
this.GrayTextBrush = Brushes.DarkGray;
this.WindowBrush = darkModeBrush;
this.WindowTextBrush = Brushes.White;
// Handle Button-specific resources
this.Button_Disabled_Background = darkModeBrush;
this.Button_MouseOver_Background = darkModeBrush;
this.Button_Pressed_Background = darkModeBrush;
this.Button_Static_Background = darkModeBrush;
// Handle ComboBox-specific resources
this.ComboBox_Disabled_Background = darkModeBrush;
this.ComboBox_Disabled_Editable_Background = darkModeBrush;
this.ComboBox_Disabled_Editable_Button_Background = darkModeBrush;
this.ComboBox_MouseOver_Background = darkModeBrush;
this.ComboBox_MouseOver_Editable_Background = darkModeBrush;
this.ComboBox_MouseOver_Editable_Button_Background = darkModeBrush;
this.ComboBox_Pressed_Background = darkModeBrush;
this.ComboBox_Pressed_Editable_Background = darkModeBrush;
this.ComboBox_Pressed_Editable_Button_Background = darkModeBrush;
this.ComboBox_Static_Background = darkModeBrush;
this.ComboBox_Static_Editable_Background = darkModeBrush;
this.ComboBox_Static_Editable_Button_Background = darkModeBrush;
// Handle CustomMessageBox-specific resources
this.CustomMessageBox_Static_Background = darkModeBrush;
// Handle MenuItem-specific resources
this.MenuItem_SubMenu_Background = darkModeBrush;
this.MenuItem_SubMenu_Border = Brushes.DarkGray;
// Handle ProgressBar-specific resources
this.ProgressBar_Background = darkModeBrush;
// Handle ScrollViewer-specific resources
this.ScrollViewer_ScrollBar_Background = darkModeBrush;
// Handle TabItem-specific resources
this.TabItem_Selected_Background = darkModeBrush;
this.TabItem_Static_Background = darkModeBrush;
this.TabItem_Static_Border = Brushes.DarkGray;
// Handle TextBox-specific resources
this.TextBox_Static_Background = darkModeBrush;
}
}
}

View File

@@ -1,4 +1,4 @@
<UserControl x:Class="MPF.UserControls.UserInput"
<UserControl x:Class="MPF.UI.Core.UserControls.UserInput"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

View File

@@ -1,7 +1,7 @@
using System.Windows;
using System.Windows.Controls;
namespace MPF.UserControls
namespace MPF.UI.Core.UserControls
{
/// <summary>
/// Interaction logic for UserInput.xaml
@@ -106,7 +106,6 @@ namespace MPF.UserControls
#endregion
public UserInput()
{
// Set default values

View File

@@ -1,11 +1,13 @@
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using MPF.Core.Data;
using MPF.Core.Utilities;
using MPF.Windows;
using MPF.UI.Core.ComboBoxItems;
using MPF.UI.Core.Windows;
using RedumpLib.Data;
namespace MPF.GUI.ViewModels
namespace MPF.UI.Core.ViewModels
{
public class DiscInformationViewModel
{
@@ -16,6 +18,11 @@ namespace MPF.GUI.ViewModels
/// </summary>
public DiscInformationWindow Parent { get; private set; }
/// <summary>
/// Application-level Options object
/// </summary>
public Options Options { get; private set; }
/// <summary>
/// SubmissionInfo object to fill and save
/// </summary>
@@ -35,11 +42,152 @@ namespace MPF.GUI.ViewModels
/// </summary>
public List<Element<Region>> Regions { get; private set; } = Element<Region>.GenerateElements().ToList();
/// <summary>
/// List of Redump-supported Regions
/// </summary>
private static readonly List<Region> RedumpRegions = new List<Region>
{
Region.Argentina,
Region.Asia,
Region.AsiaEurope,
Region.AsiaUSA,
Region.Australia,
Region.AustraliaGermany,
Region.AustraliaNewZealand,
Region.Austria,
Region.AustriaSwitzerland,
Region.Belarus,
Region.Belgium,
Region.BelgiumNetherlands,
Region.Brazil,
Region.Bulgaria,
Region.Canada,
Region.China,
Region.Croatia,
Region.Czechia,
Region.Denmark,
Region.Estonia,
Region.Europe,
Region.EuropeAsia,
Region.EuropeAustralia,
Region.EuropeCanada,
Region.EuropeGermany,
Region.Export,
Region.Finland,
Region.France,
Region.FranceSpain,
Region.Germany,
Region.GreaterChina,
Region.Greece,
Region.Hungary,
Region.Iceland,
Region.India,
Region.Ireland,
Region.Israel,
Region.Italy,
Region.Japan,
Region.JapanAsia,
Region.JapanEurope,
Region.JapanKorea,
Region.JapanUSA,
Region.SouthKorea,
Region.LatinAmerica,
Region.Lithuania,
Region.Netherlands,
Region.NewZealand,
Region.Norway,
Region.Poland,
Region.Portugal,
Region.Romania,
Region.RussianFederation,
Region.Scandinavia,
Region.Serbia,
Region.Singapore,
Region.Slovakia,
Region.SouthAfrica,
Region.Spain,
Region.SpainPortugal,
Region.Sweden,
Region.Switzerland,
Region.Taiwan,
Region.Thailand,
Region.Turkey,
Region.UnitedArabEmirates,
Region.UnitedKingdom,
Region.UKAustralia,
Region.Ukraine,
Region.UnitedStatesOfAmerica,
Region.USAAsia,
Region.USAAustralia,
Region.USABrazil,
Region.USACanada,
Region.USAEurope,
Region.USAGermany,
Region.USAJapan,
Region.USAKorea,
Region.World,
};
/// <summary>
/// List of available languages
/// </summary>
public List<Element<Language>> Languages { get; private set; } = Element<Language>.GenerateElements().ToList();
/// <summary>
/// List of Redump-supported Languages
/// </summary>
private static readonly List<Language> RedumpLanguages = new List<Language>
{
Language.Afrikaans,
Language.Albanian,
Language.Arabic,
Language.Armenian,
Language.Basque,
Language.Belarusian,
Language.Bulgarian,
Language.Catalan,
Language.Chinese,
Language.Croatian,
Language.Czech,
Language.Danish,
Language.Dutch,
Language.English,
Language.Estonian,
Language.Finnish,
Language.French,
Language.Gaelic,
Language.German,
Language.Greek,
Language.Hebrew,
Language.Hindi,
Language.Hungarian,
Language.Icelandic,
Language.Indonesian,
Language.Italian,
Language.Japanese,
Language.Korean,
Language.Latin,
Language.Latvian,
Language.Lithuanian,
Language.Macedonian,
Language.Norwegian,
Language.Polish,
Language.Portuguese,
Language.Panjabi,
Language.Romanian,
Language.Russian,
Language.Serbian,
Language.Slovak,
Language.Slovenian,
Language.Spanish,
Language.Swedish,
Language.Tamil,
Language.Thai,
Language.Turkish,
Language.Ukrainian,
Language.Vietnamese,
};
/// <summary>
/// List of available languages
/// </summary>
@@ -50,11 +198,19 @@ namespace MPF.GUI.ViewModels
/// <summary>
/// Constructor
/// </summary>
public DiscInformationViewModel(DiscInformationWindow parent, SubmissionInfo submissionInfo)
public DiscInformationViewModel(DiscInformationWindow parent, Options options, SubmissionInfo submissionInfo)
{
Parent = parent;
Options = options;
SubmissionInfo = submissionInfo.Clone() as SubmissionInfo ?? new SubmissionInfo();
// Limit lists, if necessary
if (this.Options.EnableRedumpCompatibility)
{
SetRedumpRegions();
SetRedumpLanguages();
}
// Add handlers
Parent.AcceptButton.Click += OnAcceptClick;
Parent.CancelButton.Click += OnCancelClick;
@@ -74,15 +230,19 @@ namespace MPF.GUI.ViewModels
{
// Additional Information
Parent.CommentsTextBox.Tab = true;
// Contents
Parent.GeneralContent.Tab = true;
Parent.ExtrasTextBox.Tab = true;
Parent.GameFootageTextBox.Tab = true;
Parent.GamesTextBox.Tab = true;
Parent.NetYarozeGamesTextBox.Tab = true;
Parent.PatchesTextBox.Tab = true;
Parent.PlayableDemosTextBox.Tab = true;
Parent.RollingDemosTextBox.Tab = true;
Parent.SavegamesTextBox.Tab = true;
Parent.TechDemosTextBox.Tab = true;
Parent.GameFootageTextBox.Tab = true;
Parent.VideosTextBox.Tab = true;
Parent.PatchesTextBox.Tab = true;
Parent.SavegamesTextBox.Tab = true;
Parent.ExtrasTextBox.Tab = true;
// L0
Parent.L0MasteringRing.Tab = true;
@@ -114,14 +274,22 @@ namespace MPF.GUI.ViewModels
/// </summary>
private void HideReadOnlyFields()
{
if (SubmissionInfo?.MatchedIDs == null)
Parent.MatchedIDs.Visibility = Visibility.Collapsed;
if (SubmissionInfo?.FullyMatchedID == null)
Parent.FullyMatchedID.Visibility = Visibility.Collapsed;
else
Parent.MatchedIDs.Text = string.Join(", ", SubmissionInfo.MatchedIDs);
Parent.FullyMatchedID.Text = SubmissionInfo.FullyMatchedID.ToString();
if (SubmissionInfo?.PartiallyMatchedIDs == null)
Parent.PartiallyMatchedIDs.Visibility = Visibility.Collapsed;
else
Parent.PartiallyMatchedIDs.Text = string.Join(", ", SubmissionInfo.PartiallyMatchedIDs);
if (SubmissionInfo?.CopyProtection?.AntiModchip == null)
Parent.AntiModchip.Visibility = Visibility.Collapsed;
else
Parent.AntiModchip.Text = SubmissionInfo.CopyProtection.AntiModchip.LongName();
if (SubmissionInfo?.TracksAndWriteOffsets?.OtherWriteOffsets == null)
Parent.DiscOffset.Visibility = Visibility.Collapsed;
else
Parent.DiscOffset.Text = SubmissionInfo.TracksAndWriteOffsets.OtherWriteOffsets;
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.DMIHash) != true)
Parent.DMIHash.Visibility = Visibility.Collapsed;
if (string.IsNullOrWhiteSpace(SubmissionInfo?.CommonDiscInfo?.ErrorsCount))
@@ -132,8 +300,12 @@ namespace MPF.GUI.ViewModels
Parent.EDC.Visibility = Visibility.Collapsed;
else
Parent.EDC.Text = SubmissionInfo.EDC.EDC.LongName();
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.Filename) != true)
Parent.Filename.Visibility = Visibility.Collapsed;
if (string.IsNullOrWhiteSpace(SubmissionInfo?.Extras?.Header))
Parent.Header.Visibility = Visibility.Collapsed;
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.InternalName) != true)
Parent.InternalName.Visibility = Visibility.Collapsed;
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.InternalSerialName) != true)
Parent.InternalSerialName.Visibility = Visibility.Collapsed;
if (SubmissionInfo?.CopyProtection?.LibCrypt == null)
@@ -146,10 +318,12 @@ namespace MPF.GUI.ViewModels
Parent.PFIHash.Visibility = Visibility.Collapsed;
if (string.IsNullOrWhiteSpace(SubmissionInfo?.Extras?.PIC))
Parent.PIC.Visibility = Visibility.Collapsed;
if (string.IsNullOrWhiteSpace(SubmissionInfo?.CopyProtection?.Protection))
Parent.Protection.Visibility = Visibility.Collapsed;
if (string.IsNullOrWhiteSpace(SubmissionInfo?.Extras?.PVD))
Parent.PVD.Visibility = Visibility.Collapsed;
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.Multisession) != true)
Parent.Multisession.Visibility = Visibility.Collapsed;
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.RingNonZeroDataStart) != true)
Parent.RingNonZeroDataStart.Visibility = Visibility.Collapsed;
if (string.IsNullOrWhiteSpace(SubmissionInfo?.CopyProtection?.SecuROMData))
Parent.SecuROMData.Visibility = Visibility.Collapsed;
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.SSHash) != true)
@@ -158,6 +332,8 @@ namespace MPF.GUI.ViewModels
Parent.SecuritySectorRanges.Visibility = Visibility.Collapsed;
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.SSVersion) != true)
Parent.SSVersion.Visibility = Visibility.Collapsed;
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.UniversalHash) != true)
Parent.UniversalHash.Visibility = Visibility.Collapsed;
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.VolumeLabel) != true)
Parent.VolumeLabel.Visibility = Visibility.Collapsed;
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.XeMID) != true)
@@ -172,7 +348,7 @@ namespace MPF.GUI.ViewModels
private void ManipulateFields()
{
// Enable tabs in all fields, if required
if (App.Options.EnableTabsInInputFields)
if (this.Options.EnableTabsInInputFields)
EnableTabsInInputFields();
// Hide read-only fields that don't have values set
@@ -283,14 +459,24 @@ namespace MPF.GUI.ViewModels
// Read-Only Information
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.DMIHash))
Parent.DMIHash.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.DMIHash];
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.Filename))
Parent.Filename.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.Filename];
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.InternalName))
Parent.InternalName.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalName];
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.InternalSerialName))
Parent.InternalSerialName.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName];
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.Multisession))
Parent.Multisession.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.Multisession];
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.PFIHash))
Parent.PFIHash.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash];
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.RingNonZeroDataStart))
Parent.RingNonZeroDataStart.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.RingNonZeroDataStart];
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.SSHash))
Parent.SSHash.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash];
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.SSVersion))
Parent.SSVersion.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSVersion];
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.UniversalHash))
Parent.UniversalHash.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.UniversalHash];
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.VolumeLabel))
Parent.VolumeLabel.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.VolumeLabel];
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.XeMID))
@@ -398,10 +584,15 @@ namespace MPF.GUI.ViewModels
// Read-Only Information
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.DMIHash] = Parent.DMIHash.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.Filename] = Parent.Filename.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalName] = Parent.InternalName.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = Parent.InternalSerialName.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.Multisession] = Parent.Multisession.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash] = Parent.PFIHash.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.RingNonZeroDataStart] = Parent.RingNonZeroDataStart.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash] = Parent.SSHash.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSVersion] = Parent.SSVersion.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.UniversalHash] = Parent.UniversalHash.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.VolumeLabel] = Parent.VolumeLabel.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.XeMID] = Parent.XeMID.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.XMID] = Parent.XMID.Text;
@@ -431,6 +622,22 @@ namespace MPF.GUI.ViewModels
#endregion
}
/// <summary>
/// Repopulate the list of Languages based on Redump support
/// </summary>
private void SetRedumpLanguages()
{
this.Languages = RedumpLanguages.Select(l => new Element<Language>(l)).ToList();
}
/// <summary>
/// Repopulate the list of Regions based on Redump support
/// </summary>
private void SetRedumpRegions()
{
this.Regions = RedumpRegions.Select(r => new Element<Region>(r)).ToList();
}
/// <summary>
/// Update visible fields and sections based on the media type
/// </summary>
@@ -462,8 +669,13 @@ namespace MPF.GUI.ViewModels
case DiscType.DVD5:
case DiscType.DVD9:
case DiscType.HDDVDSL:
case DiscType.HDDVDDL:
case DiscType.BD25:
case DiscType.BD33:
case DiscType.BD50:
case DiscType.BD66:
case DiscType.BD100:
case DiscType.BD128:
case DiscType.NintendoGameCubeGameDisc:
case DiscType.NintendoWiiOpticalDiscSL:
case DiscType.NintendoWiiOpticalDiscDL:

View File

@@ -1,10 +1,10 @@
<windows:WindowBase x:Class="MPF.Windows.DiscInformationWindow"
<windows:WindowBase x:Class="MPF.UI.Core.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:controls="clr-namespace:MPF.UserControls"
xmlns:windows="clr-namespace:MPF.Windows"
xmlns:controls="clr-namespace:MPF.UI.Core.UserControls"
xmlns:windows="clr-namespace:MPF.UI.Core.Windows"
mc:Ignorable="d"
Title="Disc Information" Width="515" WindowStyle="None"
WindowStartupLocation="CenterOwner" ResizeMode="CanMinimize" SizeToContent="Height"
@@ -165,6 +165,9 @@
Text="{Binding SubmissionInfo.CommonDiscInfo.Comments, Mode=TwoWay}" TextHeight="50"
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top" />
<controls:UserInput x:Name="GenreTextBox" Label="Genre"/>
<controls:UserInput x:Name="ProtectionTextBox" Label="Protection" ToolTip="CAUTION: Only edit if you know what you are doing!"
Text="{Binding SubmissionInfo.CopyProtection.Protection, Mode=TwoWay}" TextHeight="75" TextWrapping="Wrap"
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.75*" />
@@ -335,18 +338,26 @@
<TabItem Header="Read-Only Info" Style="{DynamicResource CustomTabItemStyle}">
<ScrollViewer CanContentScroll="False" VerticalScrollBarVisibility="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MaxHeight="500">
<StackPanel Orientation="Vertical">
<controls:UserInput x:Name="MatchedIDs" Label="Matched ID(s)" IsReadOnly="True"/>
<controls:UserInput x:Name="FullyMatchedID" Label="Fully Matched ID" IsReadOnly="True"/>
<controls:UserInput x:Name="PartiallyMatchedIDs" Label="Partially Matched ID(s)" IsReadOnly="True"/>
<controls:UserInput x:Name="AntiModchip" Label="Anti-Modchip" IsReadOnly="True"/>
<controls:UserInput x:Name="DiscOffset" Label="Disc Offset" IsReadOnly="True"/>
<controls:UserInput x:Name="DMIHash" Label="DMI Hash" IsReadOnly="True"/>
<controls:UserInput x:Name="EDC" Label="EDC" IsReadOnly="True"/>
<controls:UserInput x:Name="ErrorsCount" Label="Error(s) Count" IsReadOnly="True"
Text="{Binding SubmissionInfo.CommonDiscInfo.ErrorsCount, Mode=TwoWay}"/>
<controls:UserInput x:Name="EXEDateBuildDate" Label="EXE/Build Date" IsReadOnly="True"
Text="{Binding SubmissionInfo.CommonDiscInfo.EXEDateBuildDate, Mode=TwoWay}"/>
<controls:UserInput x:Name="Filename" Label="Filename" IsReadOnly="True"
TextHeight="75" TextWrapping="NoWrap"
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
<controls:UserInput x:Name="Header" Label="Header" IsReadOnly="True"
Text="{Binding SubmissionInfo.Extras.Header, Mode=TwoWay}" TextHeight="75" TextWrapping="NoWrap"
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
<controls:UserInput x:Name="InternalName" Label="Internal Names" IsReadOnly="True"/>
<controls:UserInput x:Name="InternalSerialName" Label="Internal Serial" IsReadOnly="True"/>
<controls:UserInput x:Name="Multisession" Label="Multisession" IsReadOnly="True" TextHeight="75" TextWrapping="NoWrap"
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
<controls:UserInput x:Name="LibCrypt" Label="LibCrypt" IsReadOnly="True"/>
<controls:UserInput x:Name="LibCryptData" Label="LibCrypt Data" IsReadOnly="True"
Text="{Binding SubmissionInfo.CopyProtection.LibCryptData, Mode=TwoWay}" TextHeight="75" TextWrapping="NoWrap"
@@ -355,12 +366,10 @@
<controls:UserInput x:Name="PIC" Label="PIC" IsReadOnly="True"
Text="{Binding SubmissionInfo.Extras.PIC, Mode=TwoWay}" TextHeight="75" TextWrapping="NoWrap"
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
<controls:UserInput x:Name="Protection" Label="Protection" IsReadOnly="True"
Text="{Binding SubmissionInfo.CopyProtection.Protection, Mode=TwoWay}" TextHeight="75" TextWrapping="Wrap"
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
<controls:UserInput x:Name="PVD" Label="PVD" IsReadOnly="True"
Text="{Binding SubmissionInfo.Extras.PVD, Mode=TwoWay}" TextHeight="75" TextWrapping="NoWrap"
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
<controls:UserInput x:Name="RingNonZeroDataStart" Label="Ring Non-Zero Data Start" IsReadOnly="True"/>
<controls:UserInput x:Name="SecuROMData" Label="SecuROM Data" IsReadOnly="True"
Text="{Binding SubmissionInfo.CopyProtection.SecuROMData, Mode=TwoWay}" TextHeight="75" TextWrapping="NoWrap"
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
@@ -369,6 +378,7 @@
Text="{Binding SubmissionInfo.Extras.SecuritySectorRanges, Mode=TwoWay}" TextHeight="75" TextWrapping="NoWrap"
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
<controls:UserInput x:Name="SSVersion" Label="Security Sector Version" IsReadOnly="True"/>
<controls:UserInput x:Name="UniversalHash" Label="Universal Hash (SHA-1)" IsReadOnly="True"/>
<controls:UserInput x:Name="VolumeLabel" Label="Volume Label" IsReadOnly="True"/>
<controls:UserInput x:Name="XeMID" Label="XeMID" IsReadOnly="True"/>
<controls:UserInput x:Name="XMID" Label="XMID" IsReadOnly="True"/>

View File

@@ -1,7 +1,8 @@
using MPF.GUI.ViewModels;
using MPF.Core.Data;
using MPF.UI.Core.ViewModels;
using RedumpLib.Data;
namespace MPF.Windows
namespace MPF.UI.Core.Windows
{
/// <summary>
/// Interaction logic for DiscInformationWindow.xaml
@@ -16,10 +17,10 @@ namespace MPF.Windows
/// <summary>
/// Constructor
/// </summary>
public DiscInformationWindow(SubmissionInfo submissionInfo)
public DiscInformationWindow(Options options, SubmissionInfo submissionInfo)
{
InitializeComponent();
DataContext = new DiscInformationViewModel(this, submissionInfo);
DataContext = new DiscInformationViewModel(this, options, submissionInfo);
}
}
}

View File

@@ -1,11 +1,10 @@
<windows:WindowBase x:Class="MPF.Windows.RingCodeGuideWindow"
<windows:WindowBase x:Class="MPF.UI.Core.Windows.RingCodeGuideWindow"
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:MPF"
xmlns:controls="clr-namespace:MPF.UserControls"
xmlns:windows="clr-namespace:MPF.Windows"
xmlns:controls="clr-namespace:MPF.UI.Core.UserControls"
xmlns:windows="clr-namespace:MPF.UI.Core.Windows"
mc:Ignorable="d"
Title="Ring Code Guide" Width="500" WindowStyle="None"
WindowStartupLocation="CenterOwner" ResizeMode="CanMinimize" SizeToContent="Height"
@@ -81,12 +80,12 @@
<RowDefinition/>
</Grid.RowDefinitions>
<Image Grid.Row="0" Source="/Images/ring-code-guide-1-layer.png"
<Image Grid.Row="0" Source="../Images/ring-code-guide-1-layer.png"
HorizontalAlignment="Center" Stretch="Fill" Width="500" Height="500"
RenderOptions.BitmapScalingMode="HighQuality" />
<Label Grid.Row="1">
<Label.Content>
<TextBlock><Bold Foreground="Red">1. Mastering Ring:</Bold> Sony DADC&lt;tab&gt;A0100368905-0101&lt;tab&gt;15</TextBlock>
<TextBlock><Bold Foreground="Red">1. Mastering Ring:</Bold> Sony DADC&lt;tab&gt;A0100368905-0101&lt;tab&gt;13</TextBlock>
</Label.Content>
</Label>
<Label Grid.Row="2">
@@ -122,7 +121,7 @@
<RowDefinition/>
</Grid.RowDefinitions>
<Image Grid.Row="0" Source="/Images/ring-code-guide-2-layer.png"
<Image Grid.Row="0" Source="../Images/ring-code-guide-2-layer.png"
HorizontalAlignment="Center" Stretch="Fill" Width="475" Height="500"
RenderOptions.BitmapScalingMode="HighQuality" />
<Label Grid.Row="1">
@@ -132,7 +131,7 @@
</Label>
<Label Grid.Row="2">
<Label.Content>
<TextBlock><Bold Foreground="Green">2. Inner Mastering Ring:</Bold> IM01501A-L0&lt;tab&gt;03 +&lt;tab&gt;+</TextBlock>
<TextBlock><Bold Foreground="Green">2. Inner Mastering Ring:</Bold> IM01501A-L0&lt;tab&gt;01 +&lt;tab&gt;+</TextBlock>
</Label.Content>
</Label>
<Label Grid.Row="3">

View File

@@ -1,4 +1,4 @@
namespace MPF.Windows
namespace MPF.UI.Core.Windows
{
/// <summary>
/// Interaction logic for RingCodeGuideWindow.xaml

View File

@@ -1,7 +1,7 @@
using System.Windows;
using System.Windows.Input;
namespace MPF.Windows
namespace MPF.UI.Core.Windows
{
public class WindowBase : Window
{

33
MPF.sln
View File

@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28803.156
# Visual Studio Version 17
VisualStudioVersion = 17.1.32407.343
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MPF", "MPF\MPF.csproj", "{7B1B75EB-8940-466F-BD51-76471A57F9BE}"
EndProject
@@ -15,19 +15,26 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
appveyor.yml = appveyor.yml
CHANGELIST.md = CHANGELIST.md
.github\ISSUE_TEMPLATE\feature-request.md = .github\ISSUE_TEMPLATE\feature-request.md
.github\ISSUE_TEMPLATE\informational.md = .github\ISSUE_TEMPLATE\informational.md
.github\ISSUE_TEMPLATE\issue-report.md = .github\ISSUE_TEMPLATE\issue-report.md
publish-nix.sh = publish-nix.sh
README.md = README.md
publish-win.bat = publish-win.bat
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RedumpLib", "RedumpLib\RedumpLib.csproj", "{13574913-A426-4644-9955-F49AD0876E5F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MPF.CueSheets", "MPF.CueSheets\MPF.CueSheets.csproj", "{F2C12798-DF53-4D4C-A55B-F5A77F29D6B1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CICMMetadataEditor", "CICMMetadata\CICMMetadataEditor\CICMMetadataEditor\CICMMetadataEditor.csproj", "{E4271454-6217-4500-BC36-F8856AC7AD6B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MPF.Core", "MPF.Core\MPF.Core.csproj", "{70B1265D-FE49-472A-A83D-0B462152D37A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MPF.Modules", "MPF.Modules\MPF.Modules.csproj", "{8A4254BD-552F-4238-B8EB-D59AACD768B9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MPF.UI.Core", "MPF.UI.Core\MPF.UI.Core.csproj", "{EA3768DB-694A-4653-82E4-9FF71B8963F3}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MPF", "MPF", "{4160167D-681D-480B-ABC6-06AC869E5769}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -58,10 +65,6 @@ Global
{F2C12798-DF53-4D4C-A55B-F5A77F29D6B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F2C12798-DF53-4D4C-A55B-F5A77F29D6B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F2C12798-DF53-4D4C-A55B-F5A77F29D6B1}.Release|Any CPU.Build.0 = Release|Any CPU
{E4271454-6217-4500-BC36-F8856AC7AD6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E4271454-6217-4500-BC36-F8856AC7AD6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E4271454-6217-4500-BC36-F8856AC7AD6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E4271454-6217-4500-BC36-F8856AC7AD6B}.Release|Any CPU.Build.0 = Release|Any CPU
{70B1265D-FE49-472A-A83D-0B462152D37A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{70B1265D-FE49-472A-A83D-0B462152D37A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{70B1265D-FE49-472A-A83D-0B462152D37A}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -70,10 +73,24 @@ Global
{8A4254BD-552F-4238-B8EB-D59AACD768B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8A4254BD-552F-4238-B8EB-D59AACD768B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8A4254BD-552F-4238-B8EB-D59AACD768B9}.Release|Any CPU.Build.0 = Release|Any CPU
{EA3768DB-694A-4653-82E4-9FF71B8963F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EA3768DB-694A-4653-82E4-9FF71B8963F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EA3768DB-694A-4653-82E4-9FF71B8963F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EA3768DB-694A-4653-82E4-9FF71B8963F3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{7B1B75EB-8940-466F-BD51-76471A57F9BE} = {4160167D-681D-480B-ABC6-06AC869E5769}
{7CC064D2-38AB-4A05-8519-28660DE4562A} = {4160167D-681D-480B-ABC6-06AC869E5769}
{51AB0928-13F9-44BF-A407-B6957A43A056} = {4160167D-681D-480B-ABC6-06AC869E5769}
{8CFDE289-E171-4D49-A40D-5293265C1253} = {4160167D-681D-480B-ABC6-06AC869E5769}
{F2C12798-DF53-4D4C-A55B-F5A77F29D6B1} = {4160167D-681D-480B-ABC6-06AC869E5769}
{70B1265D-FE49-472A-A83D-0B462152D37A} = {4160167D-681D-480B-ABC6-06AC869E5769}
{8A4254BD-552F-4238-B8EB-D59AACD768B9} = {4160167D-681D-480B-ABC6-06AC869E5769}
{EA3768DB-694A-4653-82E4-9FF71B8963F3} = {4160167D-681D-480B-ABC6-06AC869E5769}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {73C62E6A-6584-4D93-83B5-ECB1FBDB469B}
EndGlobalSection

View File

@@ -1,6 +1,7 @@
using System.Windows;
using MPF.Core.Data;
using MPF.GUI.ViewModels;
using MPF.Core.Utilities;
using MPF.UI.ViewModels;
using MPF.Windows;
namespace MPF

View File

@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MPF.Core.Converters;
using MPF.Core.Utilities;
using MPF.UI.Core.ComboBoxItems;
using RedumpLib.Data;
namespace MPF

View File

@@ -13,11 +13,13 @@ namespace MPF
// Private lists of known drive speed ranges
private static IReadOnlyList<int> CD { get; } = new List<int> { 1, 2, 3, 4, 6, 8, 12, 16, 20, 24, 32, 40, 44, 48, 52, 56, 72 };
private static IReadOnlyList<int> DVD { get; } = CD.Where(s => s <= 24).ToList();
private static IReadOnlyList<int> HDDVD { get; } = CD.Where(s => s <= 24).ToList();
private static IReadOnlyList<int> BD { get; } = CD.Where(s => s <= 16).ToList();
// 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 SpeedsForHDDVDAsCollection { get; } = GetDoubleCollectionFromIntList(HDDVD);
public static DoubleCollection SpeedsForBDAsCollection { get; } = GetDoubleCollectionFromIntList(BD);
private static DoubleCollection GetDoubleCollectionFromIntList(IReadOnlyList<int> list)
=> new DoubleCollection(list.Select(i => Convert.ToDouble(i)).ToList());

View File

@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFrameworks>net48;netcoreapp3.1;net5.0-windows</TargetFrameworks>
<PlatformTarget>x86</PlatformTarget>
<TargetFrameworks>net48;net6.0-windows</TargetFrameworks>
<RuntimeIdentifiers>win7-x64;win8-x64;win81-x64;win10-x64</RuntimeIdentifiers>
<OutputType>WinExe</OutputType>
<UseWindowsForms>true</UseWindowsForms>
<UseWPF>true</UseWPF>
@@ -11,9 +11,9 @@
<AssemblyName>MPF</AssemblyName>
<Description>Frontend for various dumping programs</Description>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2021</Copyright>
<Copyright>Copyright (c)2019-2023</Copyright>
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
<Version>2.3</Version>
<Version>2.6.2</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<FileVersion>$(Version)</FileVersion>
<IncludeSource>true</IncludeSource>
@@ -27,11 +27,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="1.8.0" GeneratePathProperty="true">
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="2.8.0" GeneratePathProperty="true">
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0-rc.1.21451.13" />
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.1">
<PackageReference Include="System.Configuration.ConfigurationManager" Version="7.0.0" />
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
@@ -41,22 +41,14 @@
<Content Include="$(PkgBurnOutSharp)\content\**" PackagePath="contentFiles\any\any;content" CopyToOutputDirectory="Always" PackageCopyToOutput="true" />
</ItemGroup>
<ItemGroup>
<None Remove="Images\ring-code-guide-2-layer.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Images\Icon.ico" />
<Resource Include="Images\ring-code-guide-2-layer.png" />
<Resource Include="Images\ring-code-guide-1-layer.png" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj">
<Project>{51ab0928-13f9-44bf-a407-b6957a43a056}</Project>
<Name>MPF.Library</Name>
</ProjectReference>
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj" />
<ProjectReference Include="..\MPF.UI.Core\MPF.UI.Core.csproj" />
<ProjectReference Include="..\RedumpLib\RedumpLib.csproj" />
</ItemGroup>

View File

@@ -1,44 +0,0 @@
using System.Collections.Generic;
using System.Configuration;
using MPF.Core.Data;
namespace MPF
{
public static class OptionsLoader
{
/// <summary>
/// Load the current set of options from the application configuration
/// </summary>
public static Options LoadFromConfig()
{
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var settings = configFile.AppSettings.Settings;
var dict = new Dictionary<string, string>();
foreach (string key in settings.AllKeys)
{
dict[key] = settings[key]?.Value ?? string.Empty;
}
return new Options(dict);
}
/// <summary>
/// Save the current set of options to the application configuration
/// </summary>
public static void SaveToConfig(Options options)
{
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
// Loop through all settings in Options and save them, overwriting existing settings
foreach (var kvp in options)
{
configFile.AppSettings.Settings.Remove(kvp.Key);
configFile.AppSettings.Settings.Add(kvp.Key, kvp.Value);
}
configFile.Save(ConfigurationSaveMode.Modified);
}
}
}

View File

@@ -1,5 +1,5 @@
using System.Windows.Controls;
using MPF.GUI.ViewModels;
using MPF.UI.ViewModels;
namespace MPF.UserControls
{

View File

@@ -10,7 +10,7 @@ using System.Windows.Media;
using MPF.Core.Data;
using MPF.UserControls;
namespace MPF.GUI.ViewModels
namespace MPF.UI.ViewModels
{
public class LogViewModel
{

File diff suppressed because it is too large Load Diff

View File

@@ -2,14 +2,16 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using MPF.Core.Data;
using MPF.UI.Core.ComboBoxItems;
using MPF.Windows;
using RedumpLib.Web;
using WPFCustomMessageBox;
namespace MPF.GUI.ViewModels
namespace MPF.UI.ViewModels
{
public class OptionsViewModel
{
@@ -103,7 +105,7 @@ namespace MPF.GUI.ViewModels
/// </summary>
private static List<Element<InternalProgram>> PopulateInternalPrograms()
{
var internalPrograms = new List<InternalProgram> { InternalProgram.DiscImageCreator, InternalProgram.Aaru, InternalProgram.DD };
var internalPrograms = new List<InternalProgram> { InternalProgram.DiscImageCreator, InternalProgram.Aaru, InternalProgram.Redumper, InternalProgram.DD };
return internalPrograms.Select(ip => new Element<InternalProgram>(ip)).ToList();
}
@@ -186,18 +188,25 @@ namespace MPF.GUI.ViewModels
/// <summary>
/// Test Redump login credentials
/// </summary>
private void TestRedumpLogin()
#if NET48 || NETSTANDARD2_1
private bool? TestRedumpLogin()
#else
private async Task<bool?> TestRedumpLogin()
#endif
{
using (RedumpWebClient wc = new RedumpWebClient())
{
bool? loggedIn = wc.Login(Parent.RedumpUsernameTextBox.Text, Parent.RedumpPasswordBox.Password);
if (loggedIn == true)
CustomMessageBox.Show(Parent, "Redump login credentials accepted!", "Success", MessageBoxButton.OK, MessageBoxImage.Information);
else if (loggedIn == false)
CustomMessageBox.Show(Parent, "Redump login credentials denied!", "Failure", MessageBoxButton.OK, MessageBoxImage.Error);
else
CustomMessageBox.Show(Parent, "Error validating credentials!", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
#if NET48 || NETSTANDARD2_1
(bool? success, string message) = RedumpWebClient.ValidateCredentials(Parent.RedumpUsernameTextBox.Text, Parent.RedumpPasswordBox.Password);
#else
(bool? success, string message) = await RedumpHttpClient.ValidateCredentials(Parent.RedumpUsernameTextBox.Text, Parent.RedumpPasswordBox.Password);
#endif
if (success == true)
CustomMessageBox.Show(Parent, message, "Success", MessageBoxButton.OK, MessageBoxImage.Information);
else if (success == false)
CustomMessageBox.Show(Parent, message, "Failure", MessageBoxButton.OK, MessageBoxImage.Error);
else
CustomMessageBox.Show(Parent, message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return success;
}
#endregion
@@ -256,8 +265,13 @@ namespace MPF.GUI.ViewModels
/// <summary>
/// Test Redump credentials for validity
/// </summary>
#if NET48 || NETSTANDARD2_1
private void OnRedumpTestClick(object sender, EventArgs e) =>
TestRedumpLogin();
#else
private async void OnRedumpTestClick(object sender, EventArgs e) =>
_ = await TestRedumpLogin();
#endif
#endregion
}

View File

@@ -1,15 +1,15 @@
<windows:WindowBase x:Class="MPF.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:controls="clr-namespace:MPF.UserControls"
xmlns:viewModels="clr-namespace:MPF.GUI.ViewModels"
xmlns:windows="clr-namespace:MPF.Windows"
mc:Ignorable="d"
Title="Media Preservation Frontend" Width="600" WindowStyle="None"
WindowStartupLocation="CenterScreen" ResizeMode="CanMinimize" SizeToContent="Height"
BorderBrush="DarkGray" BorderThickness="2">
<coreWindows:WindowBase x:Class="MPF.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:controls="clr-namespace:MPF.UserControls"
xmlns:coreWindows="clr-namespace:MPF.UI.Core.Windows;assembly=MPF.UI.Core"
xmlns:viewModels="clr-namespace:MPF.UI.ViewModels"
mc:Ignorable="d"
Title="Media Preservation Frontend" Width="600" WindowStyle="None"
WindowStartupLocation="CenterScreen" ResizeMode="CanMinimize" SizeToContent="Height"
BorderBrush="DarkGray" BorderThickness="2">
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="0" ResizeBorderThickness="0" />
@@ -24,7 +24,7 @@
<Grid Margin="0,2,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="115"/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
@@ -136,16 +136,13 @@
</ComboBox>
<ComboBox x:Name="MediaTypeComboBox" Grid.Row="0" Grid.Column="1" Height="22" Width="140" HorizontalAlignment="Right" Style="{DynamicResource CustomComboBoxStyle}" />
<Label x:Name="OutputFilenameLabel" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Content="Output Filename"/>
<TextBox x:Name="OutputFilenameTextBox" Grid.Row="1" Grid.Column="1" Height="22" VerticalContentAlignment="Center" />
<Label x:Name="OutputDirectoryLabel" Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Content="Output Directory"/>
<TextBox x:Name="OutputDirectoryTextBox" Grid.Row="2" Grid.Column="1" Height="22" Width="345" HorizontalAlignment="Left" VerticalContentAlignment="Center" />
<Button x:Name="OutputDirectoryBrowseButton" Grid.Row="2" Grid.Column="1" Height="22" Width="50" HorizontalAlignment="Right" Content="Browse"
<Label x:Name="OutputPathLabel" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Content="Output Path"/>
<TextBox x:Name="OutputPathTextBox" Grid.Row="1" Grid.Column="1" Height="22" Width="345" HorizontalAlignment="Left" VerticalContentAlignment="Center" />
<Button x:Name="OutputPathBrowseButton" Grid.Row="1" Grid.Column="1" Height="22" Width="50" HorizontalAlignment="Right" Content="Browse"
Style="{DynamicResource CustomButtonStyle}"/>
<Label x:Name="DriveLetterLabel" Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" Content="Drive Letter"/>
<ComboBox x:Name="DriveLetterComboBox" Grid.Row="3" Grid.Column="1" Height="22" Width="60" HorizontalAlignment="Left" Style="{DynamicResource CustomComboBoxStyle}">
<Label x:Name="DriveLetterLabel" Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Content="Drive Letter"/>
<ComboBox x:Name="DriveLetterComboBox" Grid.Row="2" Grid.Column="1" Height="22" Width="60" HorizontalAlignment="Left" Style="{DynamicResource CustomComboBoxStyle}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Letter}" />
@@ -153,9 +150,12 @@
</ComboBox.ItemTemplate>
</ComboBox>
<Label x:Name="DriveSpeedLabel" Grid.Row="4" Grid.Column="0" VerticalAlignment="Center" Content="Drive Speed"/>
<ComboBox x:Name="DriveSpeedComboBox" Grid.Row="4" Grid.Column="1" Height="22" Width="60" HorizontalAlignment="Left" Style="{DynamicResource CustomComboBoxStyle}" />
<Label x:Name="DriveSpeedLabel" Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" Content="Drive Speed"/>
<ComboBox x:Name="DriveSpeedComboBox" Grid.Row="3" Grid.Column="1" Height="22" Width="60" HorizontalAlignment="Left" Style="{DynamicResource CustomComboBoxStyle}" />
<Label x:Name="DumpingProgramLabel" Grid.Row="4" Grid.Column="0" VerticalAlignment="Center" Content="Dumping Program"/>
<ComboBox x:Name="DumpingProgramComboBox" Grid.Row="4" Grid.Column="1" Height="22" Width="250" HorizontalAlignment="Left" Style="{DynamicResource CustomComboBoxStyle}" />
<Label x:Name="ParametersLabel" Grid.Row="5" Grid.Column="0" VerticalAlignment="Center" Content="Parameters"/>
<TextBox x:Name="ParametersTextBox" Grid.Row="5" Grid.Column="1" Height="22" Width="370" HorizontalAlignment="Left" IsEnabled="False" VerticalContentAlignment="Center" />
<CheckBox x:Name="EnableParametersCheckBox" Grid.Row="5" Grid.Column="1" Height="22" HorizontalAlignment="Right" IsChecked="False" />
@@ -163,11 +163,13 @@
</GroupBox>
<GroupBox Margin="5,5,5,5" HorizontalAlignment="Stretch" Header="Controls">
<UniformGrid Columns="3" Margin="5,5,5,5">
<UniformGrid Columns="4" Margin="5,5,5,5">
<Button x:Name="StartStopButton" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" IsDefault="True" Content="Start Dumping"
IsEnabled="False" Style="{DynamicResource CustomButtonStyle}" />
<Button x:Name="MediaScanButton" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Scan for discs"
Style="{DynamicResource CustomButtonStyle}" />
<Button x:Name="UpdateVolumeLabel" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Update Label"
Style="{DynamicResource CustomButtonStyle}" />
<Button x:Name="CopyProtectScanButton" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Scan for protection"
Style="{DynamicResource CustomButtonStyle}" />
</UniformGrid>
@@ -175,7 +177,7 @@
<GroupBox Margin="5,5,5,5" HorizontalAlignment="Stretch" Header="Status">
<UniformGrid Margin="5,5,5,5" Grid.ColumnSpan="2">
<Label x:Name="StatusLabel" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Waiting for media..." />
<TextBlock x:Name="StatusLabel" VerticalAlignment="Center" HorizontalAlignment="Center" Text="Waiting for media..." />
</UniformGrid>
</GroupBox>
@@ -184,4 +186,4 @@
</Expander>
</StackPanel>
</Grid>
</windows:WindowBase>
</coreWindows:WindowBase>

View File

@@ -1,5 +1,6 @@
using System;
using MPF.GUI.ViewModels;
using MPF.UI.Core.Windows;
using MPF.UI.ViewModels;
namespace MPF.Windows
{

View File

@@ -1,14 +1,14 @@
<windows:WindowBase x:Class="MPF.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:MPF"
xmlns:windows="clr-namespace:MPF.Windows"
mc:Ignorable="d"
Title="Options" Width="515.132" WindowStyle="None"
WindowStartupLocation="CenterOwner" ResizeMode="CanMinimize" SizeToContent="Height"
BorderBrush="DarkGray" BorderThickness="2">
<coreWindows:WindowBase x:Class="MPF.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:MPF"
xmlns:coreWindows="clr-namespace:MPF.UI.Core.Windows;assembly=MPF.UI.Core"
mc:Ignorable="d"
Title="Options" Width="515.132" WindowStyle="None"
WindowStartupLocation="CenterOwner" ResizeMode="CanMinimize" SizeToContent="Height"
BorderBrush="DarkGray" BorderThickness="2">
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="0" ResizeBorderThickness="0" />
@@ -70,12 +70,15 @@
<CheckBox VerticalAlignment="Center" Content="Enable Dark Mode"
IsChecked="{Binding Options.EnableDarkMode}"
ToolTip="(Experimental) Enable dark mode across the entire application" Margin="0,4"
/>
/>
<CheckBox VerticalAlignment="Center" Content="Check for Updates on Startup"
IsChecked="{Binding Options.CheckForUpdatesOnStartup}"
ToolTip="Check for updates when the application starts" Margin="0,4"
/>
<CheckBox VerticalAlignment="Center" Content="Fast Update Label"
IsChecked="{Binding Options.FastUpdateLabel}"
ToolTip="Bypasses disc checks to quickly update the output path. Use with caution!" Margin="0,4"
/>
</UniformGrid>
</TabItem>
@@ -92,6 +95,7 @@
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Aaru Path" />
@@ -109,13 +113,18 @@
<Button x:Name="DDPathButton" Grid.Row="2" Grid.Column="2" Height="22" Width="22" Content="..."
Style="{DynamicResource CustomButtonStyle}" />
<Label Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Dumping Program" />
<ComboBox x:Name="InternalProgramComboBox" Grid.Row="3" Grid.Column="1" Height="22" HorizontalAlignment="Stretch"
<Label Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Redumper Path" />
<TextBox x:Name="RedumperPathTextBox" Grid.Row="3" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" Text="{Binding Options.RedumperPath}" VerticalContentAlignment="Center" />
<Button x:Name="RedumperPathButton" Grid.Row="3" Grid.Column="2" Height="22" Width="22" Content="..."
Style="{DynamicResource CustomButtonStyle}" />
<Label Grid.Row="4" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Default Dumping Program" />
<ComboBox x:Name="InternalProgramComboBox" Grid.Row="4" Grid.Column="1" Height="22" HorizontalAlignment="Stretch"
ItemsSource="{Binding InternalPrograms}" Style="{DynamicResource CustomComboBoxStyle}" />
<Label Grid.Row="4" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Default Output Path" />
<TextBox x:Name="DefaultOutputPathTextBox" Grid.Row="4" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" Text="{Binding Options.DefaultOutputPath}" VerticalContentAlignment="Center" />
<Button x:Name="DefaultOutputPathButton" Grid.Row="4" Grid.Column="2" Height="22" Width="22" Content="..."
<Label Grid.Row="5" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Default Output Path" />
<TextBox x:Name="DefaultOutputPathTextBox" Grid.Row="5" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" Text="{Binding Options.DefaultOutputPath}" VerticalContentAlignment="Center" />
<Button x:Name="DefaultOutputPathButton" Grid.Row="5" Grid.Column="2" Height="22" Width="22" Content="..."
Style="{DynamicResource CustomButtonStyle}" />
</Grid>
</TabItem>
@@ -123,8 +132,8 @@
<TabItem Header="Dumping" Style="{DynamicResource CustomTabItemStyle}">
<StackPanel>
<GroupBox Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Dumping">
<UniformGrid Columns="2" Rows="8">
<CheckBox VerticalAlignment="Center" Content="Skip Type Detect"
<UniformGrid Columns="2" Rows="9">
<CheckBox x:Name="SkipMediaTypeDetectionCheckBox" VerticalAlignment="Center" Content="Skip Type Detect"
IsChecked="{Binding Options.SkipMediaTypeDetection}"
ToolTip="Disable trying to guess media type inserted (may improve performance at startup)" Margin="0,4"
/>
@@ -162,6 +171,11 @@
ToolTip="Enable automatic checking for copy protection on dumped media" Margin="0,4,0,0"
/>
<CheckBox VerticalAlignment="Center" Content="Output Protection File"
IsChecked="{Binding Options.OutputSeparateProtectionFile}" IsEnabled="{Binding Options.ScanForProtection}"
ToolTip="Output protection information to a separate file" Margin="0,4,0,0"
/>
<CheckBox VerticalAlignment="Center" Content="Eject After Dump"
IsChecked="{Binding Options.EjectAfterDump}"
ToolTip="Eject the disc from the drive after dumping has completed" Margin="0,4"
@@ -173,9 +187,14 @@
/>
<CheckBox VerticalAlignment="Center" Content="Enable Tab Input"
IsChecked="{Binding Options.EnableTabsInInputFields}"
ToolTip="Enable entering tabs in supported input fields instead of tab navigation" Margin="0,4"
/>
IsChecked="{Binding Options.EnableTabsInInputFields}"
ToolTip="Enable entering tabs in supported input fields instead of tab navigation" Margin="0,4"
/>
<CheckBox VerticalAlignment="Center" Content="Enable Redump Compatibility"
IsChecked="{Binding Options.EnableRedumpCompatibility}"
ToolTip="Enable limiting outputs to only those supported by Redump" Margin="0,4"
/>
<CheckBox VerticalAlignment="Center" Content="Show Eject Reminder"
IsChecked="{Binding Options.ShowDiscEjectReminder}"
@@ -193,7 +212,7 @@
/>
<CheckBox VerticalAlignment="Center" Content="Include Artifacts"
IsChecked="{Binding Options.IncludeArtifacts}" IsEnabled="{Binding Options.OutputSubmissionJSON}"
IsChecked="{Binding Options.IncludeArtifacts}" IsEnabled="{Binding Options.OutputSubmissionJSON}"
ToolTip="Include log files in serialized JSON data" Margin="0,4"
/>
@@ -216,27 +235,35 @@
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="CD-ROM" />
<Label Grid.Row="0" Grid.Column="0" Content="CD" />
<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}}"
Value="{Binding Options.PreferredDumpSpeedCD}" />
<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" />
<Label Grid.Row="1" Grid.Column="0" Content="DVD" />
<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}}"
Value="{Binding Options.PreferredDumpSpeedDVD}" />
<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"
<Label Grid.Row="2" Grid.Column="0" Content="HD-DVD" />
<Slider x:Name="DumpSpeedHDDVDSlider" Grid.Row="2" Grid.Column="1" Minimum="1" Maximum="24" IsSnapToTickEnabled="True" TickPlacement="BottomRight"
Ticks="{Binding Source={x:Static local:Constants.SpeedsForHDDVDAsCollection}}"
Value="{Binding Options.PreferredDumpSpeedHDDVD}" />
<TextBox x:Name="DumpSpeedHDDVDTextBox" Grid.Row="2" Grid.Column="2" Width="22" Height="22" TextAlignment="Center" IsReadOnly="True" IsReadOnlyCaretVisible="False" VerticalAlignment="Center"
Text="{Binding ElementName=DumpSpeedHDDVDSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}" Background="LightGray" Foreground="Gray"/>
<Label Grid.Row="3" Grid.Column="0" Content="BD" />
<Slider x:Name="DumpSpeedBDSlider" Grid.Row="3" Grid.Column="1" Minimum="1" Maximum="16" IsSnapToTickEnabled="True" TickPlacement="BottomRight"
Ticks="{Binding Source={x:Static local:Constants.SpeedsForBDAsCollection}}"
Value="{Binding Options.PreferredDumpSpeedBD}" />
<TextBox x:Name="DumpSpeedBDTextBox" Grid.Row="2" Grid.Column="2" Width="22" Height="22" TextAlignment="Center" IsReadOnly="True" IsReadOnlyCaretVisible="False" VerticalAlignment="Center"
<TextBox x:Name="DumpSpeedBDTextBox" Grid.Row="3" 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>
@@ -256,11 +283,6 @@
ToolTip="Include executable packers in outputted protections" Margin="0,4"
/>
<CheckBox VerticalAlignment="Center" Content="Force Scanning All Files"
IsChecked="{Binding Options.ForceScanningForProtection}"
ToolTip="Force scanning all files even if they're not executables" Margin="0,4"
/>
<CheckBox VerticalAlignment="Center" Content="Include Debug Information"
IsChecked="{Binding Options.IncludeDebugProtectionInformation}"
ToolTip="Include debug information during protection scans" Margin="0,4"
@@ -300,7 +322,7 @@
</TabItem>
<TabItem Header="DiscImageCreator" Style="{DynamicResource CustomTabItemStyle}">
<UniformGrid Columns="2" Rows="3">
<UniformGrid Columns="2" Rows="6">
<CheckBox VerticalAlignment="Center" Content="Quiet Mode"
IsChecked="{Binding Options.DICQuietMode}"
ToolTip="Disable sounds (beeps) during and after operations" Margin="0,4"
@@ -321,10 +343,48 @@
ToolTip="Reset disc drives after dumping; useful for some older machines" Margin="0,4"
/>
<Label Content="Reread Tries:" VerticalAlignment="Center" HorizontalAlignment="Right"/>
<CheckBox VerticalAlignment="Center" Content="Multi-Sector Read"
IsChecked="{Binding Options.DICMultiSectorRead}"
ToolTip="Enable the /mr flag for BD drive dumping" Margin="0,4"
/>
<Label/> <!-- Empty label for padding -->
<Label Content="Multi-Sector Read Value:" VerticalAlignment="Center" HorizontalAlignment="Right"/>
<TextBox VerticalAlignment="Center" VerticalContentAlignment="Center"
Text="{Binding Options.DICMultiSectorReadValue}" IsEnabled="{Binding Options.DICMultiSectorRead}"
ToolTip="Set the default value for the /mr flag"
/>
<Label Content="CD Reread Tries:" VerticalAlignment="Center" HorizontalAlignment="Right"/>
<TextBox VerticalAlignment="Center" VerticalContentAlignment="Center"
Text="{Binding Options.DICRereadCount}"
ToolTip="Specifies how many rereads are attempted on C2 error"
ToolTip="Specifies how many rereads are attempted on C2 error [CD only]"
/>
<Label Content="DVD/HD-DVD/BD Reread Tries:" VerticalAlignment="Center" HorizontalAlignment="Right"/>
<TextBox VerticalAlignment="Center" VerticalContentAlignment="Center"
Text="{Binding Options.DICDVDRereadCount}"
ToolTip="Specifies how many rereads are attempted on read error [DVD/HD-DVD/BD only]"
/>
</UniformGrid>
</TabItem>
<TabItem Header="Redumper" Style="{DynamicResource CustomTabItemStyle}">
<UniformGrid Columns="2" Rows="2">
<CheckBox VerticalAlignment="Center" Content="Enable Debug Output"
IsChecked="{Binding Options.RedumperEnableDebug}"
ToolTip="Enable debug output in logs" Margin="0,4"
/>
<CheckBox VerticalAlignment="Center" Content="Enable Verbose Output"
IsChecked="{Binding Options.RedumperEnableVerbose}"
ToolTip="Enable verbose output in logs" Margin="0,4"
/>
<Label Content="Reread Tries:" VerticalAlignment="Center" HorizontalAlignment="Right"/>
<TextBox VerticalAlignment="Center" VerticalContentAlignment="Center"
Text="{Binding Options.RedumperRereadCount}"
ToolTip="Specifies how many rereads are attempted on read error"
/>
</UniformGrid>
</TabItem>
@@ -356,7 +416,7 @@
<TabItem Header="Login Info" Style="{DynamicResource CustomTabItemStyle}">
<StackPanel>
<GroupBox Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Redump Credentials">
<UniformGrid Columns="5" Rows="1">
<UniformGrid Columns="5">
<Label VerticalAlignment="Center" HorizontalAlignment="Right" Content="Username" />
<TextBox x:Name="RedumpUsernameTextBox" Height="22" HorizontalAlignment="Stretch"
Text="{Binding Options.RedumpUsername}" />
@@ -368,6 +428,12 @@
Style="{DynamicResource CustomButtonStyle}" />
</UniformGrid>
</GroupBox>
<Label>
<Label.Content>
<TextBlock TextWrapping="Wrap"><Bold Foreground="Red">WARNING:</Bold> If you choose to enable validation and information retrieval, you are responsible for ensuring that all data populated matches your actual media. Some information may be marked to check for validity as a reminder, but all information should be subject to the same scrutiny.</TextBlock>
</Label.Content>
</Label>
</StackPanel>
</TabItem>
</TabControl>
@@ -385,4 +451,4 @@
</GroupBox>
</StackPanel>
</Grid>
</windows:WindowBase>
</coreWindows:WindowBase>

View File

@@ -1,4 +1,5 @@
using MPF.GUI.ViewModels;
using MPF.UI.Core.Windows;
using MPF.UI.ViewModels;
namespace MPF.Windows
{
@@ -19,6 +20,12 @@ namespace MPF.Windows
{
InitializeComponent();
DataContext = new OptionsViewModel(this);
#if NET6_0_OR_GREATER
this.SkipMediaTypeDetectionCheckBox.IsEnabled = false;
this.SkipMediaTypeDetectionCheckBox.IsChecked = false;
this.SkipMediaTypeDetectionCheckBox.ToolTip = "This feature is not enabled for .NET 6";
#endif
}
}
}

View File

@@ -13,17 +13,69 @@ For those who would rather use the most recent stable build, download the latest
For those who like to test the newest features, download the latest AppVeyor WIP build here: [AppVeyor](https://ci.appveyor.com/project/mnadareski/MPF/build/artifacts)
## System Requirements
## Media Preservation Frontend (MPF)
Even though this is written in C#, this program can only be used on Windows systems due to one of the base programs, DiscImageCreator, being Windows-only. There is some preliminary support for Linux underway, and we will try to integrate with that when the time comes.
MPF is the main, UI-centric application of the MPF suite. This program allows users to use DiscImageCreator, Aaru, Redumper, or dd for Windows in a more user-friendly way. Each backend dumping program is supported as fully as possible to ensure that all information is captured on output. There are many customization options and quality of life settings that can be access through the Options menu.
- Windows 7 (newest version of Windows recommended) or Mono-compatible Linux environment (MPF.Check only)
- .NET Framework 4.8 or .NET Core 3.1 Runtimes (.NET Core 3.1 is mostly functional due to a dependency issues but may be unstable in some situations)
- 1 GB of free RAM
### System Requirements
- Windows 8.1 (x86 or x64) or newer
- Users who wish to use MPF on Windows 7 need to disable strong name validation due to `Microsoft.Management.Infrastructure` being unsigned. Add the following registry keys (accurate at time of writing):
```
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\*,31bf3856ad364e35]
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\*,31bf3856ad364e35]
```
- Alternatively, look at this [StackOverflow question](https://stackoverflow.com/questions/403731/strong-name-validation-failed) for more information.
- .NET Framework 4.8 or .NET 6.0 Runtimes (.NET 6.0 is mostly functional due to a dependency issues but may be unstable in some situations)
- As much hard drive space as the amount of discs you will be dumping (20+ GB recommended)
Ensure that your operating system is as up-to-date as possible, since some features may rely on those updates.
### Build Instructions
To build for .NET Framework 4.8 (Windows only), ensure that the .NET Framework 4.8 SDK is installed and included in your PATH. Then, run the following commands from command prompt, Powershell, or Terminal:
```
dotnet restore
msbuild MPF\MPF.csproj -property:TargetFramework=net48 -property:RuntimeIdentifiers=win7-x64
```
To build for .NET 6.0 (Windows only), ensure that the .NET 6.0 SDK (or later) is installed and included in your PATH. Then, run the following commands from command prompt, Powershell, or Terminal:
```
dotnet build MPF\MPF.csproj --framework net6.0-windows --runtime [win7-x64|win8-x64|win81-x64|win10-x64]
```
Choose one of `[win7-x64|win8-x64|win81-x64|win10-x64]` depending on the machine you are targeting. `win10-x64` also includes Windows 11.
## Media Preservation Frontend Checker (MPF.Check)
MPF.Check is a commandline-only program that allows users to generate submission information from their personal rips. This program supports the outputs from DiscImageCreator, Aaru, Redumper, dd for Windows, Cleanrip, and UmdImageCreator. Running this program without any parameters will display the help text, including all supported parameters.
### System Requirements
- Windows 8.1 (x86 or x64) or newer, GNU/Linux x64, or OSX x64
- .NET Framework 4.8 (Windows or `mono` only) or .NET 6.0 Runtimes
### Build Instructions
To build for .NET Framework 4.8 (Windows only), ensure that the .NET Framework 4.8 SDK is installed and included in your PATH. Then, run the following commands from command prompt, Powershell, or Terminal:
```
dotnet restore
msbuild MPF.Check\MPF.Check.csproj -property:TargetFramework=net48 -property:RuntimeIdentifiers=win7-x64
```
To build for .NET 6.0 (All supported OSes), ensure that the .NET 6.0 SDK (or later) is installed and included in your PATH. Then, run the following commands from command prompt, Powershell, Terminal, or shell:
```
dotnet build MPF.Check\MPF.Check.csproj --framework net6.0 --runtime [win7-x64|win8-x64|win81-x64|win10-x64|linux-x64|osx-x64]
```
Choose one of `[win7-x64|win8-x64|win81-x64|win10-x64|linux-x64|osx-x64]` depending on the machine you are targeting. `win10-x64` also includes Windows 11.
## Information
For all additional information, including information about the individual components included in the project and what dumping programs are supported, please see [the wiki](https://github.com/SabreTools/MPF/wiki) for more details.
@@ -37,8 +89,8 @@ A list of all changes in each stable release and current WIP builds can now be f
MPF uses some external libraries to assist with additional information gathering after the dumping process.
- **BurnOutSharp** - Protection scanning - [GitHub](https://github.com/mnadareski/BurnOutSharp)
- **WPFCustomMessageBox.thabse** - Custom message boxes in UI - [GitHub](https://github.com/thabse/WPFCustomMessageBox)
- **UnshieldSharp** - Protection scanning - [GitHub](https://github.com/mnadareski/UnshieldSharp)
- **WPFCustomMessageBox.thabse** - Custom message boxes in UI - [GitHub](https://github.com/thabse/WPFCustomMessageBox)
## Contributors

View File

@@ -177,12 +177,12 @@ namespace RedumpLib.Data
public const string DiscPageUrl = @"http://redump.org/disc/{0}/";
/// <summary>
/// Redump last modified search URL
/// Redump last modified search URL template
/// </summary>
public const string LastModifiedUrl = @"http://redump.org/discs/sort/modified/dir/desc?page={0}";
/// <summary>
/// Redump login page URL
/// Redump login page URL template
/// </summary>
public const string LoginUrl = "http://forum.redump.org/login/";
@@ -231,6 +231,11 @@ namespace RedumpLib.Data
/// </summary>
public const string UserDumpsUrl = @"http://redump.org/discs/dumper/{0}/?page={1}";
/// <summary>
/// Redump last modified user dumps URL template
/// </summary>
public const string UserDumpsLastModifiedUrl = @"http://redump.org/discs/sort/modified/dir/desc/dumper/{0}?page={1}";
/// <summary>
/// Redump WIP disc page URL template
/// </summary>

View File

@@ -44,6 +44,11 @@ namespace RedumpLib.Data
/// <summary>
/// List of all disc types
/// </summary>
/// <remarks>
/// All names here match Redump names for the types, not official
/// naming. Some names had to be extrapolated due to no current support
/// in the Redump site.
/// </remarks>
public enum DiscType
{
NONE = 0,
@@ -51,9 +56,21 @@ namespace RedumpLib.Data
[HumanReadable(LongName = "BD-25")]
BD25,
[HumanReadable(LongName = "BD-33")]
BD33,
[HumanReadable(LongName = "BD-50")]
BD50,
[HumanReadable(LongName = "BD-66")]
BD66,
[HumanReadable(LongName = "BD-100")]
BD100,
[HumanReadable(LongName = "BD-128")]
BD128,
[HumanReadable(LongName = "CD")]
CD,
@@ -62,31 +79,34 @@ namespace RedumpLib.Data
[HumanReadable(LongName = "DVD-9")]
DVD9,
[HumanReadable(LongName = "GD-ROM")]
GDROM,
[HumanReadable(LongName = "HD-DVD SL")]
HDDVDSL,
[HumanReadable(LongName = "HD-DVD DL")]
HDDVDDL,
[HumanReadable(LongName = "MIL-CD")]
MILCD,
[HumanReadable(LongName = "Nintendo GameCube Game Disc")]
NintendoGameCubeGameDisc,
[HumanReadable(LongName = "Nintendo Wii Optical Disc SL")]
NintendoWiiOpticalDiscSL,
[HumanReadable(LongName = "Nintendo Wii Optical Disc DL")]
NintendoWiiOpticalDiscDL,
[HumanReadable(LongName = "Nintendo Wii U Optical Disc SL")]
NintendoWiiUOpticalDiscSL,
[HumanReadable(LongName = "UMD SL")]
UMDSL,
[HumanReadable(LongName = "UMD DL")]
UMDDL,
}
@@ -99,7 +119,7 @@ namespace RedumpLib.Data
BadDumpRed = 2,
PossibleBadDumpYellow = 3,
OriginalMediaBlue = 4,
TwoOrMoHumanReadablesGreen = 5,
TwoOrMoreGreen = 5,
}
/// <summary>
@@ -472,7 +492,7 @@ namespace RedumpLib.Data
[Language(LongName = "Erzya", ThreeLetterCode = "myv")]
Erzya,
[Language(LongName = "Esperanto", TwoLetterCode="eo", ThreeLetterCode = "epo")]
[Language(LongName = "Esperanto", TwoLetterCode = "eo", ThreeLetterCode = "epo")]
Esperanto,
[Language(LongName = "Estonian", TwoLetterCode = "et", ThreeLetterCode = "est")]
@@ -1093,7 +1113,7 @@ namespace RedumpLib.Data
// Ossetian; Ossetic
[Language(LongName = "Ossetian", TwoLetterCode = "os", ThreeLetterCode = "oss")]
Ossetian,
#endregion
#region P
@@ -1754,7 +1774,7 @@ namespace RedumpLib.Data
[HumanReadable(LongName = "Language selector")]
LanguageSelector,
[HumanReadable(LongName = "Options menu")]
OptionsMenu,
}
@@ -1928,6 +1948,9 @@ namespace RedumpLib.Data
[System(Category = SystemCategory.DiscBasedConsole, Available = false, LongName = "Fujitsu FM Towns Marty")]
FujitsuFMTownsMarty,
[System(Category = SystemCategory.DiscBasedConsole, Available = false, LongName = "Hasbro iON Educational Gaming System")]
HasbroiONEducationalGamingSystem,
[System(Category = SystemCategory.DiscBasedConsole, LongName = "Hasbro VideoNow", ShortName = "hvn", IsBanned = true, HasCues = true, HasDat = true)]
HasbroVideoNow,
@@ -1946,6 +1969,9 @@ namespace RedumpLib.Data
[System(Category = SystemCategory.DiscBasedConsole, LongName = "Mattel HyperScan", ShortName = "hs", HasCues = true, HasDat = true)]
MattelHyperScan,
[System(Category = SystemCategory.DiscBasedConsole, LongName = "Memorex Visual Information System", ShortName = "vis", HasCues = true, HasDat = true)]
MemorexVisualInformationSystem,
[System(Category = SystemCategory.DiscBasedConsole, LongName = "Microsoft Xbox", ShortName = "xbox", HasCues = true, HasDat = true)]
MicrosoftXbox,
@@ -1955,12 +1981,9 @@ namespace RedumpLib.Data
[System(Category = SystemCategory.DiscBasedConsole, LongName = "Microsoft Xbox One", ShortName = "xboxone", IsBanned = true, HasDat = true)]
MicrosoftXboxOne,
[System(Category = SystemCategory.DiscBasedConsole, Available = false, LongName = "Microsoft Xbox Series X/S")]
[System(Category = SystemCategory.DiscBasedConsole, LongName = "Microsoft Xbox Series X", ShortName = "xboxsx", IsBanned = true, HasDat = true)]
MicrosoftXboxSeriesXS,
[System(Category = SystemCategory.DiscBasedConsole, LongName = "Memorex Visual Information System", ShortName = "vis", HasCues = true, HasDat = true)]
MemorexVisualInformationSystem,
[System(Category = SystemCategory.DiscBasedConsole, LongName = "NEC PC Engine CD & TurboGrafx CD", ShortName = "pce", HasCues = true, HasDat = true)]
NECPCEngineCDTurboGrafxCD,
@@ -2015,7 +2038,7 @@ namespace RedumpLib.Data
[System(Category = SystemCategory.DiscBasedConsole, LongName = "Sony PlayStation 4", ShortName = "ps4", IsBanned = true, HasDat = true)]
SonyPlayStation4,
[System(Category = SystemCategory.DiscBasedConsole, Available = false, LongName = "Sony PlayStation 5")]
[System(Category = SystemCategory.DiscBasedConsole, LongName = "Sony PlayStation 5", ShortName = "ps5", IsBanned = true, HasDat = true)]
SonyPlayStation5,
[System(Category = SystemCategory.DiscBasedConsole, LongName = "Sony PlayStation Portable", ShortName = "psp", HasDat = true)]
@@ -2190,10 +2213,10 @@ namespace RedumpLib.Data
#region Computers
[System(Category = SystemCategory.Computer, LongName = "Acorn Archimedes", ShortName = "archcd", HasCues = true, HasDat = true)]
[System(Category = SystemCategory.Computer, LongName = "Acorn Archimedes", ShortName = "arch", HasCues = true, HasDat = true)]
AcornArchimedes,
[System(Category = SystemCategory.Computer, LongName = "Apple Macintosh", ShortName = "mac", HasCues = true, HasDat = true)]
[System(Category = SystemCategory.Computer, LongName = "Apple Macintosh", ShortName = "mac", HasCues = true, HasDat = true, HasLsd = true, HasSbi = true)]
AppleMacintosh,
[System(Category = SystemCategory.Computer, LongName = "Commodore Amiga CD", ShortName = "acd", HasCues = true, HasDat = true)]
@@ -2204,7 +2227,7 @@ namespace RedumpLib.Data
[System(Category = SystemCategory.Computer, LongName = "IBM PC compatible", ShortName = "pc", HasCues = true, HasDat = true, HasLsd = true, HasSbi = true)]
IBMPCcompatible,
[System(Category = SystemCategory.Computer, LongName = "NEC PC-88 series", ShortName = "pc-88", HasCues = true, HasDat = true)]
NECPC88series,
@@ -2263,6 +2286,9 @@ namespace RedumpLib.Data
[System(Category = SystemCategory.Arcade, Available = false, LongName = "Incredible Technologies PC-based Systems")]
IncredibleTechnologiesVarious,
[System(Category = SystemCategory.Arcade, Available = false, LongName = "JVL iTouch")]
JVLiTouch,
[System(Category = SystemCategory.Arcade, LongName = "Konami e-Amusement", ShortName = "kea", HasCues = true, HasDat = true)]
KonamieAmusement,
@@ -2278,7 +2304,7 @@ namespace RedumpLib.Data
[System(Category = SystemCategory.Arcade, Available = false, LongName = "Konami Python 2")]
KonamiPython2,
[System(Category = SystemCategory.Arcade, LongName = "Konami System 573", ShortName = "ks573")]
[System(Category = SystemCategory.Arcade, LongName = "Konami System 573", ShortName = "ks573", HasCues = true, HasDat = true)]
KonamiSystem573,
[System(Category = SystemCategory.Arcade, LongName = "Konami System GV", ShortName = "ksgv", HasCues = true, HasDat = true)]
@@ -2376,10 +2402,13 @@ namespace RedumpLib.Data
[System(Category = SystemCategory.Arcade, LongName = "TAB-Austria Quizard", ShortName = "quizard", HasCues = true, HasDat = true)]
TABAustriaQuizard,
[System(Category = SystemCategory.Arcade, Available = false, LongName = "Tsunami TsuMo Multi-Game Motion System")]
TsunamiTsuMoMultiGameMotionSystem,
[System(Category = SystemCategory.Arcade, Available = false, LongName = "UltraCade PC-based Systems")]
UltraCade,
// End of arcade section delimiter
MarkerArcadeEnd,
@@ -2426,6 +2455,9 @@ namespace RedumpLib.Data
[System(Category = SystemCategory.Other, LongName = "Sega Prologue 21 Multimedia Karaoke System", ShortName = "sp21", HasCues = true, HasDat = true)]
SegaPrologue21MultimediaKaraokeSystem,
[System(Category = SystemCategory.Other, Available = false, LongName = "Sony Electronic Book")]
SonyElectronicBook,
[System(Category = SystemCategory.Other, Available = false, LongName = "Super Audio CD")]
SuperAudioCD,
@@ -3517,6 +3549,10 @@ namespace RedumpLib.Data
[HumanReadable(ShortName = "[T:X]", LongName = "<b>Extras</b>:")]
Extras,
// TODO: This doesn't have a site tag yet
[HumanReadable(ShortName = "<b>Filename</b>:", LongName = "<b>Filename</b>:")]
Filename,
[HumanReadable(ShortName = "[T:FIID]", LongName = "<b>Fox Interactive ID</b>:")]
FoxInteractiveID,
@@ -3533,6 +3569,10 @@ namespace RedumpLib.Data
[HumanReadable(ShortName = "[T:GTID]", LongName = "<b>GT Interactive ID</b>:")]
GTInteractiveID,
// TODO: This doesn't have a site tag yet
[HumanReadable(ShortName = "<b>Internal Name</b>:", LongName = "<b>Internal Name</b>:")]
InternalName,
[HumanReadable(ShortName = "[T:ISN]", LongName = "<b>Internal Serial</b>:")]
InternalSerialName,
@@ -3561,6 +3601,10 @@ namespace RedumpLib.Data
[HumanReadable(ShortName = "<b>Microsoft ID</b>:", LongName = "<b>Microsoft ID</b>:")]
MicrosoftID,
// TODO: This doesn't have a site tag yet
[HumanReadable(ShortName = "<b>Multisession</b>:", LongName = "<b>Multisession</b>:")]
Multisession,
[HumanReadable(ShortName = "[T:NGID]", LongName = "<b>Nagano ID</b>:")]
NaganoID,
@@ -3595,6 +3639,10 @@ namespace RedumpLib.Data
[HumanReadable(ShortName = "[T:PPN]", LongName = "<b>PPN</b>:")]
PPN,
// TODO: This doesn't have a site tag yet
[HumanReadable(ShortName = "<b>Ring non-zero data start</b>:", LongName = "<b>Ring non-zero data start</b>:")]
RingNonZeroDataStart,
[HumanReadable(ShortName = "[T:RD]", LongName = "<b>Rolling Demos</b>:")]
RollingDemos,
@@ -3631,6 +3679,10 @@ namespace RedumpLib.Data
[HumanReadable(ShortName = "[T:UID]", LongName = "<b>Ubisoft ID</b>:")]
UbisoftID,
// TODO: This doesn't have a site tag yet
[HumanReadable(ShortName = "<b>Universal Hash (SHA-1)</b>:", LongName = "<b>Universal Hash (SHA-1)</b>:")]
UniversalHash,
[HumanReadable(ShortName = "[T:VID]", LongName = "<b>Valve ID</b>:")]
ValveID,

View File

@@ -12,7 +12,7 @@ namespace RedumpLib.Data
{
#region Cross-Enumeration
/// <summary>
/// <summary>
/// Get a list of valid MediaTypes for a given RedumpSystem
/// </summary>
/// <param name="system">RedumpSystem value to check</param>
@@ -62,6 +62,11 @@ namespace RedumpLib.Data
types.Add(MediaType.FloppyDisk);
break;
// http://videogamekraken.com/ion-educational-gaming-system-by-hasbro
case RedumpSystem.HasbroiONEducationalGamingSystem:
types.Add(MediaType.CDROM);
break;
// https://en.wikipedia.org/wiki/VideoNow
case RedumpSystem.HasbroVideoNow:
types.Add(MediaType.CDROM);
@@ -372,6 +377,12 @@ namespace RedumpLib.Data
types.Add(MediaType.DVD);
break;
// UNKNOWN
case RedumpSystem.JVLiTouch:
types.Add(MediaType.CDROM);
types.Add(MediaType.DVD);
break;
// https://en.wikipedia.org/wiki/E-Amusement
case RedumpSystem.KonamieAmusement:
types.Add(MediaType.CDROM);
@@ -514,6 +525,7 @@ namespace RedumpLib.Data
types.Add(MediaType.DVD);
break;
// UNKNOWN
case RedumpSystem.SegaALLS:
types.Add(MediaType.DVD);
break;
@@ -604,6 +616,12 @@ namespace RedumpLib.Data
types.Add(MediaType.CDROM);
break;
// https://en.wikipedia.org/wiki/UltraCade_Technologies
case RedumpSystem.UltraCade:
types.Add(MediaType.CDROM);
types.Add(MediaType.DVD);
break;
#endregion
#region Others
@@ -673,6 +691,11 @@ namespace RedumpLib.Data
types.Add(MediaType.CDROM);
break;
// UNKNOWN
case RedumpSystem.SonyElectronicBook:
types.Add(MediaType.CDROM);
break;
// https://en.wikipedia.org/wiki/Super_Audio_CD
case RedumpSystem.SuperAudioCD:
types.Add(MediaType.CDROM);
@@ -747,7 +770,11 @@ namespace RedumpLib.Data
switch (discType)
{
case DiscType.BD25:
case DiscType.BD33:
case DiscType.BD50:
case DiscType.BD66:
case DiscType.BD100:
case DiscType.BD128:
return MediaType.BluRay;
case DiscType.CD:
return MediaType.CDROM;
@@ -757,6 +784,7 @@ namespace RedumpLib.Data
case DiscType.GDROM:
return MediaType.GDROM;
case DiscType.HDDVDSL:
case DiscType.HDDVDDL:
return MediaType.HDDVD;
// case DiscType.MILCD: // TODO: Support this?
// return MediaType.MILCD;
@@ -847,9 +875,21 @@ namespace RedumpLib.Data
case "bd25":
case "bd-25":
return DiscType.BD25;
case "bd33":
case "bd-33":
return DiscType.BD33;
case "bd50":
case "bd-50":
return DiscType.BD50;
case "bd66":
case "bd-66":
return DiscType.BD66;
case "bd100":
case "bd-100":
return DiscType.BD100;
case "bd128":
case "bd-128":
return DiscType.BD128;
case "cd":
case "cdrom":
case "cd-rom":
@@ -868,6 +908,9 @@ namespace RedumpLib.Data
case "hddvdsl":
case "hd-dvd sl":
return DiscType.HDDVDSL;
case "hddvddl":
case "hd-dvd dl":
return DiscType.HDDVDDL;
case "milcd":
case "mil-cd":
return DiscType.MILCD;
@@ -1001,6 +1044,24 @@ namespace RedumpLib.Data
#region Media Type
/// <summary>
/// List all media types with their short usable names
/// </summary>
public static List<string> ListMediaTypes()
{
var mediaTypes = new List<string>();
foreach (var val in Enum.GetValues(typeof(MediaType)))
{
if (((MediaType)val) == MediaType.NONE)
continue;
mediaTypes.Add($"{((MediaType?)val).ShortName()} - {((MediaType?)val).LongName()}");
}
return mediaTypes;
}
/// <summary>
/// Get the Redump longnames for each known media type
/// </summary>
@@ -1076,6 +1137,46 @@ namespace RedumpLib.Data
#region System
/// <summary>
/// Determine if a system is a marker value
/// </summary>
/// <param name="system">RedumpSystem value to check</param>
/// <returns>True if the system is a marker value, false otherwise</returns>
public static bool IsMarker(this RedumpSystem? system)
{
switch (system)
{
case RedumpSystem.MarkerArcadeEnd:
case RedumpSystem.MarkerComputerEnd:
case RedumpSystem.MarkerDiscBasedConsoleEnd:
// case RedumpSystem.MarkerOtherConsoleEnd:
case RedumpSystem.MarkerOtherEnd:
return true;
default:
return false;
}
}
/// <summary>
/// List all systems with their short usable names
/// </summary>
public static List<string> ListSystems()
{
var systems = new List<string>();
var knownSystems = Enum.GetValues(typeof(RedumpSystem))
.OfType<RedumpSystem?>()
.Where(s => s != null && !s.IsMarker() && s.GetCategory() != SystemCategory.NONE)
.OrderBy(s => s.LongName() ?? string.Empty);
foreach (var val in knownSystems)
{
systems.Add($"{val.ShortName()} - {val.LongName()}");
}
return systems;
}
/// <summary>
/// Get the Redump longnames for each known system
/// </summary>
@@ -1153,12 +1254,14 @@ namespace RedumpLib.Data
case "xboxbios":
case "xbox bios":
case "xbox-bios":
case "microsoftxboxbios":
case "microsoftxbox bios":
case "microsoft xbox bios":
return RedumpSystem.MicrosoftXboxBIOS;
case "gcbios":
case "gc bios":
case "gc-bios":
case "gamecubebios":
case "ngcbios":
case "ngc bios":
@@ -1169,6 +1272,7 @@ namespace RedumpLib.Data
case "ps1 bios":
case "psxbios":
case "psx bios":
case "psx-bios":
case "playstationbios":
case "playstation bios":
case "sonyps1bios":
@@ -1183,6 +1287,7 @@ namespace RedumpLib.Data
return RedumpSystem.SonyPlayStationBIOS;
case "ps2bios":
case "ps2 bios":
case "ps2-bios":
case "playstation2bios":
case "playstation2 bios":
case "playstation 2 bios":
@@ -1198,6 +1303,7 @@ namespace RedumpLib.Data
#region Consoles
case "ajcd":
case "jaguar":
case "jagcd":
case "jaguarcd":
@@ -1207,6 +1313,7 @@ namespace RedumpLib.Data
case "atarijaguarcd":
case "atari jaguar cd":
return RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem;
case "qis":
case "playdia":
case "playdiaqis":
case "playdiaquickinteractivesystem":
@@ -1250,20 +1357,30 @@ namespace RedumpLib.Data
case "fujitsufmtownsmarty":
case "fujitsu fm towns marty":
return RedumpSystem.FujitsuFMTownsMarty;
case "ion":
case "ionegs":
case "hasbroion":
case "hasbroioneducationalgamingsystem":
case "hasbro ion educational gaming system":
return RedumpSystem.HasbroiONEducationalGamingSystem;
case "hvn":
case "videonow":
case "hasbrovideonow":
case "hasbro videonow":
return RedumpSystem.HasbroVideoNow;
case "hvnc":
case "videonowcolor":
case "videonow color":
case "hasbrovideonowcolor":
case "hasbro videonow color":
return RedumpSystem.HasbroVideoNowColor;
case "hvnjr":
case "videonowjr":
case "videonow jr":
case "hasbrovideonowjr":
case "hasbro videonow jr":
return RedumpSystem.HasbroVideoNowJr;
case "xvnxp":
case "videonowxp":
case "videonow xp":
case "hasbrovideonowxp":
@@ -1282,6 +1399,7 @@ namespace RedumpLib.Data
case "mattel fisherprice ixl":
case "mattel fisher-price ixl":
return RedumpSystem.MattelFisherPriceiXL;
case "hs":
case "hyperscan":
case "mattelhyperscan":
case "mattel hyperscan":
@@ -1306,6 +1424,7 @@ namespace RedumpLib.Data
case "microsoft xbox one":
return RedumpSystem.MicrosoftXboxOne;
case "xbs":
case "xboxsx":
case "xbseries":
case "xbseriess":
case "xbseriesx":
@@ -1323,6 +1442,7 @@ namespace RedumpLib.Data
case "microsoft xbox series x":
case "microsoft xbox series x and s":
return RedumpSystem.MicrosoftXboxSeriesXS;
case "pce":
case "pcecd":
case "pce-cd":
case "tgcd":
@@ -1418,6 +1538,7 @@ namespace RedumpLib.Data
case "segadreamcast":
case "sega dreamcast":
return RedumpSystem.SegaDreamcast;
case "ss":
case "saturn":
case "segasaturn":
case "sega saturn":
@@ -1527,6 +1648,7 @@ namespace RedumpLib.Data
#region Computers
case "acorn":
case "archcd":
case "archimedes":
case "acornarchimedes":
case "acorn archimedes":
@@ -1539,6 +1661,7 @@ namespace RedumpLib.Data
case "apple mac":
case "apple macintosh":
return RedumpSystem.AppleMacintosh;
case "acd":
case "amiga":
case "commodoreamiga":
case "commodore amiga":
@@ -1569,6 +1692,7 @@ namespace RedumpLib.Data
case "nec pc-98":
return RedumpSystem.NECPC98series;
case "x68k":
case "x68kcd":
case "x68000":
case "sharpx68k":
case "sharp x68k":
@@ -1640,6 +1764,7 @@ namespace RedumpLib.Data
case "ice pc":
case "ice pc-based hardware":
return RedumpSystem.ICEPCHardware;
case "ite":
case "iteagle":
case "eagle":
case "incredible technologies eagle":
@@ -1647,6 +1772,10 @@ namespace RedumpLib.Data
case "itpc":
case "incredible technologies pc-based systems":
return RedumpSystem.IncredibleTechnologiesVarious;
case "jvlitouch":
case "jvl itouch":
return RedumpSystem.JVLiTouch;
case "kea":
case "eamusement":
case "e-amusement":
case "konamieamusement":
@@ -1654,10 +1783,12 @@ namespace RedumpLib.Data
case "konamie-amusement":
case "konami e-amusement":
return RedumpSystem.KonamieAmusement;
case "kfb":
case "firebeat":
case "konamifirebeat":
case "konami firebeat":
return RedumpSystem.KonamiFireBeat;
case "ksgv":
case "gvsystem":
case "gv system":
case "konamigvsystem":
@@ -1667,6 +1798,7 @@ namespace RedumpLib.Data
case "konamisystemgv":
case "konami system gv":
return RedumpSystem.KonamiSystemGV;
case "km2":
case "konamim2":
case "konami m2":
return RedumpSystem.KonamiM2;
@@ -1679,11 +1811,13 @@ namespace RedumpLib.Data
case "konamipython2":
case "konami python 2":
return RedumpSystem.KonamiPython2;
case "ks573":
case "system573":
case "system 573":
case "konamisystem573":
case "konami system 573":
return RedumpSystem.KonamiSystem573;
case "kt":
case "twinkle":
case "konamitwinkle":
case "konami twinkle":
@@ -1716,6 +1850,7 @@ namespace RedumpLib.Data
case "meritindustriesmegatouchxl":
case "merit industries megatouch xl":
return RedumpSystem.MeritIndustriesMegaTouchXL;
case "ns246":
case "system246":
case "system 246":
case "namcosystem246":
@@ -1748,6 +1883,7 @@ namespace RedumpLib.Data
case "nintendo triforce":
case "namco / sega / nintendo triforce":
return RedumpSystem.NamcoSegaNintendoTriforce;
case "ns12":
case "system12":
case "system 12":
case "namcosystem12":
@@ -1779,6 +1915,7 @@ namespace RedumpLib.Data
case "nichibutsu xrs":
case "nichibutsu x-rate system":
return RedumpSystem.NichibutsuXRateSystem;
case "m2":
case "panasonicm2":
case "panasonic m2":
return RedumpSystem.PanasonicM2;
@@ -1822,10 +1959,12 @@ namespace RedumpLib.Data
case "seganu":
case "sega nu":
return RedumpSystem.SegaNu;
case "sre":
case "ringedge":
case "segaringedge":
case "sega ringedge":
return RedumpSystem.SegaRingEdge;
case "sre2":
case "ringedge2":
case "ringedge 2":
case "segaringedge2":
@@ -1860,6 +1999,11 @@ namespace RedumpLib.Data
case "tsunami tsumo":
case "tsunami tsumo multi-game motion system":
return RedumpSystem.TsunamiTsuMoMultiGameMotionSystem;
case "ultracade":
case "ultracadepc":
case "ultracade pc":
case "ultracade pc-based systems":
return RedumpSystem.UltraCade;
#endregion
@@ -1868,6 +2012,7 @@ namespace RedumpLib.Data
case "audio":
case "audiocd":
case "audio cd":
case "audio-cd":
return RedumpSystem.AudioCD;
case "bdvideo":
case "bd-video":
@@ -1885,6 +2030,7 @@ namespace RedumpLib.Data
return RedumpSystem.DVDVideo;
case "enhancedcd":
case "enhanced cd":
case "enhanced-cd":
case "enhancedcdrom":
case "enhanced cdrom":
case "enhanced cd-rom":
@@ -1895,6 +2041,7 @@ namespace RedumpLib.Data
case "hddvd-video":
case "hd-dvd-video":
return RedumpSystem.HDDVDVideo;
case "navi21":
case "naviken":
case "naviken21":
case "naviken 2.1":
@@ -1909,7 +2056,9 @@ namespace RedumpLib.Data
case "photo":
case "photocd":
case "photo cd":
case "photo-cd":
return RedumpSystem.PhotoCD;
case "psxgs":
case "gameshark":
case "psgameshark":
case "ps gameshark":
@@ -1925,6 +2074,7 @@ namespace RedumpLib.Data
case "rainbowdisc":
case "rainbow disc":
return RedumpSystem.RainbowDisc;
case "sp21":
case "pl21":
case "prologue21":
case "prologue 21":
@@ -1932,6 +2082,10 @@ namespace RedumpLib.Data
case "sega prologue21":
case "sega prologue 21":
return RedumpSystem.SegaPrologue21MultimediaKaraokeSystem;
case "electronicbook":
case "sonyelectronicbook":
case "sony electronic book":
return RedumpSystem.SonyElectronicBook;
case "sacd":
case "superaudiocd":
case "super audio cd":
@@ -1940,6 +2094,7 @@ namespace RedumpLib.Data
case "taoiktv":
case "tao iktv":
return RedumpSystem.TaoiKTV;
case "ksite":
case "kisssite":
case "kiss-site":
case "tomykisssite":
@@ -1959,7 +2114,7 @@ namespace RedumpLib.Data
}
#endregion
#region System Category
/// <summary>
@@ -1980,6 +2135,24 @@ namespace RedumpLib.Data
/// <returns></returns>
public static string LongName(this YesNo? yesno) => AttributeHelper<YesNo?>.GetAttribute(yesno)?.LongName ?? "Yes/No";
/// <summary>
/// Get the YesNo enum value for a given nullable boolean
/// </summary>
/// <param name="yesno">Nullable boolean value to convert</param>
/// <returns>YesNo represented by the nullable boolean, if possible</returns>
public static YesNo? ToYesNo(this bool? yesno)
{
switch (yesno)
{
case false:
return YesNo.No;
case true:
return YesNo.Yes;
default:
return YesNo.NULL;
}
}
/// <summary>
/// Get the YesNo enum value for a given string
/// </summary>

View File

@@ -12,13 +12,19 @@ namespace RedumpLib.Data
/// Version of the current schema
/// </summary>
[JsonProperty(PropertyName = "schema_version", DefaultValueHandling = DefaultValueHandling.Ignore)]
public int SchemaVersion { get; set; } = 1;
public int SchemaVersion { get; set; } = 3;
/// <summary>
/// List of matched Redump IDs
/// Fully matched Redump ID
/// </summary>
[JsonIgnore]
public List<int> MatchedIDs { get; set; }
public int? FullyMatchedID { get; set; }
/// <summary>
/// List of partially matched Redump IDs
/// </summary>
[JsonIgnore]
public List<int> PartiallyMatchedIDs { get; set; }
/// <summary>
/// DateTime of when the disc was added
@@ -59,15 +65,19 @@ namespace RedumpLib.Data
[JsonProperty(PropertyName = "size_and_checksums", DefaultValueHandling = DefaultValueHandling.Ignore)]
public SizeAndChecksumsSection SizeAndChecksums { get; set; } = new SizeAndChecksumsSection();
[JsonProperty(PropertyName = "dumping_info", DefaultValueHandling = DefaultValueHandling.Ignore)]
public DumpingInfoSection DumpingInfo { get; set; } = new DumpingInfoSection();
[JsonProperty(PropertyName = "artifacts", DefaultValueHandling = DefaultValueHandling.Ignore)]
public Dictionary<string, string> Artifacts { get; set; } = new Dictionary<string, string>();
public object Clone()
{
return new SubmissionInfo
{
SchemaVersion = this.SchemaVersion,
MatchedIDs = this.MatchedIDs,
FullyMatchedID = this.FullyMatchedID,
PartiallyMatchedIDs = this.PartiallyMatchedIDs,
Added = this.Added,
LastModified = this.LastModified,
CommonDiscInfo = this.CommonDiscInfo?.Clone() as CommonDiscInfoSection,
@@ -79,6 +89,7 @@ namespace RedumpLib.Data
DumpersAndStatus = this.DumpersAndStatus?.Clone() as DumpersAndStatusSection,
TracksAndWriteOffsets = this.TracksAndWriteOffsets?.Clone() as TracksAndWriteOffsetsSection,
SizeAndChecksums = this.SizeAndChecksums?.Clone() as SizeAndChecksumsSection,
DumpingInfo = this.DumpingInfo?.Clone() as DumpingInfoSection,
Artifacts = this.Artifacts?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value),
};
}
@@ -148,7 +159,7 @@ namespace RedumpLib.Data
[JsonProperty(PropertyName = "d_ring_0_mo1_sid", NullValueHandling = NullValueHandling.Ignore)]
public string Layer0MouldSID { get; set; }
[JsonProperty(PropertyName = "dr_ring_0_mo1", NullValueHandling = NullValueHandling.Ignore)]
[JsonProperty(PropertyName = "d_ring_0_mo1", NullValueHandling = NullValueHandling.Ignore)]
public string Layer0AdditionalMould { get; set; }
[JsonProperty(PropertyName = "d_ring_0_ma2", Required = Required.AllowNull)]
@@ -163,7 +174,7 @@ namespace RedumpLib.Data
[JsonProperty(PropertyName = "d_ring_0_mo2_sid", NullValueHandling = NullValueHandling.Ignore)]
public string Layer1MouldSID { get; set; }
[JsonProperty(PropertyName = "dr_ring_0_mo2", NullValueHandling = NullValueHandling.Ignore)]
[JsonProperty(PropertyName = "d_ring_0_mo2", NullValueHandling = NullValueHandling.Ignore)]
public string Layer1AdditionalMould { get; set; }
[JsonProperty(PropertyName = "d_ring_0_ma3", Required = Required.AllowNull)]
@@ -395,6 +406,9 @@ namespace RedumpLib.Data
[JsonProperty(PropertyName = "d_protection", NullValueHandling = NullValueHandling.Ignore)]
public string Protection { get; set; }
[JsonIgnore]
public Dictionary<string, List<string>> FullProtections { get; set; }
[JsonProperty(PropertyName = "d_securom", NullValueHandling = NullValueHandling.Ignore)]
public string SecuROMData { get; set; }
@@ -406,6 +420,7 @@ namespace RedumpLib.Data
LibCrypt = this.LibCrypt,
LibCryptData = this.LibCryptData,
Protection = this.Protection,
FullProtections = this.FullProtections?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value),
SecuROMData = this.SecuROMData,
};
}
@@ -479,6 +494,9 @@ namespace RedumpLib.Data
[JsonProperty(PropertyName = "d_layerbreak_3", NullValueHandling = NullValueHandling.Ignore)]
public long Layerbreak3 { get; set; }
[JsonProperty(PropertyName = "d_pic_identifier", NullValueHandling = NullValueHandling.Ignore)]
public string PICIdentifier { get; set; }
[JsonProperty(PropertyName = "d_size", NullValueHandling = NullValueHandling.Ignore)]
public long Size { get; set; }
@@ -498,6 +516,7 @@ namespace RedumpLib.Data
Layerbreak = this.Layerbreak,
Layerbreak2 = this.Layerbreak2,
Layerbreak3 = this.Layerbreak3,
PICIdentifier = this.PICIdentifier,
Size = this.Size,
CRC32 = this.CRC32,
MD5 = this.MD5,
@@ -505,4 +524,42 @@ namespace RedumpLib.Data
};
}
}
/// <summary>
/// Dumping info section for moderation
/// </summary>
public class DumpingInfoSection : ICloneable
{
// Name not defined by Redump
[JsonProperty(PropertyName = "d_dumping_program", Required = Required.AllowNull)]
public string DumpingProgram { get; set; }
// Name not defined by Redump
[JsonProperty(PropertyName = "d_drive_manufacturer", Required = Required.AllowNull)]
public string Manufacturer { get; set; }
// Name not defined by Redump
[JsonProperty(PropertyName = "d_drive_model", Required = Required.AllowNull)]
public string Model { get; set; }
// Name not defined by Redump
[JsonProperty(PropertyName = "d_drive_firmware", Required = Required.AllowNull)]
public string Firmware { get; set; }
// Name not defined by Redump
[JsonProperty(PropertyName = "d_reported_disc_type", Required = Required.AllowNull)]
public string ReportedDiscType { get; set; }
public object Clone()
{
return new DumpingInfoSection
{
DumpingProgram = this.DumpingProgram,
Manufacturer = this.Manufacturer,
Model = this.Model,
Firmware = this.Firmware,
ReportedDiscType = this.ReportedDiscType,
};
}
}
}

View File

@@ -1,13 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;netcoreapp3.1;net5.0</TargetFrameworks>
<PlatformTarget>x86</PlatformTarget>
<TargetFrameworks>net48;net6.0</TargetFrameworks>
<RuntimeIdentifiers>win7-x64;win8-x64;win81-x64;win10-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,808 @@
#if NET6_0
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using RedumpLib.Data;
namespace RedumpLib.Web
{
public class RedumpHttpClient : HttpClient
{
#region Properties
/// <summary>
/// Determines if user is logged into Redump
/// </summary>
public bool LoggedIn { get; private set; } = false;
/// <summary>
/// Determines if the user is a staff member
/// </summary>
public bool IsStaff { get; private set; } = false;
#endregion
/// <summary>
/// Constructor
/// </summary>
public RedumpHttpClient()
: base(new HttpClientHandler { UseCookies = true })
{
}
#region Credentials
/// <summary>
/// Validate supplied credentials
/// </summary>
public async static Task<(bool?, string)> ValidateCredentials(string username, string password)
{
// If options are invalid or we're missing something key, just return
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
return (false, null);
// Try logging in with the supplied credentials otherwise
using RedumpHttpClient httpClient = new();
bool? loggedIn = await httpClient.Login(username, password);
if (loggedIn == true)
return (true, "Redump username and password accepted!");
else if (loggedIn == false)
return (false, "Redump username and password denied!");
else
return (null, "An error occurred validating your credentials!");
}
/// <summary>
/// Login to Redump, if possible
/// </summary>
/// <param name="username">Redump username</param>
/// <param name="password">Redump password</param>
/// <returns>True if the user could be logged in, false otherwise, null on error</returns>
public async Task<bool?> Login(string username, string password)
{
// Credentials verification
if (!string.IsNullOrWhiteSpace(username) && !string.IsNullOrWhiteSpace(password))
{
Console.WriteLine("Credentials entered, will attempt Redump login...");
}
else if (!string.IsNullOrWhiteSpace(username) && string.IsNullOrWhiteSpace(password))
{
Console.WriteLine("Only a username was specified, will not attempt Redump login...");
return false;
}
else if (string.IsNullOrWhiteSpace(username))
{
Console.WriteLine("No credentials entered, will not attempt Redump login...");
return false;
}
// HTTP encode the password
password = WebUtility.UrlEncode(password);
// Attempt to login up to 3 times
for (int i = 0; i < 3; i++)
{
try
{
// Get the current token from the login page
var loginPage = await GetStringAsync(Constants.LoginUrl);
string token = Constants.TokenRegex.Match(loginPage).Groups[1].Value;
// Construct the login request
var postContent = new StringContent($"form_sent=1&redirect_url=&csrf_token={token}&req_username={username}&req_password={password}&save_pass=0", Encoding.UTF8);
postContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/x-www-form-urlencoded");
// Send the login request and get the result
var response = await PostAsync(Constants.LoginUrl, postContent);
string responseContent = await response?.Content?.ReadAsStringAsync();
if (string.IsNullOrWhiteSpace(responseContent))
{
Console.WriteLine($"An error occurred while trying to log in on attempt {i}: No response");
continue;
}
if (responseContent.Contains("Incorrect username and/or password."))
{
Console.WriteLine("Invalid credentials entered, continuing without logging in...");
return false;
}
// The user was able to be logged in
Console.WriteLine("Credentials accepted! Logged into Redump...");
LoggedIn = true;
// If the user is a moderator or staff, set accordingly
if (responseContent.Contains("http://forum.redump.org/forum/9/staff/"))
IsStaff = true;
return true;
}
catch (Exception ex)
{
Console.WriteLine($"An exception occurred while trying to log in on attempt {i}: {ex}");
}
}
Console.WriteLine("Could not login to Redump in 3 attempts, continuing without logging in...");
return false;
}
#endregion
#region Single Page Helpers
/// <summary>
/// Process a Redump site page as a list of possible IDs or disc page
/// </summary>
/// <param name="url">Base URL to download using</param>
/// <returns>List of IDs from the page, empty on error</returns>
public async Task<List<int>> CheckSingleSitePage(string url)
{
List<int> ids = new();
// Try up to 3 times to retrieve the data
string dumpsPage = await DownloadString(url, retries: 3);
// If we have no dumps left
if (dumpsPage == null || 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 (int.TryParse(value, out int id))
ids.Add(id);
return ids;
}
// Otherwise, traverse each dump on the page
var matches = Constants.DiscRegex.Matches(dumpsPage);
foreach (Match match in matches)
{
try
{
if (int.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 site page as a list of possible IDs or disc page
/// </summary>
/// <param name="url">Base URL to download using</param>
/// <param name="outDir">Output directory to save data to</param>
/// <param name="failOnSingle">True to return on first error, false otherwise</param>
/// <returns>True if the page could be downloaded, false otherwise</returns>
public async Task<bool> CheckSingleSitePage(string url, string outDir, bool failOnSingle)
{
// Try up to 3 times to retrieve the data
string dumpsPage = await DownloadString(url, retries: 3);
// If we have no dumps left
if (dumpsPage == null || dumpsPage.Contains("No discs found."))
return false;
// 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 (int.TryParse(value, out int id))
{
bool downloaded = await DownloadSingleSiteID(id, outDir, false);
if (!downloaded && failOnSingle)
return false;
}
return false;
}
// Otherwise, traverse each dump on the page
var matches = Constants.DiscRegex.Matches(dumpsPage);
foreach (Match match in matches)
{
try
{
if (int.TryParse(match.Groups[1].Value, out int value))
{
bool downloaded = await DownloadSingleSiteID(value, outDir, false);
if (!downloaded && failOnSingle)
return false;
}
}
catch (Exception ex)
{
Console.WriteLine($"An exception has occurred: {ex}");
continue;
}
}
return true;
}
/// <summary>
/// Process a Redump WIP page as a list of possible IDs or disc page
/// </summary>
/// <param name="wc">RedumpWebClient to access the packs</param>
/// <returns>List of IDs from the page, empty on error</returns>
public async Task<List<int>> CheckSingleWIPPage(string url)
{
List<int> ids = new();
// Try up to 3 times to retrieve the data
string dumpsPage = await DownloadString(url, retries: 3);
// If we have no dumps left
if (dumpsPage == null || dumpsPage.Contains("No discs found."))
return ids;
// Otherwise, traverse each dump on the page
var matches = Constants.NewDiscRegex.Matches(dumpsPage);
foreach (Match match in matches)
{
try
{
if (int.TryParse(match.Groups[2].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">RedumpWebClient to access the packs</param>
/// <param name="outDir">Output directory to save data to</param>
/// <param name="failOnSingle">True to return on first error, false otherwise</param>
/// <returns>True if the page could be downloaded, false otherwise</returns>
public async Task<bool> CheckSingleWIPPage(string url, string outDir, bool failOnSingle)
{
// Try up to 3 times to retrieve the data
string dumpsPage = await DownloadString(url, retries: 3);
// If we have no dumps left
if (dumpsPage == null || dumpsPage.Contains("No discs found."))
return false;
// Otherwise, traverse each dump on the page
var matches = Constants.NewDiscRegex.Matches(dumpsPage);
foreach (Match match in matches)
{
try
{
if (int.TryParse(match.Groups[2].Value, out int value))
{
bool downloaded = await DownloadSingleWIPID(value, outDir, false);
if (!downloaded && failOnSingle)
return false;
}
}
catch (Exception ex)
{
Console.WriteLine($"An exception has occurred: {ex}");
continue;
}
}
return true;
}
#endregion
#region Download Helpers
/// <summary>
/// Download a single pack
/// </summary>
/// <param name="url">Base URL to download using</param>
/// <param name="system">System to download packs for</param>
/// <returns>Byte array containing the downloaded pack, null on error</returns>
public async Task<byte[]> DownloadSinglePack(string url, RedumpSystem? system)
{
try
{
return await GetByteArrayAsync(string.Format(url, system.ShortName()));
}
catch (Exception ex)
{
Console.WriteLine($"An exception has occurred: {ex}");
return null;
}
}
/// <summary>
/// Download a single pack
/// </summary>
/// <param name="url">Base URL to download using</param>
/// <param name="system">System to download packs for</param>
/// <param name="outDir">Output directory to save data to</param>
/// <param name="subfolder">Named subfolder for the pack, used optionally</param>
public async Task<bool> DownloadSinglePack(string url, RedumpSystem? system, string outDir, string subfolder)
{
try
{
// If no output directory is defined, use the current directory instead
if (string.IsNullOrWhiteSpace(outDir))
outDir = Environment.CurrentDirectory;
string tempfile = Path.Combine(outDir, "tmp" + Guid.NewGuid().ToString());
string packUri = string.Format(url, system.ShortName());
// Make the call to get the pack
string remoteFileName = await DownloadFile(packUri, tempfile);
MoveOrDelete(tempfile, remoteFileName, outDir, subfolder);
return true;
}
catch (Exception ex)
{
Console.WriteLine($"An exception has occurred: {ex}");
return false;
}
}
/// <summary>
/// Download an individual site ID data, if possible
/// </summary>
/// <param name="id">Redump disc ID to retrieve</param>
/// <returns>String containing the page contents if successful, null on error</returns>
public async Task<string> DownloadSingleSiteID(int id)
{
string paddedId = id.ToString().PadLeft(5, '0');
Console.WriteLine($"Processing ID: {paddedId}");
try
{
// Try up to 3 times to retrieve the data
string discPageUri = string.Format(Constants.DiscPageUrl, +id);
string discPage = await DownloadString(discPageUri, retries: 3);
if (discPage == null || discPage.Contains($"Disc with ID \"{id}\" doesn't exist"))
{
Console.WriteLine($"ID {paddedId} could not be found!");
return null;
}
Console.WriteLine($"ID {paddedId} has been successfully downloaded");
return discPage;
}
catch (Exception ex)
{
Console.WriteLine($"An exception has occurred: {ex}");
return null;
}
}
/// <summary>
/// Download an individual site ID data, if possible
/// </summary>
/// <param name="id">Redump disc ID to retrieve</param>
/// <param name="outDir">Output directory to save data to</param>
/// <param name="rename">True to rename deleted entries, false otherwise</param>
/// <returns>True if all data was downloaded, false otherwise</returns>
public async Task<bool> DownloadSingleSiteID(int id, string outDir, bool rename)
{
// If no output directory is defined, use the current directory instead
if (string.IsNullOrWhiteSpace(outDir))
outDir = Environment.CurrentDirectory;
string paddedId = id.ToString().PadLeft(5, '0');
string paddedIdDir = Path.Combine(outDir, paddedId);
Console.WriteLine($"Processing ID: {paddedId}");
try
{
// Try up to 3 times to retrieve the data
string discPageUri = string.Format(Constants.DiscPageUrl, +id);
string discPage = await DownloadString(discPageUri, retries: 3);
if (discPage == null || discPage.Contains($"Disc with ID \"{id}\" doesn't exist"))
{
try
{
if (rename)
{
if (Directory.Exists(paddedIdDir) && rename)
Directory.Move(paddedIdDir, paddedIdDir + "-deleted");
else
Directory.CreateDirectory(paddedIdDir + "-deleted");
}
}
catch { }
Console.WriteLine($"ID {paddedId} could not be found!");
return false;
}
// Check if the page has been updated since the last time it was downloaded, if possible
if (File.Exists(Path.Combine(paddedIdDir, "disc.html")))
{
// Read in the cached file
var oldDiscPage = File.ReadAllText(Path.Combine(paddedIdDir, "disc.html"));
// Check for the last modified date in both pages
var oldResult = Constants.LastModifiedRegex.Match(oldDiscPage);
var newResult = Constants.LastModifiedRegex.Match(discPage);
// If both pages contain the same modified date, skip it
if (oldResult.Success && newResult.Success && oldResult.Groups[1].Value == newResult.Groups[1].Value)
{
Console.WriteLine($"ID {paddedId} has not been changed since last download");
return false;
}
// If neither page contains a modified date, skip it
else if (!oldResult.Success && !newResult.Success)
{
Console.WriteLine($"ID {paddedId} has not been changed since last download");
return false;
}
}
// Create ID subdirectory
Directory.CreateDirectory(paddedIdDir);
// View Edit History
if (discPage.Contains($"<a href=\"/disc/{id}/changes/\""))
_ = await DownloadFile(string.Format(Constants.DiscPageUrl, +id) + Constants.ChangesExt, Path.Combine(paddedIdDir, "changes.html"));
// CUE
if (discPage.Contains($"<a href=\"/disc/{id}/cue/\""))
_ = await DownloadFile(string.Format(Constants.DiscPageUrl, +id) + Constants.CueExt, Path.Combine(paddedIdDir, paddedId + ".cue"));
// Edit disc
if (discPage.Contains($"<a href=\"/disc/{id}/edit/\""))
_ = await DownloadFile(string.Format(Constants.DiscPageUrl, +id) + Constants.EditExt, Path.Combine(paddedIdDir, "edit.html"));
// GDI
if (discPage.Contains($"<a href=\"/disc/{id}/gdi/\""))
_ = await DownloadFile(string.Format(Constants.DiscPageUrl, +id) + Constants.GdiExt, Path.Combine(paddedIdDir, paddedId + ".gdi"));
// KEYS
if (discPage.Contains($"<a href=\"/disc/{id}/key/\""))
_ = await DownloadFile(string.Format(Constants.DiscPageUrl, +id) + Constants.KeyExt, Path.Combine(paddedIdDir, paddedId + ".key"));
// LSD
if (discPage.Contains($"<a href=\"/disc/{id}/lsd/\""))
_ = await DownloadFile(string.Format(Constants.DiscPageUrl, +id) + Constants.LsdExt, Path.Combine(paddedIdDir, paddedId + ".lsd"));
// MD5
if (discPage.Contains($"<a href=\"/disc/{id}/md5/\""))
_ = await DownloadFile(string.Format(Constants.DiscPageUrl, +id) + Constants.Md5Ext, Path.Combine(paddedIdDir, paddedId + ".md5"));
// Review WIP entry
if (Constants.NewDiscRegex.IsMatch(discPage))
{
var match = Constants.NewDiscRegex.Match(discPage);
_ = await DownloadFile(string.Format(Constants.WipDiscPageUrl, match.Groups[2].Value), Path.Combine(paddedIdDir, "newdisc.html"));
}
// SBI
if (discPage.Contains($"<a href=\"/disc/{id}/sbi/\""))
_ = await DownloadFile(string.Format(Constants.DiscPageUrl, +id) + Constants.SbiExt, Path.Combine(paddedIdDir, paddedId + ".sbi"));
// SFV
if (discPage.Contains($"<a href=\"/disc/{id}/sfv/\""))
await DownloadFile(string.Format(Constants.DiscPageUrl, +id) + Constants.SfvExt, Path.Combine(paddedIdDir, paddedId + ".sfv"));
// SHA1
if (discPage.Contains($"<a href=\"/disc/{id}/sha1/\""))
_ = await DownloadFile(string.Format(Constants.DiscPageUrl, +id) + Constants.Sha1Ext, Path.Combine(paddedIdDir, paddedId + ".sha1"));
// HTML (Last in case of errors)
using (var discStreamWriter = File.CreateText(Path.Combine(paddedIdDir, "disc.html")))
{
discStreamWriter.Write(discPage);
}
Console.WriteLine($"ID {paddedId} has been successfully downloaded");
return true;
}
catch (Exception ex)
{
Console.WriteLine($"An exception has occurred: {ex}");
return false;
}
}
/// <summary>
/// Download an individual WIP ID data, if possible
/// </summary>
/// <param name="id">Redump WIP disc ID to retrieve</param>
/// <returns>String containing the page contents if successful, null on error</returns>
public async Task<string> DownloadSingleWIPID(int id)
{
string paddedId = id.ToString().PadLeft(5, '0');
Console.WriteLine($"Processing ID: {paddedId}");
try
{
// Try up to 3 times to retrieve the data
string discPageUri = string.Format(Constants.WipDiscPageUrl, +id);
string discPage = await DownloadString(discPageUri, retries: 3);
if (discPage == null || discPage.Contains($"WIP disc with ID \"{id}\" doesn't exist"))
{
Console.WriteLine($"ID {paddedId} could not be found!");
return null;
}
Console.WriteLine($"ID {paddedId} has been successfully downloaded");
return discPage;
}
catch (Exception ex)
{
Console.WriteLine($"An exception has occurred: {ex}");
return null;
}
}
/// <summary>
/// Download an individual WIP ID data, if possible
/// </summary>
/// <param name="id">Redump WIP disc ID to retrieve</param>
/// <param name="outDir">Output directory to save data to</param>
/// <param name="rename">True to rename deleted entries, false otherwise</param>
/// <returns>True if all data was downloaded, false otherwise</returns>
public async Task<bool> DownloadSingleWIPID(int id, string outDir, bool rename)
{
// If no output directory is defined, use the current directory instead
if (string.IsNullOrWhiteSpace(outDir))
outDir = Environment.CurrentDirectory;
string paddedId = id.ToString().PadLeft(5, '0');
string paddedIdDir = Path.Combine(outDir, paddedId);
Console.WriteLine($"Processing ID: {paddedId}");
try
{
// Try up to 3 times to retrieve the data
string discPageUri = string.Format(Constants.WipDiscPageUrl, +id);
string discPage = await DownloadString(discPageUri, retries: 3);
if (discPage == null || discPage.Contains($"WIP disc with ID \"{id}\" doesn't exist"))
{
try
{
if (rename)
{
if (Directory.Exists(paddedIdDir) && rename)
Directory.Move(paddedIdDir, paddedIdDir + "-deleted");
else
Directory.CreateDirectory(paddedIdDir + "-deleted");
}
}
catch { }
Console.WriteLine($"ID {paddedId} could not be found!");
return false;
}
// Check if the page has been updated since the last time it was downloaded, if possible
if (File.Exists(Path.Combine(paddedIdDir, "disc.html")))
{
// Read in the cached file
var oldDiscPage = File.ReadAllText(Path.Combine(paddedIdDir, "disc.html"));
// Check for the full match ID in both pages
var oldResult = Constants.FullMatchRegex.Match(oldDiscPage);
var newResult = Constants.FullMatchRegex.Match(discPage);
// If both pages contain the same ID, skip it
if (oldResult.Success && newResult.Success && oldResult.Groups[1].Value == newResult.Groups[1].Value)
{
Console.WriteLine($"ID {paddedId} has not been changed since last download");
return false;
}
// If neither page contains an ID, skip it
else if (!oldResult.Success && !newResult.Success)
{
Console.WriteLine($"ID {paddedId} has not been changed since last download");
return false;
}
}
// Create ID subdirectory
Directory.CreateDirectory(paddedIdDir);
// HTML
using (var discStreamWriter = File.CreateText(Path.Combine(paddedIdDir, "disc.html")))
{
discStreamWriter.Write(discPage);
}
Console.WriteLine($"ID {paddedId} has been successfully downloaded");
return true;
}
catch (Exception ex)
{
Console.WriteLine($"An exception has occurred: {ex}");
return false;
}
}
#endregion
#region Helpers
/// <summary>
/// Download a set of packs
/// </summary>
/// <param name="url">Base URL to download using</param>
/// <param name="system">Systems to download packs for</param>
/// <param name="title">Name of the pack that is downloading</param>
public async Task<Dictionary<RedumpSystem, byte[]>> DownloadPacks(string url, RedumpSystem?[] systems, string title)
{
var packsDictionary = new Dictionary<RedumpSystem, byte[]>();
Console.WriteLine($"Downloading {title}");
foreach (var system in systems)
{
// If the system is invalid, we can't do anything
if (system == null || !system.IsAvailable())
continue;
// If we didn't have credentials
if (!LoggedIn && system.IsBanned())
continue;
// If the system is unknown, we can't do anything
string longName = system.LongName();
if (string.IsNullOrWhiteSpace(longName))
continue;
Console.Write($"\r{longName}{new string(' ', Console.BufferWidth - longName.Length - 1)}");
byte[] pack = await DownloadSinglePack(url, system);
if (pack != null)
packsDictionary.Add(system.Value, pack);
}
Console.Write($"\rComplete!{new string(' ', Console.BufferWidth - 10)}");
Console.WriteLine();
return packsDictionary;
}
/// <summary>
/// Download a set of packs
/// </summary>
/// <param name="url">Base URL to download using</param>
/// <param name="systems">Systems to download packs for</param>
/// <param name="title">Name of the pack that is downloading</param>
/// <param name="outDir">Output directory to save data to</param>
/// <param name="subfolder">Named subfolder for the pack, used optionally</param>
public async Task<bool> DownloadPacks(string url, RedumpSystem?[] systems, string title, string outDir, string subfolder)
{
Console.WriteLine($"Downloading {title}");
foreach (var system in systems)
{
// If the system is invalid, we can't do anything
if (system == null || !system.IsAvailable())
continue;
// If we didn't have credentials
if (!LoggedIn && system.IsBanned())
continue;
// If the system is unknown, we can't do anything
string longName = system.LongName();
if (string.IsNullOrWhiteSpace(longName))
continue;
Console.Write($"\r{longName}{new string(' ', Console.BufferWidth - longName.Length - 1)}");
await DownloadSinglePack(url, system, outDir, subfolder);
}
Console.Write($"\rComplete!{new string(' ', Console.BufferWidth - 10)}");
Console.WriteLine();
return true;
}
/// <summary>
/// Download from a URI to a local file
/// </summary>
/// <param name="uri">Remote URI to retrieve</param>
/// <param name="fileName">Filename to write to</param>
/// <returns>The remote filename from the URI, null on error</returns>
private async Task<string> DownloadFile(string uri, string fileName)
{
// Make the call to get the file
var response = await GetAsync(uri);
if (response?.Content?.Headers == null || !response.IsSuccessStatusCode)
{
Console.WriteLine($"Could not download {uri}");
return null;
}
// Copy the data to a local temp file
using (var responseStream = await response.Content.ReadAsStreamAsync())
using (var tempFileStream = File.OpenWrite(fileName))
{
responseStream.CopyTo(tempFileStream);
}
return response.Content.Headers.ContentDisposition?.FileName?.Replace("\"", "");
}
/// <summary>
/// Download from a URI to a string
/// </summary>
/// <param name="uri">Remote URI to retrieve</param>
/// <param name="retries">Number of times to retry on error</param>
/// <returns>String from the URI, null on error</returns>
private async Task<string> DownloadString(string uri, int retries = 3)
{
// Only retry a positive number of times
if (retries <= 0)
return null;
for (int i = 0; i < retries; i++)
{
try
{
return await GetStringAsync(uri);
}
catch { }
}
return null;
}
/// <summary>
/// Move a tempfile to a new name unless it aleady exists, in which case, delete the tempfile
/// </summary>
/// <param name="tempfile">Path to existing temporary file</param>
/// <param name="newfile">Path to new output file</param>
/// <param name="outDir">Output directory to save data to</param>
/// <param name="subfolder">Optional subfolder to append to the path</param>
private static void MoveOrDelete(string tempfile, string newfile, string outDir, string subfolder)
{
// If we don't have a file to move to, just delete the temp file
if (string.IsNullOrWhiteSpace(newfile))
{
File.Delete(tempfile);
return;
}
// If we have a subfolder, create it and update the newfile name
if (!string.IsNullOrWhiteSpace(subfolder))
{
if (!Directory.Exists(Path.Combine(outDir, subfolder)))
Directory.CreateDirectory(Path.Combine(outDir, subfolder));
newfile = Path.Combine(subfolder, newfile);
}
// If the file already exists, don't overwrite it
if (File.Exists(Path.Combine(outDir, newfile)))
File.Delete(tempfile);
else
File.Move(tempfile, Path.Combine(outDir, newfile));
}
#endregion
}
}
#endif

View File

@@ -1,4 +1,6 @@
using System;
#if NET48 || NETSTANDARD2_1
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
@@ -32,29 +34,58 @@ namespace RedumpLib.Web
// If the response headers are null or empty
if (ResponseHeaders == null || ResponseHeaders.Count == 0)
return null;
// If we don't have the response header we care about
string headerValue = ResponseHeaders.Get("Content-Disposition");
if (string.IsNullOrWhiteSpace(headerValue))
return null;
// Extract the filename from the value
#if NETSTANDARD2_1
return headerValue[(headerValue.IndexOf("filename=") + 9)..].Replace("\"", "");
#else
return headerValue.Substring(headerValue.IndexOf("filename=") + 9).Replace("\"", "");
#endif
}
/// <inheritdoc/>
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
HttpWebRequest webRequest = request as HttpWebRequest;
if (webRequest != null)
{
if (request is HttpWebRequest webRequest)
webRequest.CookieContainer = m_container;
}
return request;
}
/// <summary>
/// Validate supplied credentials
/// </summary>
public static (bool?, string) ValidateCredentials(string username, string password)
{
// If options are invalid or we're missing something key, just return
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
return (false, null);
// Try logging in with the supplied credentials otherwise
#if NETSTANDARD2_1
using RedumpWebClient wc = new RedumpWebClient();
#else
using (RedumpWebClient wc = new RedumpWebClient())
{
#endif
bool? loggedIn = wc.Login(username, password);
if (loggedIn == true)
return (true, "Redump username and password accepted!");
else if (loggedIn == false)
return (false, "Redump username and password denied!");
else
return (null, "An error occurred validating your credentials!");
#if NET48
}
#endif
}
/// <summary>
/// Login to Redump, if possible
/// </summary>
@@ -502,7 +533,7 @@ namespace RedumpLib.Web
// View Edit History
if (discPage.Contains($"<a href=\"/disc/{id}/changes/\""))
DownloadFile(string.Format(Constants.DiscPageUrl, +id) + Constants.ChangesExt, Path.Combine(paddedIdDir, "changes.html"));
// CUE
if (discPage.Contains($"<a href=\"/disc/{id}/cue/\""))
DownloadFile(string.Format(Constants.DiscPageUrl, +id) + Constants.CueExt, Path.Combine(paddedIdDir, paddedId + ".cue"));
@@ -719,7 +750,7 @@ namespace RedumpLib.Web
// If we didn't have credentials
if (!LoggedIn && system.IsBanned())
continue;
// If the system is unknown, we can't do anything
string longName = system.LongName();
if (string.IsNullOrWhiteSpace(longName))
@@ -765,7 +796,7 @@ namespace RedumpLib.Web
Console.Write($"\r{longName}{new string(' ', Console.BufferWidth - longName.Length - 1)}");
DownloadSinglePack(url, system, outDir, subfolder);
}
}
Console.Write($"\rComplete!{new string(' ', Console.BufferWidth - 10)}");
Console.WriteLine();
@@ -778,7 +809,7 @@ namespace RedumpLib.Web
/// <param name="newfile">Path to new output file</param>
/// <param name="outDir">Output directory to save data to</param>
/// <param name="subfolder">Optional subfolder to append to the path</param>
private void MoveOrDelete(string tempfile, string newfile, string outDir, string subfolder)
private static void MoveOrDelete(string tempfile, string newfile, string outDir, string subfolder)
{
if (!string.IsNullOrWhiteSpace(newfile))
{
@@ -802,3 +833,5 @@ namespace RedumpLib.Web
#endregion
}
}
#endif

View File

@@ -1,76 +1,125 @@
# version format
version: 2.3-{build}
version: 2.6.2-{build}
# pull request template
pull_requests:
do_not_increment_build_number: true
# vm template
image: Visual Studio 2019
image: Visual Studio 2022
# environment variables
environment:
EnableNuGetPackageRestore: true
# msbuild configuration
platform:
- Any CPU
configuration:
- Debug
# install dependencies
install:
- ps: appveyor DownloadFile https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
- cd %APPVEYOR_BUILD_FOLDER%
- git submodule update --init --recursive
# pre-build script
before_build:
- nuget restore
# build step
build:
verbosity: minimal
project: MPF.sln
build_script:
- dotnet restore
# .NET Framework 4.8
- msbuild MPF\MPF.csproj -target:Publish -property:TargetFramework=net48 -property:RuntimeIdentifiers=win7-x64
- msbuild MPF.Check\MPF.Check.csproj -target:Publish -property:TargetFramework=net48 -property:RuntimeIdentifiers=win7-x64
# .NET 6.0
- dotnet publish MPF\MPF.csproj --framework net6.0-windows --runtime win7-x64 --self-contained true -p:PublishSingleFile=true
- dotnet publish MPF\MPF.csproj --framework net6.0-windows --runtime win8-x64 --self-contained true -p:PublishSingleFile=true
- dotnet publish MPF\MPF.csproj --framework net6.0-windows --runtime win81-x64 --self-contained true -p:PublishSingleFile=true
- dotnet publish MPF\MPF.csproj --framework net6.0-windows --runtime win10-x64 --self-contained true -p:PublishSingleFile=true
- dotnet publish MPF.Check\MPF.Check.csproj --framework net6.0 --runtime win7-x64 --self-contained true -p:PublishSingleFile=true
- dotnet publish MPF.Check\MPF.Check.csproj --framework net6.0 --runtime win8-x64 --self-contained true -p:PublishSingleFile=true
- dotnet publish MPF.Check\MPF.Check.csproj --framework net6.0 --runtime win81-x64 --self-contained true -p:PublishSingleFile=true
- dotnet publish MPF.Check\MPF.Check.csproj --framework net6.0 --runtime win10-x64 --self-contained true -p:PublishSingleFile=true
- dotnet publish MPF.Check\MPF.Check.csproj --framework net6.0 --runtime linux-x64 --self-contained true -p:PublishSingleFile=true
- dotnet publish MPF.Check\MPF.Check.csproj --framework net6.0 --runtime osx-x64 --self-contained true -p:PublishSingleFile=true
# post-build step
after_build:
- ps: appveyor DownloadFile https://github.com/aaru-dps/Aaru/releases/download/v5.3.0/aaru-5.3.0_windows_x64.zip
# Aaru
- ps: appveyor DownloadFile https://github.com/aaru-dps/Aaru/releases/download/v5.3.2/aaru-5.3.2_windows_x64.zip
- 7z x aaru-5.3.2_windows_x64.zip -oMPF\bin\Debug\net48\publish\Programs\Aaru *
- 7z x aaru-5.3.2_windows_x64.zip -oMPF\bin\Debug\net6.0-windows\win7-x64\publish\Programs\Aaru *
- 7z x aaru-5.3.2_windows_x64.zip -oMPF\bin\Debug\net6.0-windows\win8-x64\publish\Programs\Aaru *
- 7z x aaru-5.3.2_windows_x64.zip -oMPF\bin\Debug\net6.0-windows\win81-x64\publish\Programs\Aaru *
- 7z x aaru-5.3.2_windows_x64.zip -oMPF\bin\Debug\net6.0-windows\win10-x64\publish\Programs\Aaru *
# dd for Windows
- ps: appveyor DownloadFile http://www.chrysocome.net/downloads/8ab730cd2a29e76ddd89be1f99357942/dd-0.6beta3.zip
- ps: appveyor DownloadFile https://github.com/saramibreak/DiscImageCreator/files/7453967/DiscImageCreator_20211101.zip
- 7z e dd-0.6beta3.zip -oMPF\bin\Debug\net48\publish\Programs\DD *
- 7z e dd-0.6beta3.zip -oMPF\bin\Debug\net6.0-windows\win7-x64\publish\Programs\DD *
- 7z e dd-0.6beta3.zip -oMPF\bin\Debug\net6.0-windows\win8-x64\publish\Programs\DD *
- 7z e dd-0.6beta3.zip -oMPF\bin\Debug\net6.0-windows\win81-x64\publish\Programs\DD *
- 7z e dd-0.6beta3.zip -oMPF\bin\Debug\net6.0-windows\win10-x64\publish\Programs\DD *
# DiscImageCreator
- ps: appveyor DownloadFile https://github.com/saramibreak/DiscImageCreator/files/11660558/DiscImageCreator_20230606.zip
- 7z e DiscImageCreator_20230606.zip -oMPF\bin\Debug\net48\publish\Programs\Creator Release_ANSI\*
- 7z e DiscImageCreator_20230606.zip -oMPF\bin\Debug\net6.0-windows\win7-x64\publish\Programs\Creator Release_ANSI\*
- 7z e DiscImageCreator_20230606.zip -oMPF\bin\Debug\net6.0-windows\win8-x64\publish\Programs\Creator Release_ANSI\*
- 7z e DiscImageCreator_20230606.zip -oMPF\bin\Debug\net6.0-windows\win81-x64\publish\Programs\Creator Release_ANSI\*
- 7z e DiscImageCreator_20230606.zip -oMPF\bin\Debug\net6.0-windows\win10-x64\publish\Programs\Creator Release_ANSI\*
# Redumper
- ps: appveyor DownloadFile https://github.com/superg/redumper/releases/download/build_183/redumper-2023.07.09_build183-win64.zip
- 7z e redumper-2023.07.09_build183-win64.zip -oMPF\bin\Debug\net48\publish\Programs\Redumper redumper-2023.07.09_build183-win64\bin\*
- 7z e redumper-2023.07.09_build183-win64.zip -oMPF\bin\Debug\net6.0-windows\win7-x64\publish\Programs\Redumper redumper-2023.07.09_build183-win64\bin\*
- 7z e redumper-2023.07.09_build183-win64.zip -oMPF\bin\Debug\net6.0-windows\win8-x64\publish\Programs\Redumper redumper-2023.07.09_build183-win64\bin\*
- 7z e redumper-2023.07.09_build183-win64.zip -oMPF\bin\Debug\net6.0-windows\win81-x64\publish\Programs\Redumper redumper-2023.07.09_build183-win64\bin\*
- 7z e redumper-2023.07.09_build183-win64.zip -oMPF\bin\Debug\net6.0-windows\win10-x64\publish\Programs\Redumper redumper-2023.07.09_build183-win64\bin\*
# Subdump
- ps: appveyor DownloadFile https://archive.org/download/subdump_fua_0x28/subdump_fua_0x28.zip
- 7z e subdump_fua_0x28.zip -oMPF\bin\Debug\net48\publish *
- mkdir MPF\bin\Debug\net48\publish\Programs\Subdump
- mv MPF\bin\Debug\net48\publish\subdump_fua_0x28.exe MPF\bin\Debug\net48\publish\Programs\Subdump\subdump.exe
- 7z e subdump_fua_0x28.zip -oMPF\bin\Debug\net6.0-windows *
- mkdir MPF\bin\Debug\net6.0-windows\win7-x64\publish\Programs\Subdump
- mv MPF\bin\Debug\net6.0-windows\subdump_fua_0x28.exe MPF\bin\Debug\net6.0-windows\win7-x64\publish\Programs\Subdump\subdump.exe
- 7z e subdump_fua_0x28.zip -oMPF\bin\Debug\net6.0-windows *
- mkdir MPF\bin\Debug\net6.0-windows\win8-x64\publish\Programs\Subdump
- mv MPF\bin\Debug\net6.0-windows\subdump_fua_0x28.exe MPF\bin\Debug\net6.0-windows\win8-x64\publish\Programs\Subdump\subdump.exe
- 7z e subdump_fua_0x28.zip -oMPF\bin\Debug\net6.0-windows *
- mkdir MPF\bin\Debug\net6.0-windows\win81-x64\publish\Programs\Subdump
- mv MPF\bin\Debug\net6.0-windows\subdump_fua_0x28.exe MPF\bin\Debug\net6.0-windows\win81-x64\publish\Programs\Subdump\subdump.exe
- 7z e subdump_fua_0x28.zip -oMPF\bin\Debug\net6.0-windows *
- mkdir MPF\bin\Debug\net6.0-windows\win10-x64\publish\Programs\Subdump
- mv MPF\bin\Debug\net6.0-windows\subdump_fua_0x28.exe MPF\bin\Debug\net6.0-windows\win10-x64\publish\Programs\Subdump\subdump.exe
- 7z x aaru-5.3.0_windows_x64.zip -oMPF\bin\Debug\net48\Programs\Aaru *
#- 7z x aaru-5.3.0_windows_x64.zip -oMPF\bin\Debug\netcoreapp3.1\Programs\Aaru *
#- 7z x aaru-5.3.0_windows_x64.zip -oMPF\bin\Debug\net5.0\Programs\Aaru *
# MPF
- cd %APPVEYOR_BUILD_FOLDER%\MPF\bin\Debug\net48\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF_net48.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF\bin\Debug\net6.0-windows\win7-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF_net6.0_win7-x64.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF\bin\Debug\net6.0-windows\win8-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF_net6.0_win8-x64.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF\bin\Debug\net6.0-windows\win81-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF_net6.0_win81-x64.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF\bin\Debug\net6.0-windows\win10-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF_net6.0_win10-x64.zip *
- 7z e dd-0.6beta3.zip -oMPF\bin\Debug\net48\Programs\DD *
#- 7z e dd-0.6beta3.zip -oMPF\bin\Debug\netcoreapp3.1\Programs\DD *
#- 7z e dd-0.6beta3.zip -oMPF\bin\Debug\net5.0\Programs\DD *
- 7z e DiscImageCreator_20211101.zip -oMPF\bin\Debug\net48\Programs\Creator Release_ANSI\*
#- 7z e DiscImageCreator_20211101.zip -oMPF\bin\Debug\netcoreapp3.1\Programs\Creator Release_ANSI\*
#- 7z e DiscImageCreator_20211101.zip -oMPF\bin\Debug\net5.0\Programs\Creator Release_ANSI\*
- 7z e subdump_fua_0x28.zip -oMPF\bin\Debug\net48 *
- mkdir MPF\bin\Debug\net48\Programs\Subdump
- mv MPF\bin\Debug\net48\subdump_fua_0x28.exe MPF\bin\Debug\net48\Programs\Subdump\subdump.exe
#- 7z e subdump_fua_0x28.zip -oMPF\bin\Debug\netcoreapp3.1 *
#- mkdir MPF\bin\Debug\netcoreapp3.1\Programs\Subdump
#- mv MPF\bin\Debug\netcoreapp3.1\subdump_fua_0x28.exe MPF\bin\Debug\netcoreapp3.1\Programs\Subdump\subdump.exe
#- 7z e subdump_fua_0x28.zip -oMPF\bin\Debug\net5.0 *
#- mkdir MPF\bin\Debug\net5.0\Programs\Subdump
#- mv MPF\bin\Debug\net5.0\subdump_fua_0x28.exe MPF\bin\Debug\net5.0\Programs\Subdump\subdump.exe
- cd MPF\bin\Debug
- 7z a MPF_net48.zip net48\*
#- 7z a MPF_netcoreapp3.1.zip netcoreapp3.1\*
#- 7z a MPF_net5.0.zip net5.0\*
- cd ..\..\..\MPF.Check\bin\Debug
- 7z a MPF-Check_net48.zip net48\*
#- 7z a MPF-Check_netcoreapp3.1.zip netcoreapp3.1\*
#- 7z a MPF-Check_net5.0.zip net5.0\*
# MPF.Check
- cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Debug\net48\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_net48.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Debug\net6.0\win7-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_net6.0_win7-x64.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Debug\net6.0\win8-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_net6.0_win8-x64.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Debug\net6.0\win81-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_net6.0_win81-x64.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Debug\net6.0\win10-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_net6.0_win10-x64.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Debug\net6.0\linux-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_net6.0_linux-x64.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Debug\net6.0\osx-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_net6.0_osx-x64.zip *
# success/failure tracking
on_success:
@@ -82,16 +131,28 @@ on_failure:
# artifact linking
artifacts:
- path: MPF\bin\Debug\MPF_net48.zip
name: MPF (WPF UI) (.NET Framework 4.8)
#- path: MPF\bin\Debug\MPF_netcoreapp3.1.zip
# name: MPF (WPF UI) (.NET Core 3.1)
#- path: MPF\bin\Debug\MPF_net5.0.zip
# name: MPF (WPF UI) (.NET 5.0)
- path: MPF_net48.zip
name: MPF (.NET Framework 4.8)
- path: MPF_net6.0_win7-x64.zip
name: MPF (.NET 6.0, Windows 7 x64)
- path: MPF_net6.0_win8-x64.zip
name: MPF (.NET 6.0, Windows 8 x64)
- path: MPF_net6.0_win81-x64.zip
name: MPF (.NET 6.0, Windows 8.1 x64)
- path: MPF_net6.0_win10-x64.zip
name: MPF (.NET 6.0, Windows 10 x64)
- path: MPF.Check\bin\Debug\MPF-Check_net48.zip
- path: MPF.Check_net48.zip
name: MPF Check (.NET Framework 4.8)
#- path: MPF.Check\bin\Debug\MPF-Check_netcoreapp3.1.zip
# name: MPF Check (.NET Core 3.1)
#- path: MPF.Check\bin\Debug\MPF-Check_net5.0.zip
# name: MPF Check (.NET 5.0)
- path: MPF.Check_net6.0_win7-x64.zip
name: MPF.Check (.NET 6.0, Windows 7 x64)
- path: MPF.Check_net6.0_win8-x64.zip
name: MPF.Check (.NET 6.0, Windows 8 x64)
- path: MPF.Check_net6.0_win81-x64.zip
name: MPF.Check (.NET 6.0, Windows 8.1 x64)
- path: MPF.Check_net6.0_win10-x64.zip
name: MPF.Check (.NET 6.0, Windows 10 x64)
- path: MPF.Check_net6.0_linux-x64.zip
name: MPF.Check (.NET 6.0, Linux x64)
- path: MPF.Check_net6.0_osx-x64.zip
name: MPF.Check (.NET 6.0, OSX x64)

57
publish-nix.sh Executable file
View File

@@ -0,0 +1,57 @@
#! /bin/bash
# This batch file assumes the following:
# - .NET 6.0 (or newer) SDK is installed and in PATH
# - zip is installed and in PATH
# - The relevant commandline programs are already downloaded
# and put into their respective folders
#
# If any of these are not satisfied, the operation may fail
# in an unpredictable way and result in an incomplete output.
# TODO: Re-enable MPF building after figuring out how to build Windows desktop applications on Linux
# This may require an additional package to be installed?
# Set the current directory as a variable
BUILD_FOLDER=$PWD
# Restore Nuget packages for all builds
echo "Restoring Nuget packages"
dotnet restore
# .NET 6.0
echo "Building .NET 6.0 releases"
#dotnet publish MPF/MPF.csproj --framework net6.0-windows --runtime win7-x64 --self-contained true -p:PublishSingleFile=true
#dotnet publish MPF/MPF.csproj --framework net6.0-windows --runtime win8-x64 --self-contained true -p:PublishSingleFile=true
#dotnet publish MPF/MPF.csproj --framework net6.0-windows --runtime win81-x64 --self-contained true -p:PublishSingleFile=true
#dotnet publish MPF/MPF.csproj --framework net6.0-windows --runtime win10-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check/MPF.Check.csproj --framework net6.0 --runtime win7-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check/MPF.Check.csproj --framework net6.0 --runtime win8-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check/MPF.Check.csproj --framework net6.0 --runtime win81-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check/MPF.Check.csproj --framework net6.0 --runtime win10-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check/MPF.Check.csproj --framework net6.0 --runtime linux-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check/MPF.Check.csproj --framework net6.0 --runtime osx-x64 --self-contained true -p:PublishSingleFile=true
# Create MPF archives
#cd $BUILD_FOLDER/MPF/bin/Debug/net6.0-windows/win7-x64/publish/
#zip -r $BUILD_FOLDER/MPF_net6.0_win7-x64.zip .
#cd $BUILD_FOLDER/MPF/bin/Debug/net6.0-windows/win8-x64/publish/
#zip -r $BUILD_FOLDER/MPF_net6.0_win8-x64.zip .
#cd $BUILD_FOLDER/MPF/bin/Debug/net6.0-windows/win81-x64/publish/
#zip -r $BUILD_FOLDER/MPF_net6.0_win81-x64.zip .
#cd $BUILD_FOLDER/MPF/bin/Debug/net6.0-windows/win10-x64/publish/
#zip -r $BUILD_FOLDER/MPF_net6.0_win10-x64.zip .
# Create MPF.Check archives
cd $BUILD_FOLDER/MPF.Check/bin/Debug/net6.0/win7-x64/publish/
zip -r $BUILD_FOLDER/MPF.Check_net6.0_win7-x64.zip .
cd $BUILD_FOLDER/MPF.Check/bin/Debug/net6.0/win8-x64/publish/
zip -r $BUILD_FOLDER/MPF.Check_net6.0_win8-x64.zip .
cd $BUILD_FOLDER/MPF.Check/bin/Debug/net6.0/win81-x64/publish/
zip -r $BUILD_FOLDER/MPF.Check_net6.0_win81-x64.zip .
cd $BUILD_FOLDER/MPF.Check/bin/Debug/net6.0/win10-x64/publish/
zip -r $BUILD_FOLDER/MPF.Check_net6.0_win10-x64.zip .
cd $BUILD_FOLDER/MPF.Check/bin/Debug/net6.0/linux-x64/publish/
zip -r $BUILD_FOLDER/MPF.Check_net6.0_linux-x64.zip .
cd $BUILD_FOLDER/MPF.Check/bin/Debug/net6.0/osx-x64/publish/
zip -r $BUILD_FOLDER/MPF.Check_net6.0_osx-x64.zip .

64
publish-win.bat Normal file
View File

@@ -0,0 +1,64 @@
@echo OFF
REM This batch file assumes the following:
REM - .NET Framework 4.8 SDK is installed and in PATH
REM - .NET 6.0 (or newer) SDK is installed and in PATH
REM - 7-zip commandline (7z.exe) is installed and in PATH
REM - The relevant commandline programs are already downloaded
REM and put into their respective folders
REM
REM If any of these are not satisfied, the operation may fail
REM in an unpredictable way and result in an incomplete output.
REM Set the current directory as a variable
set BUILD_FOLDER=%~dp0
REM Restore Nuget packages for all builds
echo Restoring Nuget packages
dotnet restore
REM .NET Framework 4.8
echo Building .NET Framework 4.8 releases
msbuild MPF\MPF.csproj -target:Publish -property:TargetFramework=net48 -property:RuntimeIdentifiers=win7-x64
msbuild MPF.Check\MPF.Check.csproj -target:Publish -property:TargetFramework=net48 -property:RuntimeIdentifiers=win7-x64
REM .NET 6.0
echo Building .NET 6.0 releases
dotnet publish MPF\MPF.csproj --framework net6.0-windows --runtime win7-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF\MPF.csproj --framework net6.0-windows --runtime win8-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF\MPF.csproj --framework net6.0-windows --runtime win81-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF\MPF.csproj --framework net6.0-windows --runtime win10-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj --framework net6.0 --runtime win7-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj --framework net6.0 --runtime win8-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj --framework net6.0 --runtime win81-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj --framework net6.0 --runtime win10-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj --framework net6.0 --runtime linux-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj --framework net6.0 --runtime osx-x64 --self-contained true -p:PublishSingleFile=true
REM Create MPF archives
cd %BUILD_FOLDER%\MPF\bin\Debug\net48\publish\
7z a -tzip %BUILD_FOLDER%\MPF_net48.zip *
cd %BUILD_FOLDER%\MPF\bin\Debug\net6.0-windows\win7-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF_net6.0_win7-x64.zip *
cd %BUILD_FOLDER%\MPF\bin\Debug\net6.0-windows\win8-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF_net6.0_win8-x64.zip *
cd %BUILD_FOLDER%\MPF\bin\Debug\net6.0-windows\win81-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF_net6.0_win81-x64.zip *
cd %BUILD_FOLDER%\MPF\bin\Debug\net6.0-windows\win10-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF_net6.0_win10-x64.zip *
REM Create MPF.Check archives
cd %BUILD_FOLDER%\MPF.Check\bin\Debug\net48\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check_net48.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Debug\net6.0\win7-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check_net6.0_win7-x64.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Debug\net6.0\win8-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check_net6.0_win8-x64.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Debug\net6.0\win81-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check_net6.0_win81-x64.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Debug\net6.0\win10-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check_net6.0_win10-x64.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Debug\net6.0\linux-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check_net6.0_linux-x64.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Debug\net6.0\osx-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check_net6.0_osx-x64.zip *