Compare commits

...

1216 Commits

Author SHA1 Message Date
Matt Nadareski
299fafe1f8 Update changelog 2026-02-02 16:24:01 -05:00
Matt Nadareski
8f6305a7c4 Extend logging with a new state (fixes #944) 2026-02-02 16:23:48 -05:00
Matt Nadareski
3f61957715 Log the system being used, in case it came from config 2026-01-30 08:45:13 -05:00
Matt Nadareski
57750295fb Validate a system is provided for CLI applications 2026-01-29 20:36:56 -05:00
Matt Nadareski
286ec864ab Add unused Dreamdump execution context 2026-01-27 16:16:34 -05:00
Matt Nadareski
e4fd644c61 Split path creation in OptionsLoader 2026-01-27 15:07:22 -05:00
Matt Nadareski
7502d7e8df Update RedumpLib to 1.9.1 2026-01-27 14:02:54 -05:00
Matt Nadareski
439fb2717c Add MPRESS to packer filters (fixes #938) 2026-01-27 08:40:17 -05:00
Matt Nadareski
089ab1c4a2 Add editorconfig, fix issues 2026-01-25 18:09:00 -05:00
Deterous
89a50ea424 Update Redumper to build 683 (#933) 2026-01-04 20:13:35 -05:00
Matt Nadareski
740d867d7b Update DIC to 20260101 2026-01-03 21:57:14 -05:00
Matt Nadareski
83fa4852c9 Add default subfolder to CLI outputs 2026-01-01 10:21:19 -05:00
Deterous
ecc00a28c2 Update Redumper to build 681 (Dreamcast support) (#930)
* Update redumper to b678

* Update Redumper to build 681 (Dreamcast support)

* build 682
2025-12-26 21:24:02 -05:00
Matt Nadareski
2d90c849e1 Use default media type if not provided (fixes #925) 2025-12-22 10:10:49 -05:00
Deterous
1d065ffd48 Update Redumper to build 676 (rename asus flags to mediatek) (#927)
* Update Redumper to build 676 (rename asus flags to mediatek)

* Fix ToRedumperDriveType enum extension
2025-12-15 09:56:49 -05:00
Deterous
ca885c3b89 Update Redumper to build 671 (#924)
* Update Redumper to build 669

* Fix tests

* Bump to build 670

* Update to build 671

* Bump changelist

* Fix tests
2025-12-10 20:32:08 -05:00
Matt Nadareski
94fd614673 Check range-specific values in layerbreak 2025-12-02 08:36:57 -05:00
Matt Nadareski
9fc5799999 Check for null or empty layerbreak arrays 2025-12-02 08:30:33 -05:00
Matt Nadareski
61f90a635f Bump version 2025-11-28 09:53:54 -05:00
Matt Nadareski
8cc0ff3829 Reenable Zstd PKZIP outputs 2025-11-27 20:09:43 -05:00
Matt Nadareski
cac6bcc4de Add commented fix for Zstd PKZIP 2025-11-26 20:25:51 -05:00
Matt Nadareski
7ac0089e81 Disable Zstd PKZIP outputs 2025-11-25 19:38:30 -05:00
Matt Nadareski
48576b38be Update Redumper to build 665 2025-11-25 18:14:08 -05:00
Matt Nadareski
82dedf1ceb Add support for .NET 10 2025-11-25 09:14:46 -05:00
Matt Nadareski
395cded5ef Clarify the unmounted device case (fixes #921) 2025-11-24 13:14:24 -05:00
Deterous
a48f9d1c83 New Redumper Drive Pregap Start option (#920)
* Pregap start option

* Fix DriveType names

* Fix options window

* Update changelist
2025-11-24 09:18:28 -05:00
Matt Nadareski
3975003686 Update changelog 2025-11-18 18:42:28 -05:00
HeroponRikiBestest
4beae71511 Remove DPM identifier for StarForce Keyless (#918)
* Redump staff does not deem the DPM identifier useful, so clean it from the submissioninfo output

* Add test for sanitization of StarForce Keyless
2025-11-18 18:41:10 -05:00
Matt Nadareski
f0f41c86c5 Ensure volume label is trimmed if used in filenames 2025-11-14 09:14:14 -05:00
Matt Nadareski
b1b6eb2c9d Clean up informational issues 2025-11-11 15:52:26 -05:00
Matt Nadareski
29754b4c0e Name some type parameters 2025-11-11 12:06:30 -05:00
Matt Nadareski
35cda84308 Update Redumper to build 663 2025-11-10 20:37:41 -05:00
Matt Nadareski
a877397fe6 Path scan after image scan 2025-11-10 19:34:17 -05:00
Matt Nadareski
2f0471d596 Move and rename new protection scan method 2025-11-10 13:52:31 -05:00
Matt Nadareski
2037ded792 Scan multi-track images for protection 2025-11-10 13:37:23 -05:00
Matt Nadareski
5f1a68a5f5 Scan disc image if not multi-track 2025-11-10 13:27:54 -05:00
Matt Nadareski
87746c8677 Update packages 2025-11-10 13:17:10 -05:00
Matt Nadareski
2665c29918 Use dated default output filenames 2025-11-09 20:03:46 -05:00
Matt Nadareski
5637cf5201 Update Redumper to build 660 2025-11-07 22:06:20 -05:00
Matt Nadareski
eb1d000e4f Fix tests 2025-11-07 09:58:28 -05:00
Matt Nadareski
8db467128d Add DVD-Video to list of copy protection scanning systems 2025-11-07 09:52:49 -05:00
Deterous
dc90e2609d Pre-compress all skeletons for multi-track CDs (#915)
* Pre-compress all skeletons for multi-track CDs

* Gate behind file existing

* Full track path

* split

* if base path is root
2025-11-06 07:39:41 -05:00
Deterous
e96bd21f1d Update Redumper to build 658 (#914) 2025-11-05 20:04:20 -05:00
Matt Nadareski
693599b986 Clean up submission info use and log link text 2025-11-03 08:08:51 -05:00
Matt Nadareski
d482fe926c Fix issues with path assembly 2025-10-29 20:11:02 -04:00
Deterous
17b5432352 Fix langs (#913)
* Fix langs

* changelist
2025-10-27 12:24:15 -04:00
Deterous
ca480f27ed Add hidden language (NovaAurora) (#912)
* Add hidden language (NovaAurora)

* add test
2025-10-27 10:04:00 -04:00
Matt Nadareski
4bad66e706 Slight tweak to automatic UI links 2025-10-26 22:01:10 -04:00
Matt Nadareski
abe00fe132 Try to add UI links to rolling release 2025-10-26 21:46:39 -04:00
Deterous
ba73479837 Rolling tag fix (#911)
* Rolling tag fix

* Remove recursive pull
2025-10-25 21:40:40 -04:00
Matt Nadareski
f2a28dd36b Update changelog 2025-10-24 09:24:40 -04:00
Piotr Swat
928e30a5de Updated Polish translation (#910) 2025-10-24 09:01:26 -04:00
Matt Nadareski
007fc2f9b9 Stop using long name for default system setting 2025-10-23 08:39:09 -04:00
Matt Nadareski
d2d23ebbdf Limit visibility of Compatible OS text box 2025-10-22 11:45:10 -04:00
Matt Nadareski
e02ab769ec Update RedumpLib to 1.8.0 2025-10-22 09:16:53 -04:00
Matt Nadareski
3df78def00 Minor Spanish cleanup 2025-10-21 10:59:49 -04:00
Matt Nadareski
7eddfc5fed Possibly fix missing options string 2025-10-21 09:50:54 -04:00
Matt Nadareski
f6f154b6db Free disk space for runners 2025-10-21 09:22:10 -04:00
Matt Nadareski
47cd133437 Change CLI first-run wording 2025-10-21 09:01:33 -04:00
Matt Nadareski
74c9641a54 Simplify first-run CLI experience 2025-10-21 08:58:01 -04:00
Matt Nadareski
fc5929db2a Add per-OS executable names 2025-10-21 08:51:24 -04:00
Matt Nadareski
f53b428075 Separate out default program paths 2025-10-21 08:43:52 -04:00
Matt Nadareski
46dc931b3f Readme updates for accuracy 2025-10-21 08:30:53 -04:00
Deterous
9608cfb700 Be selective on which systems to enable skeleton (#909)
* Be selective on which systems to enable skeleton

* Bring back lost brace

* case

* RedumpSystem
2025-10-19 20:41:15 -04:00
Matt Nadareski
3493238849 Make log archive handling more user-apparent 2025-10-19 13:15:48 -04:00
Matt Nadareski
4c364f519e Regex outputs should not name based on pattern 2025-10-19 12:47:21 -04:00
Matt Nadareski
337a7a181c Fix tests broken by last commit 2025-10-19 12:27:50 -04:00
Matt Nadareski
071e3a0024 Redumper state file is not accessed 2025-10-19 12:21:20 -04:00
Matt Nadareski
ff0c742dee Handle log zip path in information extraction 2025-10-19 11:55:37 -04:00
Matt Nadareski
7aba0d1c9c Make .img not required for DIC outputs 2025-10-19 11:53:51 -04:00
Matt Nadareski
ac6a77d9da Allow placeholder files to be used in Check 2025-10-19 11:45:22 -04:00
Matt Nadareski
6eb976c842 Merge pull request #908 from SabreTools/ui-langs
Support UI Languages
2025-10-19 09:51:41 -04:00
Matt Nadareski
ba39a8b22f Update changelog 2025-10-19 09:46:11 -04:00
Deterous
88a6fa71a9 Fix long translated strings (#907)
* Build branch

* Enable debug media info window by default

* Fix bold options window context menu

* Shorten ukr strings

* More shortened strings

* better short ukr

* revert build changes and debug flag

* fix test login button strings
2025-10-19 09:46:00 -04:00
Matt Nadareski
584b8c0109 Allow files to be zipped but not deleted 2025-10-19 09:25:56 -04:00
Matt Nadareski
c6258b5520 Handle a provided log zip in Check operation 2025-10-18 20:15:47 -04:00
Matt Nadareski
d6dbbbe928 Add list configuration commandline feature (fixes #906) 2025-10-18 18:47:27 -04:00
Matt Nadareski
f22b3c4ac0 Add Ukrainian translation (superg) 2025-10-18 18:10:45 -04:00
Matt Nadareski
fae399f8bc Add console print when Check loads from config 2025-10-18 13:08:32 -04:00
Matt Nadareski
d2ed2f81ae Make Check flags toggle if config used 2025-10-18 12:03:37 -04:00
Deterous
7dbcfce46c Add basic translation for 8 more languages (#902)
* Add langs

* Top menu spacing

* need using

* ToInterfaceLanguage

* fix UI strings

* auto menu width

* cleanup strings

* fix spacing

* better strings

* revert CI change

* more translation work

* test remove System.Windows.Forms

* full namespace for WinForms

* WinForms namespace

* App is in System.Windows

* Fix string bugs

* Better swedish

* Update changelog
2025-10-18 21:12:51 +09:00
Matt Nadareski
ebd0552a2a Add 8 more language menu items 2025-10-17 17:36:12 -04:00
Matt Nadareski
343973263c Add skeleton for 8 more languages 2025-10-17 17:26:56 -04:00
Matt Nadareski
e5220a8224 Update changelog 2025-10-17 13:01:51 -04:00
Deterous
146120c210 Complete translation support (#901)
* Translate options window

* build on branch

* ui-langs-dev

* fix dupe string

* Translate Media Information Window

* Revert CI process
2025-10-17 13:01:31 -04:00
Matt Nadareski
807e4655a6 Update changelog 2025-10-17 09:12:37 -04:00
Matt Nadareski
e32ebec197 Ensure readers and writers dispose 2025-10-17 08:50:50 -04:00
Matt Nadareski
8d8886390d Minor formatting cleanup 2025-10-17 08:10:02 -04:00
Deterous
5a2aa9d325 Continue UI translation work (#900)
* No redundant translation

* semicolon

* rename DefaultUILanguage

* finish rename

* Cleanup

* Fix SetInterfaceLanguage

* Fix LanguageMenuItemClick

* Set resources before window loads

* set lang during init

* Update interface language after setting options

* Check language menuitem when updating options

* Clear checks when loading language from options

* SetInterfaceLanguage clears checks

* obj as MenuItem

* safer unchecking

* type naming

* uncheck menuitem

* var

* don't uncheck within setlanguage

* test

* equals

* top left menu margin

* help menu right margin

* Fix title bar

* Margin on help menu item

* margin on stack panel

* more translations

* Translate message boxes

* fix margin

* only change lang if options was saved

* only update language if it has been updated

* smaller negative margin

* padding

* padding on textblock

* Revert GHA changes
2025-10-17 08:02:09 -04:00
Matt Nadareski
37aa1645dd Add UI by default to launch 2025-10-17 07:50:46 -04:00
Matt Nadareski
052d074e92 Fill in some gaps 2025-10-16 23:02:35 -04:00
Matt Nadareski
8c551dc990 Clean up a bit of element work 2025-10-16 22:35:31 -04:00
Matt Nadareski
b2fcc190fd Clean up nullability 2025-10-16 21:09:42 -04:00
Matt Nadareski
2325844bd4 Slight cleanup to main window language handling 2025-10-16 20:33:43 -04:00
Matt Nadareski
f63517bb52 Move to enum-based model for UI language options 2025-10-16 20:28:37 -04:00
Deterous
99d26f177b Initial UI lang code (#899)
* Test using resources

* Include system namespace in resource xaml

* system namespace name

* rename strings

* Default strings

* Window resources

* add keys

* just one key

* Combo box example

* window resources

* Dropdown in menu bar

* nullable

* non nullable

* string list init

* simple

* English default

* Add menu item for language

* parent is menuitem

* fix

* no null lang

* Only build win-x64, GHA storage limit

* Korean

* test

* Set resource strings at app level

* remove lost endif

* Better UI

* Move langs next to buttons

* update

* fix button

* More translations

* Better menu size

* too many semicolons

* top right menu bar

* Tweaks

* Top bar positioning

* title bar width

* try again

* final

* Back to original publish script

* more windows

* pre-merge test

* Test non-latin underscore

* More strings

* fix

* FindResource is a function

* space

* cast spells

* Log about text

* semicolon

* Good

* cast spells

* using System.Windows in Frontend

* Translate in MainViewModel

* Dynamic GetFormattedVolumeLabel

* Nullability

* Fix

* using for dict

* Translate func in MVM

* Don't translate in init

* Update MVM translations

* closing brace

* Deprecate resource string

* test

* test2

* set current system

* trial field

* field is preview

* default empty string

* default null

* fix build

* empty string

* GIve up on no system selected text

* Fix context menu border

* Revert half fix

* Translate more IRD Window strings

* Loose string

* Detect current locale

* fix

* System.Globalization

* Locale detection for default lang

* break on zh case

* default startup lang

* default lang option

* fix

* fix2

* fix3

* nonnullable

* final fix

* final final fix

* default language option

* use default language on startup

* empty entry

* semicolon
2025-10-16 11:47:36 -04:00
Matt Nadareski
d6b28de586 Reduce chance of empty strings 2025-10-12 22:45:54 -04:00
Deterous
e8d1567d07 Parse XboxOne/SX Title IDs (#897)
* Parse XboxOne/SX Title IDs

* Bump RedumpLib

* Fix build

* Don't use lists because net20
2025-10-12 20:14:50 -04:00
Matt Nadareski
cd8b484ae3 Replace "We" comments 2025-10-11 16:06:53 -04:00
Matt Nadareski
65b9735941 Conditionally require state 2025-10-11 09:41:28 -04:00
Matt Nadareski
22f7e2a0ed Move output file implementations to separate namespace 2025-10-11 09:34:00 -04:00
Matt Nadareski
2c5dc7390a Use WriteToFile extension for zip entries 2025-10-11 09:27:55 -04:00
Deterous
c5e01b9578 Support reparsing of MPF-processed outputs (#896)
* Have a go at extracting files from existing log

* no null output dir

* Extract log from archive if it is zipped during mediatype detection

* imports

* fix variable names

* fix null output dir

* Final fixes

* changelist

* assign null

* fix
2025-10-10 22:03:03 -04:00
Matt Nadareski
882243316c Implement file merging in CleanRip 2025-10-10 11:40:02 -04:00
Matt Nadareski
1b62ed0c03 Add file merge method in CleanRip 2025-10-10 11:37:11 -04:00
Matt Nadareski
edb8c08a39 Move Zstd compression helper to base processor 2025-10-10 10:07:32 -04:00
Matt Nadareski
ad93387aea Add BCA to list of files to select in Check UI 2025-10-10 09:05:54 -04:00
Matt Nadareski
9012ff85a9 Bump version 2025-10-10 08:44:07 -04:00
Matt Nadareski
ccc33bebbd Try to handle Windows-specific compression issue 2025-10-10 08:09:49 -04:00
Matt Nadareski
57b07aee02 Support detecting split Wii for CleanRip 2025-10-09 15:35:38 -04:00
Matt Nadareski
069d676492 Fix test broken by last commit 2025-10-09 15:05:57 -04:00
Matt Nadareski
a26dfb7e7a Enable skeleton output for all CLI runs 2025-10-09 12:06:16 -04:00
Matt Nadareski
a9ea457808 Use block-based reading instead of CopyTo 2025-10-09 10:31:59 -04:00
Matt Nadareski
41bc410452 Pre-compress state files with Zstd 2025-10-09 10:01:24 -04:00
Matt Nadareski
bbfdf462d0 Fix broken file count tests 2025-10-08 12:54:18 -04:00
Matt Nadareski
5a1d51c05f Pre-compress skeleton files with Zstd 2025-10-08 12:48:50 -04:00
Matt Nadareski
16e80f75cf Add preemptive helper for Zstd handling 2025-10-08 12:04:04 -04:00
Matt Nadareski
2a6e066707 Add preemptive new file support 2025-10-08 11:53:19 -04:00
Matt Nadareski
d6102107fb Only allow skeleton creation for CD and DVD
This was a hard decision to limit again, but with the inability to make Zstd the default for log compression, this is not a reasonable thing to enable for most users.
2025-10-08 11:31:12 -04:00
Matt Nadareski
79163dcb35 Fix default value tests 2025-10-08 11:15:16 -04:00
Matt Nadareski
c1aa863c91 Allow skeleton creation for all media types 2025-10-08 11:10:13 -04:00
Matt Nadareski
dbd4b55dda Use ZipWriterOptions instead of generic 2025-10-08 10:59:51 -04:00
Matt Nadareski
1f58521f51 Fix incorrect flagging of a failed check 2025-10-08 10:54:20 -04:00
Matt Nadareski
4da1ab9c29 Guard against unzippable files 2025-10-08 10:35:28 -04:00
Matt Nadareski
5771add8c0 Revert "Use Deflate64 instead of Deflate for compression"
This reverts commit 977a71d9cf.
2025-10-08 10:20:10 -04:00
Matt Nadareski
977a71d9cf Use Deflate64 instead of Deflate for compression 2025-10-08 09:59:41 -04:00
Matt Nadareski
b2d09d04ea Use null or empty instead of just null 2025-10-08 09:49:22 -04:00
Matt Nadareski
78df92e5d3 More gracefully handle "missing" media types 2025-10-08 09:29:34 -04:00
Matt Nadareski
9770b7c917 Add more useful credentials inputs for Check 2025-10-07 20:37:11 -04:00
Matt Nadareski
1ddb287977 Minor cleanup on interactive modes 2025-10-07 20:27:22 -04:00
Matt Nadareski
b9e4bbf744 Finalize wire-through and clean up 2025-10-07 19:43:34 -04:00
Matt Nadareski
08829ed811 Fix minor issues with options loading 2025-10-07 18:27:12 -04:00
Matt Nadareski
bf181e2294 Start wiring through log compression changes 2025-10-07 18:07:46 -04:00
Matt Nadareski
49571c6bfc Use GC.SharpCompress as archive handling library 2025-10-07 17:33:01 -04:00
Matt Nadareski
9a0bc868f8 More consistency in commandline programs 2025-10-07 16:40:30 -04:00
Matt Nadareski
bc2c08690d Update packages 2025-10-07 16:21:02 -04:00
Matt Nadareski
493cb80624 Allow but do not require config for Check 2025-10-07 15:19:50 -04:00
Matt Nadareski
49b8ecf6c3 Fix minor typo in verify inputs check 2025-10-06 18:05:14 -04:00
Matt Nadareski
c9b7ad7819 Exit early on parsing failures 2025-10-06 17:53:15 -04:00
Matt Nadareski
fe76387f6a Remove CommandOptions implementations 2025-10-06 17:49:16 -04:00
Matt Nadareski
0a60fe5a37 Fix strange invocations of extension methods 2025-10-06 16:37:28 -04:00
Matt Nadareski
baffdb8b29 Remove duplicate input declarations 2025-10-06 16:34:19 -04:00
Matt Nadareski
4a3c585a8d Assign inputs for interactive modes 2025-10-06 16:25:41 -04:00
Matt Nadareski
1ee7ea1948 Create and use base feature in CLI 2025-10-06 16:13:51 -04:00
Matt Nadareski
ee08bfe0fc Create and use base feature in Check 2025-10-06 16:06:23 -04:00
Matt Nadareski
896caec9cd Create and use main features for CLI and Check 2025-10-06 15:54:14 -04:00
Matt Nadareski
68932ab473 Reduce unnecessary shared code 2025-10-06 15:25:11 -04:00
Matt Nadareski
d105d04146 Add placeholder command set creation 2025-10-06 11:01:25 -04:00
Matt Nadareski
7023c78d40 Minor cleanup around last added 2025-10-06 10:34:11 -04:00
Matt Nadareski
81156a3c63 Create interactive mode features 2025-10-06 10:32:16 -04:00
Matt Nadareski
7b2b06a36f Use CommandLine library for CLI executables 2025-10-06 10:11:44 -04:00
Matt Nadareski
3f974ab336 Update packages 2025-10-05 17:41:38 -04:00
Matt Nadareski
b238616685 Rename log zip on collision 2025-10-04 20:49:56 -04:00
Matt Nadareski
2984459823 Tweaks to how failure cases are reported 2025-10-04 18:57:25 -04:00
Matt Nadareski
ce979b3c3f Add failure if media type could not be determined 2025-10-02 22:06:22 -04:00
Matt Nadareski
cb8e1fd34b Bump version 2025-09-30 12:02:06 -04:00
Matt Nadareski
cc148735f8 Require exact versions for build 2025-09-30 11:18:59 -04:00
Matt Nadareski
8238d14f7b Fix missed package update 2025-09-30 10:55:57 -04:00
Matt Nadareski
a56676501e Fix starting index for CLI 2025-09-29 22:43:33 -04:00
Matt Nadareski
79716ea0b5 Bump version 2025-09-29 17:54:03 -04:00
Matt Nadareski
43477a133f Update BinaryObjectScanner to 3.4.3 2025-09-29 14:30:52 -04:00
Matt Nadareski
8889beef1d Reduction in media type use for dumping 2025-09-29 11:25:57 -04:00
Matt Nadareski
ac4be751b3 Make media type a named parameter for CLI 2025-09-29 10:56:56 -04:00
Matt Nadareski
69f855fc93 Fix tests 2025-09-29 10:45:53 -04:00
Matt Nadareski
cf01095623 Skip trying to set speeds if no drives 2025-09-29 10:43:12 -04:00
Matt Nadareski
3236223e3f Default to CD speed range 2025-09-29 10:40:59 -04:00
Matt Nadareski
36450cd22b Minor tweaks to frontend code 2025-09-29 10:25:24 -04:00
Deterous
6a9b6748d2 Remove SkipMediaTypeDetection option, cleanup options window (#895)
* Remove SkipMediaTypeDetection option, cleanup options window

* Shrink detection section in options

* always try to guess media type
2025-09-26 10:56:25 -04:00
Matt Nadareski
3bf83378a2 Fix logic from around Macrovision security driver filtering (fixes #811) 2025-09-25 11:38:03 -04:00
Matt Nadareski
bc938fd58c Return full result from dump checks 2025-09-25 10:54:29 -04:00
Matt Nadareski
f50a110acd Update media type visibility on system change 2025-09-25 09:26:11 -04:00
Matt Nadareski
fcda2a6e3b Change label with media type visibility 2025-09-25 09:07:41 -04:00
Matt Nadareski
d33526b27e Set media type visibility when options changed 2025-09-25 08:56:06 -04:00
Matt Nadareski
0b0427e9c1 Limit media type visibility further 2025-09-25 08:54:33 -04:00
Matt Nadareski
c34b92bad8 Default media type box to hidden to avoid visual issues 2025-09-25 08:49:04 -04:00
Matt Nadareski
89145df0fa Experiment with only showing media type box for DIC 2025-09-25 08:32:06 -04:00
Matt Nadareski
ee7cde6360 Bump version 2025-09-25 08:05:10 -04:00
Matt Nadareski
8e9edf43ac Update RedumpLib to 1.7.4 2025-09-24 13:41:27 -04:00
Matt Nadareski
51115430cb Update BinaryObjectScanner to 3.4.2 2025-09-24 13:20:29 -04:00
Matt Nadareski
7cf108828e Update changelog 2025-09-22 15:33:55 -04:00
Matt Nadareski
020390af65 Cleanup last commits, add tests 2025-09-22 15:30:48 -04:00
HeroponRikiBestest
e04ceb953c Add filters to handle Release Control output. (#892)
* Add filters to handle matroschka output.

* Apply RC-contained filtering to new framework

* Attempt to refine logic to fit framework
2025-09-22 15:23:24 -04:00
Matt Nadareski
363b018cb7 Further flesh out framework 2025-09-22 13:44:21 -04:00
Matt Nadareski
cf025522ef Add context-sensitive protections helper method 2025-09-22 13:41:11 -04:00
Matt Nadareski
0fb8bf5c29 Update BinaryObjectScanner to 3.4.0 2025-09-22 10:15:40 -04:00
Matt Nadareski
e280745eee Add RedumperRefineSectorMode setting (fixes #890) 2025-09-18 08:27:42 -04:00
fuzzball
fb306750e6 Support new versioning format in redumper (#889)
* Support new versioning format

* Update changelist
2025-09-16 07:13:54 -04:00
Deterous
da5a514482 Update redumper to build 655 (#888) 2025-09-12 07:35:01 -04:00
Deterous
fc288e1c46 Update RedumpLib, detect Playmaji Polymega system (#886)
* Update RedumpLib, detect Playmaji Polymega system

* Update libs for Processors

* Add IO and Matching to Processors csproj
2025-09-05 11:09:22 -04:00
Deterous
102acb9ebf Fix UIC processing logic (#885)
* Fix UIC title field

* the sabre approved way

* Better UIC test_disc.txt

* Fix UIC category logic

* Fix GetUMDCategoryTest

* Final test tweak
2025-09-04 08:27:13 -04:00
Deterous
b76b2a69f5 Update DIC to 20250901 (Windows/Linux only) (#884) 2025-09-02 07:24:07 -04:00
Deterous
254ad6cfd0 Support multisession cache files (#882)
* redumper multisession .cache

* Changelist

* Fix tests
2025-08-25 08:00:34 -04:00
Matt Nadareski
f432f438ab Update RedumpLib to 1.7.1 2025-08-23 09:58:16 -04:00
Matt Nadareski
e890243830 Update test Nuget packages 2025-08-23 09:56:25 -04:00
Matt Nadareski
6493b462f1 Minor cleanup 2025-08-23 09:47:17 -04:00
Deterous
54c0716ea9 Update redumper to build 653 (#880)
* Update redumper to build 653

* nit
2025-08-23 08:43:35 -04:00
Matt Nadareski
7fbb5133d7 Update LibIRD 2025-08-19 10:41:53 -04:00
Matt Nadareski
993a0fd7d3 Update RedumpLib and LibIRD 2025-08-19 07:23:02 -04:00
fuzzball
47878fee1f Fix for C2 error doubling issue (#877)
* Expand error detection

* Update changelist

---------

Co-authored-by: Matt Nadareski <mnadareski@outlook.com>
2025-08-15 10:37:15 -04:00
Matt Nadareski
4cb8a31505 Update Aaru to build 5.4.1 (fixes #879) 2025-08-14 09:02:25 -04:00
Matt Nadareski
0685972842 Fix inconsistency with newlines 2025-07-23 11:49:54 -04:00
Matt Nadareski
5b1cc3c715 Add CopyUpdateUrlToClipboard option 2025-07-23 07:51:18 -04:00
Matt Nadareski
572f0d5095 Treat all UMD as DL visually 2025-07-22 14:57:03 -04:00
Matt Nadareski
23bafad3db Update RedumpLib to 1.6.9 2025-07-21 12:14:37 -04:00
Matt Nadareski
c7b77e4bd7 Reduce preprocessing in DumpEnvironment 2025-07-19 12:36:03 -04:00
Matt Nadareski
755eee4441 Put a try/catch around GenerateArtifacts 2025-07-19 12:25:20 -04:00
Matt Nadareski
fca2c53d6c Let the processor always deal with unsupported 2025-07-19 09:06:28 -04:00
Matt Nadareski
8f6f5f6ef0 UI consistency when parameters are editable (fixes #876) 2025-07-18 15:09:21 -04:00
Matt Nadareski
2e9970ee6a Always trust the output files for processing 2025-07-18 13:20:45 -04:00
Matt Nadareski
4fa1273111 Remove media type from Check Dump UI 2025-07-18 13:15:40 -04:00
Matt Nadareski
d3993a48e4 Bump version 2025-07-18 08:20:54 -04:00
Deterous
d522bb6c76 Update redumper to build 631 (#875)
* Update redumper to build 631

* add flag to tests
2025-07-16 08:04:27 -04:00
Matt Nadareski
816672a817 Slightly better IRD organization 2025-07-15 13:06:05 -04:00
Matt Nadareski
f8171da306 Better handle mixed-separator paths 2025-07-15 08:00:55 -04:00
Matt Nadareski
ce073e5fbf Simplify code from previous commit 2025-07-14 13:13:25 -04:00
Matt Nadareski
28205e42f0 Strip errant whitespace during path normalization (fixes #874) 2025-07-14 12:58:44 -04:00
Matt Nadareski
0160366530 Add new help and version flags for CLI and Check (fixes #873) 2025-07-12 16:04:54 -04:00
Matt Nadareski
663477d408 Update RedumpLib to 1.6.8 (fixes #872) 2025-07-11 12:49:12 -04:00
Matt Nadareski
bd2e012eef Net Yaroze only for PS1 2025-07-11 12:09:06 -04:00
Matt Nadareski
a514374169 Remove legacy codes from info window (fixes #871) 2025-07-11 12:05:03 -04:00
Matt Nadareski
f73c0730e2 Update changelog 2025-07-09 07:23:38 -04:00
fuzzball
a658c80de7 Empty should be null (#868) 2025-07-09 07:23:09 -04:00
Matt Nadareski
b806bc6cd1 Fix unnecessary null assignment 2025-06-26 10:35:47 -04:00
Matt Nadareski
cf9675f620 Only use serial for PS3/4/5 if no custom volume label 2025-06-26 10:34:49 -04:00
Matt Nadareski
ea18051709 Swap PS1/2 back to original name handling 2025-06-26 08:38:46 -04:00
Matt Nadareski
4fdf8e5dde Use reasonable default names for PlayStation systems (fixes #866) 2025-06-26 08:30:14 -04:00
Deterous
a4616d139d Better handling of Xbox/360, redumper build 613 (#865)
* Better handling of bad SS, redumper build 613

* Add missing helper function

* Fix new func signature

* Fix var name

* Nulls

* Don't get vollabel for xbox/360

* formatting

* formatting v2
2025-06-23 21:03:42 -04:00
Matt Nadareski
0f09a9c913 Address nullable default value 2025-06-18 09:40:00 -04:00
Matt Nadareski
48ffd6f40c Set some default values for CLI (fixes #863) 2025-06-18 09:34:35 -04:00
Matt Nadareski
6612c8ea4d Remove dead code in DIC processor 2025-06-18 09:13:44 -04:00
Matt Nadareski
68d1a0664a IsAudio cleanup cleanup 2025-06-18 09:08:37 -04:00
Matt Nadareski
86d8590789 IsAudio cleanup 2025-06-18 08:52:51 -04:00
Matt Nadareski
e23427d7c9 Update redumper to build 611 2025-06-17 21:00:52 -04:00
Matt Nadareski
cd19a2e4a0 Use the correct base path for Check 2025-06-17 17:55:10 -04:00
Matt Nadareski
000e7d88a8 Fix start index in Check 2025-06-17 17:18:12 -04:00
Matt Nadareski
e3beb1ef77 Rename disc info to media info 2025-06-17 16:35:03 -04:00
Matt Nadareski
a3a75b1c2d Fix missed test updates 2025-06-17 15:52:48 -04:00
Matt Nadareski
11850a8d6b Enable Check to determine media type automatically 2025-06-17 15:36:23 -04:00
Matt Nadareski
bf6b58d64b Fill out DetermineMediaType for DiscImageCreator 2025-06-17 14:26:13 -04:00
Matt Nadareski
1789334625 Fill out DetermineMediaType for Aaru 2025-06-17 13:05:35 -04:00
Matt Nadareski
9520f58240 Fill out DetermineMediaType for Redumper 2025-06-17 11:37:37 -04:00
Matt Nadareski
48e5e01729 Add DetermineMediaType scaffolding and tests 2025-06-17 09:45:16 -04:00
Matt Nadareski
8c7959fb08 Reduce media-specific checks where unnecessary 2025-06-17 08:51:57 -04:00
Matt Nadareski
8ef7543cf1 Ignore volume labels with path separators 2025-06-16 09:26:56 -04:00
Matt Nadareski
f9e39ee4be Further clarify configuration requirements for CLI (fixes #861) 2025-06-16 07:43:51 -04:00
Matt Nadareski
0a4621c963 Handle layers for PS3CFW (fixes #859) 2025-06-13 20:35:32 -04:00
Matt Nadareski
04b4f528ba Fix changelog location 2025-06-12 08:34:49 -04:00
Matt Nadareski
f024e49c21 Bump version 2025-06-12 08:33:55 -04:00
Deterous
7ca404f9dd Update redumper to build 610 (#858) 2025-06-12 07:50:51 -04:00
Matt Nadareski
18fc162cd8 Fix size retrieval for Aaru 2025-06-09 09:28:04 -04:00
Matt Nadareski
b577bbae37 Create multi-size icon (fixes #857) 2025-06-06 08:38:44 -04:00
Matt Nadareski
02f9509b86 Simplify Options naming where possible 2025-06-02 10:19:48 -04:00
Matt Nadareski
8b00e3deed Decouple retieval from login 2025-06-02 09:35:26 -04:00
Matt Nadareski
3ffea60402 Remove unnecessary options property 2025-06-02 09:08:15 -04:00
Matt Nadareski
f8eab60ecc Fix tests from last commit 2025-06-01 20:54:16 -04:00
Matt Nadareski
9e8d46fb03 Fix Redump default options (fixes #855) 2025-06-01 20:49:30 -04:00
Matt Nadareski
3831922f29 Add currently-hidden RetrieveMatchInformation option 2025-06-01 20:36:18 -04:00
Matt Nadareski
7f7416c053 Update tooltips/labels for controversial options 2025-05-30 12:48:23 -04:00
Matt Nadareski
529ada1b8b Fix issues with last commit 2025-05-30 12:43:25 -04:00
Deterous
6260f1a1fe Update redumper, MPF options, SS sanity check (#854)
* Update redumper, add DriveType option

* Fix typo

* Don't save ss file if invalid SS

* Update changelist

* LongName for DriveType

* Fix typo

* Fix tests

* Redo tests

* Fix test typo

* Remove additional space from test

* Simplify redumper program options

* semicolon
2025-05-30 12:40:22 -04:00
Matt Nadareski
a7f6e09226 Update RedumpLib to 1.6.7 (fixes #853) 2025-05-23 12:54:27 -04:00
Matt Nadareski
4b49815a7a Include Aaru in automatic builds 2025-05-23 12:16:51 -04:00
Matt Nadareski
14c17bbdf7 Bump version 2025-05-23 12:02:56 -04:00
Matt Nadareski
0fe30d2d4f Remove unnecessary conditional 2025-05-22 12:11:01 -04:00
Matt Nadareski
1c3f65e7f9 Handle error count resets in Redumper (fixes #852) 2025-05-22 12:07:50 -04:00
Matt Nadareski
62ff0f955a Reset Redump errors when an INFO block is found 2025-05-22 11:24:20 -04:00
Deterous
a942e6142a Minor Check UI improvements (#851)
* Minor Check UI improvements

* Move Check warning below status box

* Hover text on status message

* Full status in tooltip

* Add ellipsis to status text

* null ref assignment

* OneWay

* trigger StatusFirstLine property changed

* Better status property block

* wrong op
2025-05-22 10:46:53 -04:00
Matt Nadareski
f637e629a3 Add and use status label for Check window 2025-05-22 08:55:18 -04:00
Deterous
72b00953d8 Don't hash bad SS (#850)
* Don't hash bad SS

* fix build

* proper namespace
2025-05-22 08:31:24 -04:00
Matt Nadareski
cfac607c7d Use null for 0 speed internally 2025-05-22 08:21:06 -04:00
Matt Nadareski
e9a84e5429 Further fix speed dropdown with Redumper (fixes #849) 2025-05-22 07:56:57 -04:00
Matt Nadareski
2f985d0526 Update redumper to build 585 2025-05-21 11:39:26 -04:00
Matt Nadareski
e1ace14753 Fix speed dropdown with Redumper (fixes #849) 2025-05-21 09:17:19 -04:00
Matt Nadareski
9c29967f65 Fix bracket formatting from last commit 2025-05-19 11:56:15 -04:00
Deterous
5612d7989d Relax PS3CFW output filename requirements (#848)
* Relax PS3CFW output filename requirements

* don't use Linq

* better regex

* literal backslash

* requested changes

* fix

* Update MPF.Processors/PS3CFW.cs

Co-authored-by: Matt Nadareski <mnadareski@outlook.com>

---------

Co-authored-by: Matt Nadareski <mnadareski@outlook.com>
2025-05-19 11:54:37 -04:00
Matt Nadareski
f872a6be29 Minor cleanup from last commit 2025-05-19 08:48:09 -04:00
Deterous
59e7ecfa8a Better audio-only check (#847)
* Better IsAudio()

* null deref

* Don't set fields if empty

* Update Changelist

* Requested changes

* fix build

* fix build again

* string literal

* C# is dumb

* Revert to original

* revert further

* remove extra comma
2025-05-19 08:23:25 -04:00
Deterous
79cce37cf6 Add newlines to pkg info printing (#846)
* Add newlines to pkg info printing

* newline for ps4 too
2025-05-16 11:00:04 -04:00
Matt Nadareski
4016b3fc19 Serialize JSON a slightly different way 2025-05-12 21:44:47 -04:00
Matt Nadareski
e5bcada606 Simplify WriteOutputData path handling 2025-05-12 21:37:48 -04:00
Matt Nadareski
60d31363e3 Explicitly unset Redumper speed, if needed 2025-05-08 07:46:49 -04:00
Matt Nadareski
22a125a838 One more note about hidden settings 2025-05-05 21:29:17 -04:00
Matt Nadareski
0a86781d61 Clarification on some options 2025-05-05 21:14:35 -04:00
Matt Nadareski
c5649ecdbb Add Check warnings around overwriting and parsing 2025-05-05 13:05:35 -04:00
Matt Nadareski
df22336ba0 Support checking Redumper DAT from zip; add tests 2025-05-05 12:45:02 -04:00
Matt Nadareski
2d7350cbaf Close the log archive, if it exists 2025-05-05 11:49:33 -04:00
Deterous
6a56a58b7c Update redumper to build 565 (#842) 2025-05-04 19:54:09 -04:00
Matt Nadareski
a97c94885c Fix lines wiped before displayed 2025-05-04 11:23:24 -04:00
Matt Nadareski
9548993982 Tweak to previous commit for some build versions 2025-05-04 11:18:28 -04:00
Matt Nadareski
1476972c26 Pre-clean file path in CLI interactive mode 2025-05-04 11:14:46 -04:00
Matt Nadareski
85cde67d0a Update RedumpLib to 1.6.6 (fixes #841) 2025-05-01 11:00:04 -04:00
Matt Nadareski
bfaf24c237 Update to DIC 20250501 2025-05-01 10:27:31 -04:00
Matt Nadareski
adfa8a9a0c Normalize Shift-JIS characters, when possible (fixes #827) 2025-05-01 09:58:48 -04:00
Matt Nadareski
3d68d880f6 Update Nuget packages 2025-05-01 09:40:42 -04:00
Matt Nadareski
77bc7e7b1a Fix package reference layout 2025-05-01 09:35:41 -04:00
Matt Nadareski
23837ee555 Update RedumpLib to 1.6.5 (fixes #809, fixes #834) 2025-04-30 21:03:01 -04:00
Matt Nadareski
0553d1256a Allow exiting from interactive modes 2025-04-30 20:32:49 -04:00
Matt Nadareski
68f0c6cf35 Avoid redundant redundancy 2025-04-30 20:27:42 -04:00
Matt Nadareski
32d3996432 Make interactive mode cleaner 2025-04-30 20:14:04 -04:00
Matt Nadareski
5af02fe508 It's not dumping, it's checking 2025-04-30 16:52:40 -04:00
Matt Nadareski
eba6a7ce4a Fix menu title in Check interactive 2025-04-30 16:50:04 -04:00
Matt Nadareski
7faedc92e4 Add interactive mode to Check 2025-04-30 16:49:28 -04:00
Matt Nadareski
3de48fc24e Clean up case-sensitivity 2025-04-30 16:29:34 -04:00
Matt Nadareski
9400523c4f Add padding above root interactive node label 2025-04-30 16:22:04 -04:00
Matt Nadareski
48c945f194 Add interactive mode to CLI (fixes #819) 2025-04-30 16:19:19 -04:00
Matt Nadareski
d9a8050beb Fix removing empty subdirectories 2025-04-30 15:15:27 -04:00
Matt Nadareski
6ec179f0ed Comment download scripts more 2025-04-30 15:01:30 -04:00
Matt Nadareski
620851af73 Fix minor packing issues 2025-04-30 14:43:16 -04:00
Matt Nadareski
f5c4b7ebdf Enable packing programs for CLI 2025-04-30 14:19:44 -04:00
Matt Nadareski
364ae1b837 Replace old download implementations (fixes #840) 2025-04-30 13:54:44 -04:00
Matt Nadareski
b4b864cd9f Fix issue with some downloads 2025-04-30 13:47:41 -04:00
Matt Nadareski
acc2f30bd2 Fix most issues in new download code 2025-04-30 13:41:36 -04:00
Matt Nadareski
dc0675d8c6 Add cleanup to download functions 2025-04-30 12:03:06 -04:00
Matt Nadareski
33ce0e4024 Add initial extraction to new functions 2025-04-30 12:00:41 -04:00
Matt Nadareski
fa8fdac0ce Trailing commas caused issues 2025-04-30 11:49:11 -04:00
Matt Nadareski
a4d876d273 Fix elif 2025-04-30 11:39:36 -04:00
Matt Nadareski
3cc779ba77 Unify download maps 2025-04-30 11:38:36 -04:00
Matt Nadareski
5c8f4b9cac Smarter mapping of URLs to runtimes 2025-04-30 11:29:00 -04:00
Matt Nadareski
fb2b926986 Move function definitions 2025-04-30 11:02:58 -04:00
Matt Nadareski
3442a1f5b2 Add commented placeholders instead of omitting 2025-04-30 09:58:30 -04:00
Matt Nadareski
1fb9039985 Make more paths configurable 2025-04-30 09:54:49 -04:00
Matt Nadareski
0032066363 Add all separate downloads 2025-04-30 09:28:13 -04:00
Matt Nadareski
c1ed042190 Start defining all download URLs 2025-04-30 09:16:28 -04:00
Matt Nadareski
6c0f2415b7 Short-circuit CLI first-run experience 2025-04-30 09:02:36 -04:00
Matt Nadareski
ca898c4689 Always write full configuration file (fixes #839) 2025-04-30 08:55:37 -04:00
Matt Nadareski
3be4378b61 Normalize file path in CLI (fixes #826) 2025-04-30 08:53:20 -04:00
Deterous
c1641d7461 Allow max speed dumping (#838)
(0) in options
2025-04-19 08:16:05 -04:00
Deterous
aefb5a3778 Change redumper default commands (#837)
* Allow "0" drive speed

* Default speed 1 for unknown system

* default speed of 1

* No skeleton

* No base command by default

* Change speed in redumper tests

* Dump no longer dumping command

* Re-allow quick exiting always

* No base command is a dumping command

* Only one mode command per redumper call

* Proper capitalization for None

* Readd disc as default command mode
2025-04-18 09:05:33 -04:00
Deterous
4557017fc5 Quality of life fixes (#836)
* Account for N-type discs in Redumper processor

* MediaType prefix

* Delete after zipping, ask before closing during dump

* Proper closing function

* proper using

* nullable object

* YesNoCancel isn't a thing for CustomMessageBox

* Ctrl-Z
2025-04-17 11:37:32 -04:00
Deterous
d77e9c1612 Update redumper to build 549 (#835)
* Update redumper to build 549

* Add more redumper tests

* Add type

* Support .flip and .cache outputs

* Fix typo

* Fix test name

* Update tests

* Update tests again

* Don't check dmi/pfi/ss hashes against redump

* Fix incorrect flag

* Get last SCSI error count

* Fix test

* Fix test again

* Fix test finally

* Fix test final

* Review

* SACD doesn't need skeleton

* Proper SACD system handling

* Final final

* delete
2025-04-17 08:39:10 -04:00
bikerspade
455fb8228a Fix typo for L1Toolstamp!.Label (#828) 2025-02-27 12:02:15 -05:00
Matt Nadareski
679b40de7c Bump version 2025-01-03 11:44:35 -05:00
Matt Nadareski
fb2b1b7c54 Fix system detection logging 2025-01-03 09:52:42 -05:00
Matt Nadareski
ac649af511 Update to DIC 20250101 (fixes #807) 2025-01-01 22:40:00 -05:00
Matt Nadareski
4fb0e38f54 Handle SCSI error count (fixes #806) 2024-12-31 23:15:43 -05:00
Matt Nadareski
a84904e374 Fix misunderstanding on perfect offset 2024-12-31 21:53:14 -05:00
Matt Nadareski
7b8becfa40 Update RedumpLib to 1.6.4 (fixes #805) 2024-12-31 21:41:32 -05:00
Matt Nadareski
ba0fefca42 Fix short name test 2024-12-31 15:10:43 -05:00
Matt Nadareski
d7736055a0 Fix BinaryObjectScanner update 2024-12-31 13:45:25 -05:00
Matt Nadareski
8e37932b86 Add and use internal program short names 2024-12-31 13:43:57 -05:00
Matt Nadareski
d2c58d4c39 Update BinaryObjectScanner to 3.3.4 2024-12-31 13:35:04 -05:00
Matt Nadareski
34f3449231 Update copyright 2024-12-30 21:43:48 -05:00
Matt Nadareski
31ee29a716 Remove unnecessary action step 2024-12-30 21:42:14 -05:00
Matt Nadareski
c1f2fd5f19 Be consistent with filename extensions (fixes #804) 2024-12-29 14:12:04 -05:00
Matt Nadareski
172f9afbcf Update changelog 2024-12-28 23:03:10 -05:00
Deterous
19dd4f43e4 Minor UI changes to DIW (#803)
* Change DIW userinput ratio to 3:7

* Add groupboxes around contents and readonly tabs in DIW

* Use real PVD and PIC in debug data

* rearrange groupbox / stackpanel

* group boxes
2024-12-28 23:02:06 -05:00
Matt Nadareski
0ae7352c5e Update RedumpLib to 1.6.3 2024-12-28 13:59:59 -05:00
Matt Nadareski
e7c11d40ac Force showing tooltips on disabled items 2024-12-28 13:19:01 -05:00
Matt Nadareski
dccd78a01e Force path update if default changed 2024-12-28 13:09:35 -05:00
Deterous
fb05409c5d Minor UI and other fixes (#802)
* Wider DIW, rounded message boxes

* Don't log drive speed

* Change margins

* Allow changing DIW size

* Revert change to DIW sizing

* Change left column size in DIW

* Increase textbox ratio in UserInput

* Fix non-userinput margins

* Allow custom message box to move from image

* Change changelist

* PS4 pkg date is useless
2024-12-28 11:43:53 -05:00
Matt Nadareski
1c9b94341a Wrap some PhysicalTool method calls 2024-12-28 00:35:12 -05:00
Matt Nadareski
d3e208a332 Partially clean up PS3CFW 2024-12-27 22:44:06 -05:00
Deterous
6b8cfb4256 Add pure-getkey output names for PS3CFW (#801)
* Add pure-getkey output names for PS3CFW

* Don't assume . prefix for getkey.log

* zip CUE files generated by MultiMAN if they exist

* iso and cue can be case sensitive

* Add extra file to cfwps3 tests
2024-12-27 22:31:20 -05:00
Matt Nadareski
f60f26065b Don't add special field keys with no reason 2024-12-27 21:58:12 -05:00
Deterous
2ed14a7688 Improve PS4/PS5 parsing (#799)
* Improve PS4/PS5 parsing

* requested changes

---------

Co-authored-by: Matt Nadareski <mnadareski@outlook.com>
2024-12-27 21:29:33 -05:00
Matt Nadareski
071b91f414 Reenable XGD1 PVD reporting 2024-12-27 20:57:39 -05:00
Matt Nadareski
0ad99cb0f5 Hide empty partially matched list (fixes #800) 2024-12-27 19:58:07 -05:00
Deterous
e51aabddae Minor UI changes (#798)
* Minor changes to read-only field boxes

* re-add textwrapping to hashdata

* rounded border

* fix build

* fix border

* shift title buttons left

* Add fake column

* Make all of the title bar draggable

* Rounded all windows

* color all windows

* fix xml namespace

* Use 8px corner radius

* revert workflow change

* Changes changelist comment

* Remove toplevel grid

* Add dropshadow and scrollbar foreground color

* Increase border size, remove test scrollbar theme

* Give textboxes the custom scrollviewer style

* Remove test styles

* Revert incidental whitespace spaces

* dont revert intended change
2024-12-27 07:47:17 -05:00
Matt Nadareski
9390699114 Missed one 2024-12-25 21:44:17 -05:00
Matt Nadareski
93d2c2e8b0 Clean up unused disabled warnings 2024-12-25 21:42:10 -05:00
Matt Nadareski
50d969f08f Unify DisplayUserMessage definitions 2024-12-25 21:39:05 -05:00
Deterous
44e87948c7 Parse redumper BIG.DAT info (#797)
* Parse redumper BIG.DAT info

* Make protection comment bold

* Add tests for GetPlayStation2Protection
2024-12-24 10:41:47 -05:00
Deterous
dea011213a More fields behind RedumpCompatible option (#795)
* More fields behind RedumpCompatible option

* Dereference of a possibly null reference
2024-12-23 23:50:40 -05:00
Matt Nadareski
5b2500637b Update changelog 2024-12-23 23:20:02 -05:00
Deterous
82ede4dac2 Tab input only needed for ringcodes (#794) 2024-12-23 23:19:31 -05:00
Matt Nadareski
032ffe75f4 Do not display invalid credentials on empty 2024-12-23 20:23:25 -05:00
Matt Nadareski
ce9c6d1f52 Wrap log compression in a thread 2024-12-23 15:35:52 -05:00
Matt Nadareski
8be145127d Use Invoke explicitly for delegates 2024-12-23 10:25:50 -05:00
Matt Nadareski
0ce928349c Use internal options instead of external 2024-12-23 10:06:44 -05:00
Matt Nadareski
79e4f4a142 Pass options to process user info separately 2024-12-23 00:54:56 -05:00
Matt Nadareski
4bd8fc476c Avoid unnecessary null checks 2024-12-23 00:05:48 -05:00
Deterous
5b82cdacda Improve system detection (#792)
* Improve Sega system detection

* Fix namespace

* Ignore exception

* Add Sega CD header

* Improve system detection

* Amiga CD check

* Improve 3DO and Mac detection

* Remove unused parameter

* Try determine system even when drive inactive

* Better logic for inactive drives

* scope issues

* GameWave and VIS

* Fix Neo Geo CD system check

* use var

* put physicaltool behind try catch

* better use var
2024-12-22 20:26:47 -05:00
Matt Nadareski
4106a6261b Slightly increase nesting of file pre-dump checks 2024-12-21 23:23:03 -05:00
Matt Nadareski
6b006958a6 Slightly reduce nesting of file pre-dump checks 2024-12-21 23:16:31 -05:00
Deterous
068b92ebac Check for partial dumps (#791)
* Check for partial dumps

* fix bugs

* Change program checking order

* comments bad

* Adds CheckExistingFiles tests

* Correct test results
2024-12-21 23:01:16 -05:00
Matt Nadareski
4cf2b8a83d Allow check and IRD most of the time 2024-12-21 20:33:19 -05:00
Matt Nadareski
333043ccae Account for menu items for disable/enable 2024-12-21 20:30:23 -05:00
Matt Nadareski
0ff1753aa2 Disable all UI elements on protect scan 2024-12-21 13:33:12 -05:00
Matt Nadareski
9ad917e508 Remove unused progress bar (fixes #788) 2024-12-21 12:15:30 -05:00
Deterous
f3ac31ce1b More pendantic GUI changes (#790) 2024-12-21 11:19:28 -05:00
Deterous
7fdf671273 Pedantic GUI changes (#789) 2024-12-21 10:51:56 -05:00
Matt Nadareski
d5dee49f6b Adjust row count in protection options 2024-12-21 10:15:25 -05:00
Matt Nadareski
acdc13efa1 Enable tabs in input fields by default 2024-12-21 01:07:13 -05:00
Matt Nadareski
8446980919 Retire and replace blue secret text 2024-12-20 23:56:23 -05:00
Matt Nadareski
e5e7bf49fc Fix log line for default system use 2024-12-20 23:11:29 -05:00
Matt Nadareski
8b73ffc4a2 Ensure parameters checkbox is enabled to start 2024-12-20 22:38:08 -05:00
Matt Nadareski
ce6ed1e01b Disable more UI elements when editing 2024-12-20 22:33:24 -05:00
Matt Nadareski
bc0cd60fc1 Separate params checkbox from input 2024-12-20 22:31:10 -05:00
Matt Nadareski
17f850ecb2 Use IBM PC as default system out of the box 2024-12-20 22:07:56 -05:00
Matt Nadareski
ad8a623f16 Selectively rebuild program list 2024-12-20 21:46:03 -05:00
Matt Nadareski
b025898d7b Fix output name null edge case 2024-12-20 21:35:49 -05:00
Matt Nadareski
b604aefd5e Simplify output name assembly logic 2024-12-20 21:30:31 -05:00
Matt Nadareski
1656b50029 Add README files for two libraries 2024-12-20 12:12:47 -05:00
Matt Nadareski
572b8cfa6b Remove reference to removed file 2024-12-20 11:55:42 -05:00
Matt Nadareski
c5cd623e75 Remove vestigial configuration file 2024-12-20 11:51:56 -05:00
Matt Nadareski
ff2dbd7b81 Fix important typo 2024-12-20 11:37:34 -05:00
Matt Nadareski
19cedfc5e8 Allow symbols to be packed 2024-12-20 11:20:09 -05:00
Matt Nadareski
3df93fb59d Preserve program metadata on publish 2024-12-20 11:02:33 -05:00
Matt Nadareski
62ffd3f6d3 Include native libraries for self-extract 2024-12-20 10:54:54 -05:00
Matt Nadareski
69994774f5 Update changelog 2024-12-20 10:12:30 -05:00
Matt Nadareski
3a1fc93aac Better SecuROM handling for DIC and Redumper 2024-12-20 10:11:23 -05:00
Matt Nadareski
6f8d27b9c4 Fix now-incorrect test values 2024-12-19 14:03:16 -05:00
Matt Nadareski
42680b9915 Use simpler cuesheet reader in Redumper 2024-12-19 13:57:48 -05:00
Matt Nadareski
9033f3a798 Minor formatting tweaks; add TODO 2024-12-19 12:08:19 -05:00
Matt Nadareski
717590bf41 Remove use of psxt001 2024-12-19 12:04:13 -05:00
Matt Nadareski
4f48ccc4c6 Ensure .NET versions are installed for testing 2024-12-19 10:55:31 -05:00
Deterous
ca59d71e7d Print PS4/PS5 app.pkg info (#785)
* Print PS4/PS5 app.pkg info

* namespace

* Use a filestream

* Use appPkgHeaderDeserializer obj

* null check
2024-12-19 10:23:50 -05:00
Matt Nadareski
9207627fb0 Introduce maximum log length 2024-12-19 00:49:41 -05:00
Matt Nadareski
216c6de970 Fully remove processing queue code 2024-12-19 00:37:56 -05:00
Matt Nadareski
cebbeb264f (EXPERIMENTAL) Skip log line queue 2024-12-19 00:13:09 -05:00
Matt Nadareski
e971ee8550 Use explicit InvokeAsync when possible 2024-12-18 23:30:14 -05:00
Matt Nadareski
76029d02ea Simplify ProcessLogLine method 2024-12-18 23:21:58 -05:00
Matt Nadareski
0cdf2fc520 Fix access level for log document 2024-12-18 23:20:28 -05:00
Matt Nadareski
5ac0055e16 Fix access level for log queue 2024-12-18 23:18:02 -05:00
Matt Nadareski
7b7e8912a5 Remove non-working last line log code 2024-12-18 23:16:14 -05:00
Matt Nadareski
e055572c67 Remove vestigial progress indicators 2024-12-18 23:00:45 -05:00
Matt Nadareski
c4d981350f Simplify direct package references 2024-12-18 22:55:53 -05:00
Matt Nadareski
5035f2dcc2 Update packages 2024-12-18 22:13:58 -05:00
Deterous
7c41fe0933 Verify SecuROM sector count (#784)
* Verify securom sector count

* Make securom enum internal

* Fix bugs

* Don't set explicit var in test

* Deal with review

* Fix mistake

* Oops

* Proper DIC securom sector count

* fix names
2024-12-18 09:37:00 -05:00
Deterous
2b4fa33e81 Use proper base path for redumper output check (#783) 2024-12-17 00:05:13 -05:00
Deterous
e8f50a84b8 Enable handling non-SS Xbox discs (#782)
* Enable handling non-SS Xbox discs

* Fix manufacturer size
2024-12-16 23:09:36 -05:00
Matt Nadareski
7c0923881e Update BOS to 3.3.2 2024-12-14 23:05:57 -05:00
Matt Nadareski
eeacb7b3b2 Slight formatting tweaks 2024-12-14 20:48:28 -05:00
Deterous
d3039af3e1 Fix bug with volume labels (#781) 2024-12-14 20:31:44 -05:00
Deterous
eaa77dbeed Better deal with volume labels (#780)
* Better deal with volume labels

* Add missing using

* use nullable string

* Deal with review comments

* Fix issues

* Better deal with Xbox/Xbox360 labels

* Use FirstOrDefault

* Add todo
2024-12-14 19:58:09 -05:00
Deterous
55696f1f47 Add DumpingParameters for DIC and Redumper (#778)
* DumpingParameters for DIC and Redumper

* Update changelog

* fix typo

* Fix test

---------

Co-authored-by: Matt Nadareski <mnadareski@outlook.com>
2024-12-12 11:41:48 -05:00
Matt Nadareski
7d22341d2f Fix issue with odd quoting (fixes #779) 2024-12-12 11:35:54 -05:00
Matt Nadareski
53c6e47fa8 Simplify prefix filtering 2024-12-11 03:57:25 -05:00
Matt Nadareski
7b7da4db1f Add packer filtering tests 2024-12-10 14:51:09 -05:00
Matt Nadareski
b9d8e0c125 Always omit EA CD-Key 2024-12-10 14:11:48 -05:00
Matt Nadareski
1e2f1280be Remove now-redundant option 2024-12-10 13:07:51 -05:00
Matt Nadareski
3339ff1c14 Always filter out game engines and packers 2024-12-10 12:00:10 -05:00
Matt Nadareski
1e729459a6 Remove unnecessary re-splitting of path (fixes #772) 2024-12-07 22:08:26 -05:00
Matt Nadareski
2d547bd67f Add launch config for CLI 2024-12-07 21:45:06 -05:00
Matt Nadareski
2bb854e7a5 Add safety check around empty config files 2024-12-06 23:58:21 -05:00
Matt Nadareski
b8e923207f Add alternate config location (fixes #768) 2024-12-06 23:55:27 -05:00
Matt Nadareski
3d96379aba Remove unused gated using statement 2024-12-06 20:58:40 -05:00
Matt Nadareski
8c5437983a Update README to remove AppVeyor references 2024-12-06 20:36:15 -05:00
Matt Nadareski
7cad841f39 Migrate to using publish script for GHA 2024-12-06 15:59:46 -05:00
Matt Nadareski
b4e04314a7 Add gated program downloads to publish scripts 2024-12-06 15:56:13 -05:00
Matt Nadareski
f1506b284c Add debug flag to publish scripts 2024-12-06 14:56:50 -05:00
Matt Nadareski
3fde773018 Clean up original Drive tests 2024-12-06 00:45:41 -05:00
Matt Nadareski
2fb8613a85 Remove unnecessary namespace prefixes 2024-12-06 00:35:25 -05:00
Matt Nadareski
94d59242b1 Update protection tool tests 2024-12-06 00:27:39 -05:00
Matt Nadareski
09179810ee Add FrontendTool tests 2024-12-05 23:49:24 -05:00
Matt Nadareski
2061af06c1 Ensure Redumper support matrix is consistent 2024-12-05 23:00:28 -05:00
Matt Nadareski
075a95ef4c Ensure consistency in frontend code 2024-12-05 22:45:53 -05:00
Matt Nadareski
c8a402ee64 Update RedumpLib to 1.6.1 2024-12-05 22:19:23 -05:00
Matt Nadareski
a5d7b218b7 Add non-tools frontend tests 2024-12-05 21:51:25 -05:00
Matt Nadareski
ebb83a6a1e Unify queue handling in processing queue 2024-12-05 21:40:53 -05:00
Matt Nadareski
0c327872b5 Increase sleep time in queue 2024-12-05 21:08:15 -05:00
Matt Nadareski
6ef9debac4 Add tests around default values 2024-12-05 16:39:43 -05:00
Matt Nadareski
10c7906e9d Ensure dumping commands are tested 2024-12-05 15:37:36 -05:00
Matt Nadareski
b922857578 Fix required Int32 array input 2024-12-05 15:21:52 -05:00
Matt Nadareski
dca5235a4a Wire up input boundaries 2024-12-05 15:19:38 -05:00
Matt Nadareski
07e747f7d3 Add Int32 array input type 2024-12-05 15:14:20 -05:00
Matt Nadareski
da67c58727 Add unused min/max parameters for numeric inputs 2024-12-05 15:05:54 -05:00
Matt Nadareski
0524ad7ac2 Add DIC parameters tests 2024-12-05 15:02:08 -05:00
Matt Nadareski
2a16be2c07 Replace Redumper flag values with input types 2024-12-05 13:29:51 -05:00
Matt Nadareski
a5a048fcb0 Add quotes option to string input 2024-12-05 13:22:17 -05:00
Matt Nadareski
b2ffa2025b Add Redumper parameters tests 2024-12-05 12:32:48 -05:00
Matt Nadareski
0d11e03507 Replace Aaru flag values with input types 2024-12-05 11:59:59 -05:00
Matt Nadareski
c72aeb7f58 Add Aaru parameters tests 2024-12-05 10:53:42 -05:00
Matt Nadareski
86eca8dee7 Use string builders where possible 2024-12-05 00:23:35 -05:00
Matt Nadareski
5e5360441a Replace Aaru pre-command flags 2024-12-05 00:06:24 -05:00
Matt Nadareski
5392afbf06 Fix some formatting issues with Input types 2024-12-04 23:08:17 -05:00
Matt Nadareski
c7c700e567 Let inputs read equal-separated values 2024-12-04 22:14:06 -05:00
Matt Nadareski
8c0bbfbf10 Handle issue with old .NET 2024-12-04 21:27:49 -05:00
Matt Nadareski
e7baa7d33f Add self-formatting to Input types 2024-12-04 21:20:38 -05:00
Matt Nadareski
724b1b6719 Add unused inputs to Aaru 2024-12-04 21:00:40 -05:00
Matt Nadareski
ab88f8ffaa Add flag for value being set 2024-12-04 20:30:21 -05:00
Matt Nadareski
6feda0e69d Split Input type into typed classes 2024-12-04 20:22:47 -05:00
Matt Nadareski
d704cec97b Add currently unused Input type 2024-12-04 19:28:34 -05:00
Matt Nadareski
9fe815676f Add BaseExecutionContext tests 2024-12-04 15:57:33 -05:00
Matt Nadareski
129a7ba63f Add tests around ProcessingTool 2024-12-04 14:53:07 -05:00
Matt Nadareski
4617401e8b Use recommended Min/Max/TryParse 2024-12-04 13:12:22 -05:00
Matt Nadareski
3cb037b5af Add safety around sidecar generation 2024-12-04 13:08:44 -05:00
Matt Nadareski
49b70b7ae1 Add tests around DIC helpers 2024-12-04 12:55:05 -05:00
Matt Nadareski
4eb346632a Add sanity check output file tests 2024-12-03 23:29:51 -05:00
Matt Nadareski
56fffb0ed9 Add tests around Redumper helpers 2024-12-03 23:06:54 -05:00
Matt Nadareski
8adde6f8d5 Fix missing test data 2024-12-03 21:10:22 -05:00
Matt Nadareski
eacd60562c Enable test running on package and PR 2024-12-03 20:58:40 -05:00
Matt Nadareski
f6df7e96c1 Add tests around PS3 CFW helpers 2024-12-03 20:55:28 -05:00
Matt Nadareski
0e37025150 Add tests around UIC helpers 2024-12-03 20:46:05 -05:00
Matt Nadareski
4e338d56cd Perform better path emptiness checks 2024-12-03 20:30:15 -05:00
Matt Nadareski
c26253007d Fix failing XBC test 2024-12-03 20:26:50 -05:00
Matt Nadareski
66b4bb4eb2 Add tests around XBC helpers 2024-12-03 20:20:18 -05:00
Matt Nadareski
034494558e Fix CleanRip test access 2024-12-03 16:55:40 -05:00
Matt Nadareski
cc7116a623 Add tests around CleanRip helpers 2024-12-03 16:55:14 -05:00
Matt Nadareski
011ca670e0 Add tests around some Aaru helpers 2024-12-03 16:29:50 -05:00
Matt Nadareski
956d8efcf7 Update tests to account for new file count 2024-12-03 15:45:28 -05:00
Matt Nadareski
ee4e77b208 Ensure SS.bin only required for DVD 2024-12-03 15:42:39 -05:00
Matt Nadareski
8eff11f0ae Add processor base implementation tests 2024-12-03 15:38:59 -05:00
Matt Nadareski
8d4f22a1c4 Add BaseProcessor tests 2024-12-03 14:04:59 -05:00
Matt Nadareski
3829ee1bbe Move existing tests to new projects 2024-12-03 13:27:55 -05:00
Matt Nadareski
61060e98df Add skeleton test projects for individual libraries 2024-12-03 13:22:55 -05:00
Matt Nadareski
7f061f22e0 Update packages 2024-12-03 13:20:05 -05:00
Matt Nadareski
e72336a835 Bump version 2024-11-24 19:55:26 -05:00
Deterous
886a0a4f07 Add support for Redumper Xbox dumps (#766)
* Add support for Redumper Xbox dumps

* Fix doubleup of ranges variable name

* Don't use FileInfo

* Fix RemoveHeader

* Use manual Stream.CopyTo

* Capitalise DMI/PFI/SS hashes

* Final cleanup

* Final final cleanup
2024-11-24 19:50:45 -05:00
Deterous
093435e7b0 Don't add trailing spaces to BCA output (#765)
* Don't add trailing spaces to BCA output

* Fix import

* Fix var name
2024-11-23 22:32:40 -05:00
Matt Nadareski
59a427963d Fix PS3 firmware version being omitted 2024-11-23 19:59:25 -05:00
Deterous
19d6006aff Cleanup CleanSS check (#763)
* Cleanup CleanSS check

* Make ssv2 check consistent
2024-11-22 23:15:15 -05:00
Matt Nadareski
617b0ba2c5 Version gate remaining Linq statements 2024-11-22 12:44:50 -05:00
Matt Nadareski
195c83499c Clean up usings after last commit 2024-11-22 11:56:12 -05:00
Matt Nadareski
e5b02c27a8 Replace some uses of Regex.Replace 2024-11-22 11:50:07 -05:00
Deterous
c7b6b08397 Improve parameters for default output path (#762)
* Improve parameters for default output path

* ToUpperInvariant
2024-11-22 10:55:20 -05:00
Matt Nadareski
da6b2f0e24 Remove unncessary .NET Framework 4.0 gating 2024-11-21 13:29:06 -05:00
Matt Nadareski
c50c3edcc5 Don't preemptively sort protections 2024-11-21 12:08:02 -05:00
Matt Nadareski
d628b2a0dd Use List in protection formatting 2024-11-21 12:06:12 -05:00
Matt Nadareski
f6baaa6f5e Reduce unnecessary use of IEnumerable 2024-11-21 11:55:00 -05:00
Matt Nadareski
b05c82e903 Remove usages of this. from UI code 2024-11-21 11:49:14 -05:00
Matt Nadareski
65f472c4c9 Fix minor efficiency issues 2024-11-21 11:46:11 -05:00
Matt Nadareski
104dd4348b Update packages for bugfixes 2024-11-21 11:27:57 -05:00
Matt Nadareski
2337a2ed86 Use expanded version of split regex (fixes #761) 2024-11-20 11:41:28 -05:00
Deterous
2ce632f8b4 Fix PIC parser (#760) 2024-11-19 13:01:15 -05:00
Matt Nadareski
ce917f4f61 Remove usages of this. from themes 2024-11-18 15:44:43 -05:00
Matt Nadareski
d029cf4164 Add IMA extension for floppy disks 2024-11-18 15:39:43 -05:00
Matt Nadareski
74d52c2f3b Add Track 0/00/A/AA to Generic 2024-11-18 15:18:05 -05:00
Matt Nadareski
785786c3a9 Add unused "Generic" processor 2024-11-18 13:24:19 -05:00
Matt Nadareski
466d8f58b0 Add skeleton to Redumper CD by default 2024-11-18 12:22:50 -05:00
Matt Nadareski
bc690614e6 Remove usages of this. in more places 2024-11-18 12:21:13 -05:00
Deterous
d44798b27c Fix fully matching when multiple matches found (#759)
Co-authored-by: Matt Nadareski <mnadareski@outlook.com>
2024-11-17 19:33:09 -05:00
Matt Nadareski
595cd0d60f Consolidate parameter string splitting 2024-11-16 01:23:30 -05:00
Matt Nadareski
68fd5a2aa0 Be smarter about some data types 2024-11-16 01:07:47 -05:00
Matt Nadareski
6da98aa65c Add .NET 9 to target frameworks 2024-11-16 00:37:14 -05:00
Matt Nadareski
d8d149446f Be smarter about Linq usage 2024-11-12 22:18:08 -05:00
Matt Nadareski
4d0f48be10 Update Redumper to build 438 2024-11-06 16:06:22 -05:00
Matt Nadareski
8a048c8a57 Bump version 2024-11-06 15:36:56 -05:00
Matt Nadareski
d51db072fc Force rebuild of rolling 2024-11-05 15:33:45 -05:00
Matt Nadareski
468c9937da Reduce null use in BaseProcessor 2024-11-05 15:30:54 -05:00
Matt Nadareski
206ac76633 Fix missed GetOutputFiles invocation 2024-11-05 15:23:03 -05:00
Matt Nadareski
339b0d93d1 Ensure debug symbols are stripped 2024-11-05 14:13:18 -05:00
Matt Nadareski
fd5da5de74 Add conf to build matrix 2024-11-05 13:53:05 -05:00
Matt Nadareski
42146f991d Attempt to reduce nesting in GHA builds 2024-11-05 13:46:44 -05:00
Matt Nadareski
f3f05eee48 Attempt to reduce nesting in GHA builds 2024-11-05 13:45:40 -05:00
Matt Nadareski
61bf2f69aa Attempt to reduce nesting in GHA builds 2024-11-05 13:40:05 -05:00
Matt Nadareski
546aa70b69 Update BinaryObjectScanner to 3.1.16 2024-11-05 13:17:49 -05:00
Matt Nadareski
65cd1cede3 Remove last instances of ValueTuple usage 2024-11-03 23:14:22 -05:00
Matt Nadareski
dffa16139a Remove tupling from everything except CLI programs 2024-11-03 23:09:54 -05:00
Matt Nadareski
98bacf11fc Reduce tupling even more 2024-11-03 22:51:24 -05:00
Matt Nadareski
ee0ccecfb2 Replace user info func with ProcessUserInfoDelegate 2024-11-03 22:29:26 -05:00
Matt Nadareski
a0825f276b Use new ProtectionDictionary type 2024-11-03 22:15:42 -05:00
Matt Nadareski
66d61e20de Reduce call complexity for login result 2024-11-03 21:59:22 -05:00
Matt Nadareski
6455ebd434 Simplify GetMediaType return 2024-11-03 21:55:04 -05:00
Matt Nadareski
f4436fddfa Remove unused CompilerServices.Unsafe library 2024-11-03 21:06:14 -05:00
Matt Nadareski
317777cf93 Remove old .NET version of ValueTuple where possible 2024-11-03 20:40:36 -05:00
Matt Nadareski
da6dbe136e Remove unnecessary System.ValueTuple usage 2024-11-03 20:38:35 -05:00
Matt Nadareski
13d7cf8124 Remove unused IndexRange library 2024-11-03 20:16:48 -05:00
Matt Nadareski
bb8fea625b Update BinaryObjectScanner to 3.1.15 2024-11-03 20:13:38 -05:00
Matt Nadareski
15a0659867 Use rolling release, not AppVeyor, in issue templates 2024-10-22 12:39:51 -04:00
Matt Nadareski
988a5f6d2b Update RedumpLib to 1.4.4 2024-10-18 13:04:53 -04:00
Matt Nadareski
1941639473 No directory means no files 2024-10-16 12:04:39 -04:00
Matt Nadareski
d1772f743e Reduce cleverness in output file code 2024-10-16 11:45:06 -04:00
Matt Nadareski
870c2d1cec Add separate field for Regex; assorted cleanup 2024-10-16 02:48:39 -04:00
Matt Nadareski
f7f6ae1eee Ensure Regex directories are unescaped 2024-10-16 02:31:11 -04:00
Matt Nadareski
dd9e527592 Use new output file logic in processors 2024-10-16 01:57:31 -04:00
Matt Nadareski
e1122fa976 Ensure consistency in output file path checking (fixes #755) 2024-10-16 01:56:48 -04:00
Matt Nadareski
8a44fa3355 Ensure that the full base path is being used 2024-10-14 21:47:05 -04:00
Matt Nadareski
51a9e3005f Use fake filename for Redumper DAT 2024-10-14 21:23:16 -04:00
Matt Nadareski
413b6da24b Fix trimming of header output (fixes #754) 2024-10-13 11:00:07 -04:00
Matt Nadareski
172a0fb5dc Update Redumper to build 416 2024-10-12 20:13:27 -04:00
Matt Nadareski
83a189a5d3 Format CleanRip BCA wtih 2-byte blocks (fixes #743) 2024-10-10 12:02:22 -04:00
Matt Nadareski
60c27ec89b Sum track errors in Redumper (fixes #745) 2024-10-10 11:19:27 -04:00
Matt Nadareski
51733557cd Remove ReadLine in list commands 2024-10-10 11:11:54 -04:00
Matt Nadareski
93d964c603 Make .NET 8 the default in issue reports 2024-10-09 12:37:21 -04:00
Matt Nadareski
2925f2262b Change multiple offset delimiter 2024-10-08 22:04:03 -04:00
Matt Nadareski
5b211a7345 Fix faulty offset dedupe logic 2024-10-08 21:53:06 -04:00
Matt Nadareski
ed4bd24fcb Include all DIC write offsets (fixes #750) 2024-10-08 15:47:24 -04:00
Matt Nadareski
8a7761753b Update to DIC 20241001 2024-10-01 22:44:41 -04:00
Matt Nadareski
1b8cca9999 Update changelog 2024-10-01 10:55:33 -04:00
TheRogueArchivist
b75391b1c6 Fix SafeDisc filtering (#749)
* Start updating filtering for SafeDisc

This will need more work, as it is currently incomplete, unoptimized, and untested.

* Further updates to SafeDisc Filtering

Still not done, but most if not all the major edge cases should be accounted for. Mostly just needs testing to make sure I didn't accidentally break something along the way, and further polishing of code and outputs.

* Further update to SafeDisc Filtering

More cleanly covers another specific case.

* Hopefully final main additions to SafeDisc filtering

* Update SafeDisc matching for newest BOS

Fix things that broke with the BOS update, and update a few comments.
2024-10-01 10:53:58 -04:00
Matt Nadareski
e9c2fd9245 Update BinaryObjectScanner to 3.1.14 2024-09-28 13:21:37 -04:00
Matt Nadareski
fb24bbd8a5 Update to DIC 20240901 2024-09-26 10:56:50 -04:00
Matt Nadareski
4e3083c8e6 Fix date 2024-09-24 14:11:02 -04:00
Matt Nadareski
05738b7c11 Bump version 2024-09-24 13:43:18 -04:00
Matt Nadareski
f963db67b1 Update changelog 2024-09-07 01:25:28 -04:00
TurnedToast
de64631c00 Add _drive.txt file to GetOutputFiles for UmdImageCreator (#748)
* add _drive.txt file to GetOutputFiles for UmdImageCreator

* remove required from _drive

* disc -> drive
2024-09-07 01:24:49 -04:00
Matt Nadareski
c8adef78c2 Update changelog 2024-09-06 22:53:02 -04:00
TurnedToast
7b116e7a04 Ensure manufacturer files starting from 0 are zipped in redumper DVD … (#747)
* Ensure manufacturer files starting from 0 are zipped in redumper DVD processing

* Remove extraneous DVD manufacturer/physical, add needed physical for bluray
2024-09-06 22:52:20 -04:00
Matt Nadareski
fb7b6ff1be Fix typo in publisher identifiers 2024-09-05 19:47:07 -04:00
Matt Nadareski
7fb8e44c31 Forgot to assume directories don't exist 2024-08-29 01:53:49 -04:00
Matt Nadareski
239ad4c4bc Handle XGD required files 2024-08-23 21:44:54 -04:00
Matt Nadareski
9834d0ea3e Fix access permissions of output file classes 2024-08-23 21:39:50 -04:00
Matt Nadareski
a35c13bd10 Add and use CustomOutputFile 2024-08-23 21:36:04 -04:00
Matt Nadareski
5e1777a7c7 Add future XGD output files 2024-08-23 21:24:12 -04:00
Matt Nadareski
66570300df Forgot the other locations 2024-08-23 21:20:55 -04:00
Matt Nadareski
4ac1fb201e Less confusing implmentation of DatfileExists 2024-08-23 21:19:07 -04:00
Matt Nadareski
cba8daa010 Add archive override for RegexOutputFile 2024-08-23 21:08:43 -04:00
Matt Nadareski
ba24a4b21a Create and use RegexOutputFile 2024-08-23 20:58:55 -04:00
Matt Nadareski
91c6fdac82 Use simplified CheckAllOutputFilesExist 2024-08-23 20:39:30 -04:00
Matt Nadareski
416656c457 Rename new method to CheckRequiredFiles 2024-08-23 20:29:48 -04:00
Matt Nadareski
fdd75818c4 Rename new method to 2024-08-23 20:29:36 -04:00
Matt Nadareski
ac302626c2 Add new, unused CheckAllOutputFilesExist variant 2024-08-23 20:27:58 -04:00
Matt Nadareski
428f3cc547 Minor tweaks to existing code 2024-08-23 19:47:10 -04:00
Matt Nadareski
66fc36fe3c Add runtime error for improperly created artifacts 2024-08-23 17:07:24 -04:00
Matt Nadareski
9dddf1c9b6 Use new func in Redumper 2024-08-23 16:49:27 -04:00
Matt Nadareski
5dbb955d26 Pass in new func for OutputFile 2024-08-23 16:42:04 -04:00
Matt Nadareski
2f2958bdea Add unused passable func to OutputFile 2024-08-23 16:32:33 -04:00
Matt Nadareski
c91f6ebbce Fix recursive issue in AddToArchive 2024-08-23 16:27:51 -04:00
Matt Nadareski
22fdd036eb Fix new AddToArchive methods 2024-08-23 16:23:45 -04:00
Matt Nadareski
3f12c6acb9 Rearrange some BaseProcessor methods 2024-08-23 16:17:22 -04:00
Matt Nadareski
1dbae18da6 Fix broken build 2024-08-23 13:51:10 -04:00
Matt Nadareski
6370e2dd6a Fix up some file path methods 2024-08-23 13:47:08 -04:00
Matt Nadareski
0c8879bc66 Split new output file methods 2024-08-23 13:34:55 -04:00
Matt Nadareski
6be34414fe Make GenerateArtifacts return a dictionary 2024-08-22 15:07:13 -04:00
Matt Nadareski
f15fc989c8 Add artifact keys for all relevant files 2024-08-22 15:03:36 -04:00
Matt Nadareski
0fc53cb534 Define new ArtifactKey field 2024-08-22 14:46:50 -04:00
Matt Nadareski
dc0909808a Replace GenerateArtifacts with common code 2024-08-22 14:43:09 -04:00
Matt Nadareski
00401d1282 Move GetLogFilePaths to better location 2024-08-22 14:27:12 -04:00
Matt Nadareski
b9d0d5d8f6 Replace GetLogFilePaths with common code 2024-08-22 14:26:43 -04:00
Matt Nadareski
22a6b77d27 Hook up GetOutputFiles in debug way 2024-08-22 14:22:37 -04:00
Matt Nadareski
bc4fe17fab Add unused GetOutputFiles method 2024-08-22 14:13:52 -04:00
Matt Nadareski
4b4027f285 Make helper class more robust 2024-08-22 13:18:47 -04:00
Matt Nadareski
d28257b2b7 Create currently-unused helper class 2024-08-22 12:57:07 -04:00
Matt Nadareski
669ef47f32 Start preparing for better output file checks 2024-08-22 12:27:00 -04:00
Matt Nadareski
be224800bc Remove redundant drive calls 2024-08-21 00:45:06 -04:00
Matt Nadareski
8dbb589d42 Create some PlayStation helper methods 2024-08-21 00:35:54 -04:00
Matt Nadareski
7b2fd5bf35 Fix minor inconsistencies 2024-08-20 23:28:25 -04:00
Matt Nadareski
95fa651074 Move MSXC parsing to PhysicalTool 2024-08-20 23:26:42 -04:00
Matt Nadareski
a0a155eb9b Preemptively update Redumper Saturn support 2024-08-20 23:12:01 -04:00
Matt Nadareski
72339b18df Remove GD-ROM version fallback method 2024-08-20 22:57:46 -04:00
Matt Nadareski
95c9c7706d Include serial for UMD (fixes #742) 2024-08-20 21:16:49 -04:00
Matt Nadareski
135bb43cdf Use new BEE method in code 2024-08-20 14:12:39 -04:00
Matt Nadareski
cfc75ca84d Move BEE method to better location 2024-08-20 14:08:51 -04:00
Matt Nadareski
33c35b63d7 Add bus encryption enabled method 2024-08-20 14:04:51 -04:00
Matt Nadareski
851a43d46f Rename 2 XGD helper methods 2024-08-20 13:53:09 -04:00
Matt Nadareski
a88bef481d Make GD-ROM LD code nicer to read 2024-08-20 13:01:46 -04:00
Matt Nadareski
781fec2b57 Futureproof GD-ROM LD in Redumper 2024-08-20 12:51:31 -04:00
Matt Nadareski
ee96367a45 Support GD-ROM info for Redumper (fixes #741) 2024-08-20 12:30:46 -04:00
Matt Nadareski
9f9bfc0888 Hash DMI and PFI files for XGD in Redumper 2024-08-18 13:53:49 -04:00
Matt Nadareski
c6cc697320 Prepare Redumper for XGD support 2024-08-18 13:40:39 -04:00
Deterous
5e3f7f740b Fix cleaning XGD3 SS (#740) 2024-08-18 10:41:44 -04:00
Matt Nadareski
e17a8f4708 Allow separate mounted path for Linux (fixes #739) 2024-08-16 20:25:39 -04:00
Matt Nadareski
ff4771a74a Quote input paths if needed (fixes #738) 2024-08-16 19:40:51 -04:00
Matt Nadareski
426717102d Add more verbose requirement to CLI help 2024-08-16 14:44:03 -04:00
Matt Nadareski
126bae33a4 Fix some CLI issues (fixes #736, fixes #737) 2024-08-16 14:29:42 -04:00
Matt Nadareski
11b8dd44bb Fix config location in OptionsLoader 2024-08-08 13:59:21 -04:00
Deterous
cbbb8aaa8c Fix XGD3 SS ranges (#733)
* Fix XGD3 SS ranges

* Changelog
2024-08-06 22:34:33 -04:00
Matt Nadareski
9ee7cd7fd7 Move two extensions to a better location 2024-08-06 20:47:52 -04:00
Matt Nadareski
324c1fcee3 Fix build for older .NET 2024-08-06 16:59:04 -04:00
Matt Nadareski
06776a6093 Add physical drive extensions to new tool 2024-08-06 16:52:37 -04:00
Matt Nadareski
43a079bb28 Fix usings ordering in ItemHelper 2024-08-06 16:18:39 -04:00
Matt Nadareski
d45345d338 Add comments around default options object 2024-08-06 14:18:08 -04:00
Matt Nadareski
1ff0340cae Add Check flags for protection scan extras 2024-08-06 14:16:44 -04:00
Matt Nadareski
278c86f9f4 Clean up some Check options, add IRD option 2024-08-06 14:09:05 -04:00
Matt Nadareski
00089b799c Bump version 2024-08-05 12:23:58 -04:00
Matt Nadareski
0f98f03999 Update changelog 2024-07-26 10:12:22 -04:00
Deterous
22f6f39a91 Enable loading seed JSON (#731)
* Enable loading seed JSON

* Safer function call
2024-07-26 10:11:39 -04:00
Matt Nadareski
e9a9011dbd Update RedumpLib to 1.4.1 2024-07-24 11:45:12 -04:00
Matt Nadareski
40bbb3d1c8 Update changelog 2024-07-19 10:55:55 -04:00
John Veness
a48dad817b Remove old --protect-file mentions (#728)
The --protect-file option itself was removed in e0482aad78
2024-07-19 10:55:23 -04:00
Matt Nadareski
9f76dcc5fd Add include artifacts flag for check, sanitize options (fixes #726) 2024-07-19 10:20:45 -04:00
Matt Nadareski
4356561a8a Update changelog 2024-07-19 10:16:30 -04:00
John Veness
347c522d62 Change to generic wording in report (#727) 2024-07-19 10:15:59 -04:00
Matt Nadareski
998ecec261 Remove RedumpLib tests 2024-07-16 13:08:28 -04:00
Matt Nadareski
ab8e775df0 Fix broken test logic 2024-07-16 13:03:58 -04:00
Matt Nadareski
246e6b8bfd Update changelog 2024-07-16 13:01:52 -04:00
John Veness
c7f69de18f Fix logic for deducing region from PlayStation ISN (#724)
* Deduce PS2 region from Redumper serial

* Fix logic for deducing region from PlayStation ISN

* Fix logic again

* Fix logic again again

* Fix this too

* Undo Redumper change

* Reorder functions

* Fix OR/AND logic
2024-07-16 13:00:11 -04:00
John Veness
d4a98d7712 Fix URLs in github issue templates (#717) 2024-07-15 16:42:01 -04:00
Deterous
2983266e8a Fix parameters after extension change (#721) 2024-07-06 23:48:34 -04:00
Deterous
1baef4440a Don't set MediaType if parameters ambiguous (#720) 2024-07-06 22:28:04 -04:00
Matt Nadareski
7cd25dae1c Remove now-unncessary names 2024-06-26 03:26:08 -04:00
Matt Nadareski
38f9b7234b Bring Check and CLI in parity with param processing 2024-06-26 03:24:44 -04:00
Matt Nadareski
2d7ea1bed9 Fix CLI help text alignment 2024-06-25 19:31:01 -04:00
Matt Nadareski
806a69c280 Simplify custom parameters warning 2024-06-25 17:31:38 -04:00
Matt Nadareski
a92159b8cb Try out custom options classes 2024-06-25 17:29:32 -04:00
Matt Nadareski
9451629461 Add some custom CLI parameters 2024-06-25 17:11:24 -04:00
Matt Nadareski
51a1f0cc8e Move some Check-specific methods 2024-06-25 16:48:24 -04:00
Matt Nadareski
2830641b8a Move GetDefaultSpeedForMediaType to common location 2024-06-25 16:42:23 -04:00
Matt Nadareski
7c87a22dcc Fix minimum number of args checks 2024-06-25 16:37:26 -04:00
Matt Nadareski
dd5b5d4c7d Use speed for CLI from configuration 2024-06-25 16:32:41 -04:00
Deterous
bc5e73d371 Custom theme colors (#712)
* Custom theme colors

* Use Convert.ToByte
2024-06-25 16:27:38 -04:00
Matt Nadareski
f47a55b723 Ensure tracks are assigned in Aaru 2024-06-24 15:00:13 -04:00
Matt Nadareski
c4d014e480 Add CLI status output on runtime 2024-06-24 14:22:15 -04:00
Matt Nadareski
69b1d2f7ad Blindly assume the path exists 2024-06-24 12:17:57 -04:00
Matt Nadareski
7c295ca2f4 Try to make config safer for CLI 2024-06-24 11:55:28 -04:00
Matt Nadareski
5af3aad68a Dispose of stream when creating config 2024-06-24 11:43:22 -04:00
Matt Nadareski
f150483e84 Load options before anything else 2024-06-24 11:38:13 -04:00
Matt Nadareski
92ef962f42 Allow custom parameters for CLI 2024-06-24 11:22:18 -04:00
Matt Nadareski
859e53f843 Save default config values for CLI 2024-06-24 11:04:48 -04:00
Matt Nadareski
e70d70ca22 Add CLI information to README 2024-06-24 10:46:40 -04:00
Matt Nadareski
c2cf8147d3 Add CLI build status to README 2024-06-24 10:38:45 -04:00
Matt Nadareski
cf32f38c0e Add preliminary MPF.CLI 2024-06-24 10:37:05 -04:00
Matt Nadareski
1f92ff08d6 Seal all theme classes 2024-06-24 09:45:04 -04:00
Matt Nadareski
6aaf076434 Separate themes into own namespace and files 2024-06-24 09:44:06 -04:00
Deterous
6865b23aa7 Purple (#711) 2024-06-23 21:46:15 -04:00
Matt Nadareski
e1c13982bd Remove empty gitmodules 2024-06-20 15:42:56 -04:00
Matt Nadareski
9cddcc2eae Update README with new build matricies 2024-06-20 14:40:42 -04:00
Matt Nadareski
33932fad47 Enable last runtime by default 2024-06-20 14:38:06 -04:00
Matt Nadareski
470e5c69fe Add flag values to script settings 2024-06-20 14:12:16 -04:00
Matt Nadareski
3aae2990a3 Better support build matricies 2024-06-20 13:56:28 -04:00
Matt Nadareski
503933e67f Add osx-arm64 to libraries 2024-06-20 12:21:28 -04:00
Matt Nadareski
1a99fd9e71 Forgot to upload packages to release 2024-06-20 12:10:04 -04:00
Matt Nadareski
affc175bda Fix nuget package naming 2024-06-20 12:06:09 -04:00
Matt Nadareski
fe4c88d3ad Add Linux ARM64 as target by default 2024-06-20 12:00:26 -04:00
Matt Nadareski
9c830c9755 Address build warnings for packages 2024-06-20 11:54:40 -04:00
Matt Nadareski
fc300465f8 Add nuget packing for processors and contexts 2024-06-20 11:51:28 -04:00
Matt Nadareski
de1032a099 Bump version 2024-06-20 11:33:58 -04:00
Matt Nadareski
aa22b9fbff Fix excluding programs in nix script 2024-06-18 15:28:35 -04:00
Matt Nadareski
a41f0d6237 Update BinaryObjectScanner to 3.1.12 2024-06-17 16:23:55 -04:00
Matt Nadareski
9d5dfaaa68 Make match sets immutable 2024-06-12 14:49:16 -04:00
Matt Nadareski
7f08684e9a Fix... something with Linux publish script 2024-06-12 14:04:56 -04:00
Matt Nadareski
8c2ad6eca5 Move track full matching to separate loop 2024-06-12 13:36:52 -04:00
Matt Nadareski
dad108de52 Simplify DIC DMI location finding 2024-06-03 21:03:16 -04:00
Matt Nadareski
df3bf1f7c5 Handle Redumper .atip and .pma files 2024-06-03 20:53:41 -04:00
Matt Nadareski
0e355b906c Handle Redumper .asus files 2024-06-03 20:41:53 -04:00
Matt Nadareski
1d472bf777 Add update parameter to unzip 2024-06-03 13:08:45 -04:00
Matt Nadareski
a7e0ac0806 Fix UI build workflow 2024-06-03 12:06:09 -04:00
Matt Nadareski
5a208926a5 Update to DIC 20240601 2024-06-01 23:21:39 -04:00
Matt Nadareski
d812ea7e2b Add PS3 info extraction for DIC 2024-05-31 10:41:56 -04:00
Matt Nadareski
f19111a1b0 Clean up some ProcessSystem cases 2024-05-31 00:07:40 -04:00
Matt Nadareski
a36f7d7df4 Fix setting Python 2 version on invalid 2024-05-31 00:03:40 -04:00
Matt Nadareski
c5e8de6c1a Fix setting PS1-5 version on invalid 2024-05-30 12:28:31 -04:00
Matt Nadareski
6ebcca104f Fix logic for PS1-5 system information 2024-05-29 13:07:10 -04:00
Matt Nadareski
3f048c5243 Rearrange test classes to match new format 2024-05-28 15:30:16 -04:00
Matt Nadareski
dffebc5d43 Move ToRedumper* back to EnumExtensions 2024-05-28 15:20:28 -04:00
Matt Nadareski
37f2cf5bab Ensure setting defaults are consistent 2024-05-28 15:16:28 -04:00
Matt Nadareski
9865f88a6f Fix one DIC parameter test 2024-05-28 14:51:43 -04:00
Matt Nadareski
90d4d0d029 Move Redumper enums to a better place 2024-05-28 14:41:51 -04:00
Matt Nadareski
68c3d7c4fa Remove magic strings from settings reading 2024-05-28 14:37:15 -04:00
Matt Nadareski
503a6a8cdc Create Frontend.Tools namespace 2024-05-28 14:19:59 -04:00
Matt Nadareski
c10b3d28bd Remove Core library, fix build 2024-05-28 14:16:00 -04:00
Matt Nadareski
d349ef8a9d Combine remaining Core into Frontend 2024-05-28 14:12:36 -04:00
Matt Nadareski
3137a543a7 Decouple execution contexts from Options class 2024-05-28 14:07:18 -04:00
Matt Nadareski
7b832049e8 Move StringEventArgs to Frontend 2024-05-28 13:47:06 -04:00
Matt Nadareski
6566db5913 Remove unused reporter delegate 2024-05-28 13:46:00 -04:00
Matt Nadareski
8c70f19959 Move ResultEventArgs to Frontend 2024-05-28 13:44:57 -04:00
Matt Nadareski
898069c799 Move Drive to Frontend 2024-05-28 13:15:31 -04:00
Matt Nadareski
01e991c5fd emove Drive dependency from GenerateSubmissionInfo 2024-05-28 13:07:16 -04:00
Matt Nadareski
3b21fa62a0 Hacky move of DIC-specific code 2024-05-28 13:00:39 -04:00
Matt Nadareski
12a13a2ffa Slight readability cleanup in DIC 2024-05-28 12:50:01 -04:00
Matt Nadareski
074d2c031c Treat KP2 like PS2 in DIC 2024-05-28 12:21:02 -04:00
Matt Nadareski
e33588451d Move EnumExtensions to Frontend 2024-05-28 12:00:05 -04:00
Matt Nadareski
f2ba433859 Merge VersionTool into FrontendTool 2024-05-28 11:57:53 -04:00
Matt Nadareski
b266467c33 Clear out InfoTool and remove 2024-05-28 11:53:15 -04:00
Matt Nadareski
8eece24d9a Create FrontendTool and move some methods to it 2024-05-28 11:51:10 -04:00
Matt Nadareski
bb644e9a8b Move InfoTool to root of Core 2024-05-28 11:45:00 -04:00
Matt Nadareski
c07ca9f39c Move VersionTool to root of Core 2024-05-28 11:40:17 -04:00
Matt Nadareski
bb92c43b35 Rename Tools to VersionTool 2024-05-28 11:38:58 -04:00
Matt Nadareski
b9d6a13e20 Move ProgramSupportsMedia to MainViewModel 2024-05-28 11:36:58 -04:00
Matt Nadareski
891499710f Centralize PS1/2 region detection 2024-05-28 11:32:34 -04:00
Matt Nadareski
1328a373ea Clean up usings 2024-05-28 11:22:42 -04:00
Matt Nadareski
4a59ce1d90 Move PS3 helpers to ProcessingTool 2024-05-28 11:19:33 -04:00
Matt Nadareski
7a74042aef Move Xbox/X360 helpers to ProcessingTool 2024-05-28 11:13:17 -04:00
Matt Nadareski
2f7abee51b Move output writing to DumpEnvironment 2024-05-28 11:02:09 -04:00
Matt Nadareski
a63c844ed1 Move drive-reading methods to Drive 2024-05-28 10:56:34 -04:00
Matt Nadareski
91a0e85e24 Centralize dumping program information gathering 2024-05-28 10:34:33 -04:00
Matt Nadareski
c9a67b1b51 Move ToInternalProgram to Options 2024-05-28 10:16:50 -04:00
Matt Nadareski
3d932705bc Move DoesSupportDriveSpeed to DumpEnvironment 2024-05-28 10:15:32 -04:00
Matt Nadareski
80cde96614 Move ListPrograms to OptionsLoader 2024-05-28 10:12:06 -04:00
Matt Nadareski
aae81035c1 Move ToMediaType to OptionsLoader 2024-05-28 10:10:50 -04:00
Matt Nadareski
d08716045a Move ToRedumper* methods to Options 2024-05-28 10:08:53 -04:00
Matt Nadareski
f34999e308 Move ProtectionTool to Frontend 2024-05-28 00:37:42 -04:00
Matt Nadareski
028f7d5788 Slight cleanup of InfoTool 2024-05-28 00:32:28 -04:00
Matt Nadareski
c34aeb6e45 Move GetCopyProtection to ProtectionTool 2024-05-28 00:31:27 -04:00
Matt Nadareski
bdb367c2c9 Call psxt001z direct from DIC processor 2024-05-28 00:29:56 -04:00
Matt Nadareski
63e6ce121a Move GetSupportStatus to DumpEnvironment 2024-05-28 00:19:34 -04:00
Matt Nadareski
ac072618c4 Remove unused byte array helper methods 2024-05-28 00:15:43 -04:00
Matt Nadareski
7a640c58ee Create ProcessingTool and move some methods 2024-05-28 00:13:17 -04:00
Matt Nadareski
5ad75c80d1 Move LogLevel enum to Frontend 2024-05-27 23:52:55 -04:00
Matt Nadareski
78d648d90b Move ProcessingQueue to Frontend 2024-05-27 23:48:48 -04:00
Matt Nadareski
d415a8f161 Move ConsoleLogger to Check CLI 2024-05-27 23:40:19 -04:00
Matt Nadareski
87ba8d573d Tools always run in separate window 2024-05-27 23:34:42 -04:00
Matt Nadareski
55a84fc911 Update Redumper to build 371 2024-05-27 22:13:55 -04:00
Matt Nadareski
f9351ff058 Standardize PS1-5 outputs and parsing 2024-05-27 21:45:06 -04:00
Matt Nadareski
e0482aad78 Make protection file output required 2024-05-27 13:58:06 -04:00
Matt Nadareski
9243020cd6 Fix build scripts 2024-05-23 21:50:47 -04:00
Matt Nadareski
616f3624b7 Rename main application to MPF.UI 2024-05-23 21:40:42 -04:00
Matt Nadareski
aff981171a Merge UI.Core into main application 2024-05-23 21:35:02 -04:00
Matt Nadareski
4816c5ab6a Move Aaru CICM code to Processors 2024-05-23 21:23:02 -04:00
Matt Nadareski
77f9b048fb Clean up Core dependencies 2024-05-23 21:18:05 -04:00
Matt Nadareski
846db2f602 Move Aaru CICM code to Core 2024-05-23 21:01:04 -04:00
Matt Nadareski
6a21ca9f86 Fix up visual solution 2024-05-23 20:53:54 -04:00
Matt Nadareski
9613cae204 Rename Core.* libraries 2024-05-23 15:40:12 -04:00
Matt Nadareski
59102a8330 Split Core.ExecutionContexts into separate library 2024-05-23 15:25:40 -04:00
Matt Nadareski
52f51cf1ab Split Core.Processors into separate library 2024-05-23 15:20:53 -04:00
Matt Nadareski
98ae16f7ae Split Core.Frontend into separate library 2024-05-23 15:15:43 -04:00
Matt Nadareski
c0d8a87c44 Decouple Frontend from execution contexts 2024-05-23 15:07:25 -04:00
Matt Nadareski
7a120d155a Move Options to root of Core 2024-05-23 15:04:13 -04:00
Matt Nadareski
d99da089ef Move EnumExtensions to root of core 2024-05-23 14:42:07 -04:00
Matt Nadareski
d76cd346d4 Move SubmissionGenerator to Core.Frontend 2024-05-23 14:37:40 -04:00
Matt Nadareski
5082ca57c4 Rename SubmissionInfoTool to SubmissionGenerator 2024-05-23 14:36:27 -04:00
Matt Nadareski
c31eeb001a Decouple InfoTool from processors 2024-05-23 14:34:32 -04:00
Matt Nadareski
bef4bf175c Move Logging to Core.Frontend 2024-05-23 14:27:58 -04:00
Matt Nadareski
ac744a1e6d Move OptionsLoader to Core.Frontend 2024-05-23 14:26:16 -04:00
Matt Nadareski
13d7d83dbb Remove useless using statement 2024-05-23 14:23:39 -04:00
Matt Nadareski
7608c08e7c Move Options to Core.Frontend 2024-05-23 14:21:15 -04:00
Matt Nadareski
c5c180a9c6 Move DumpEnvironment to Core.Frontend 2024-05-23 14:17:40 -04:00
Matt Nadareski
9bce6aea1a Rename Core.UI namespace to Core.Frontend 2024-05-23 14:16:32 -04:00
Matt Nadareski
7cd84e2e9a Move GetRedumpSystem to MainViewModel 2024-05-23 14:12:50 -04:00
Matt Nadareski
b8d7bbc72e Make FormattedVolumeLabel a method 2024-05-23 14:07:42 -04:00
Matt Nadareski
a60f11135e Clean up EnumExtensions 2024-05-23 14:02:02 -04:00
Matt Nadareski
c2664a1d2d Move ToInternalDriveType to Drive 2024-05-23 14:01:47 -04:00
Matt Nadareski
e5632634d0 Move Enumerations to root of Core 2024-05-23 13:51:14 -04:00
Matt Nadareski
daa3261c16 Move Options to root of Core 2024-05-23 13:47:14 -04:00
Matt Nadareski
dbf7150a31 Move Drive to root of Core 2024-05-23 13:45:21 -04:00
Matt Nadareski
893fd34d36 Move ProtectionTool to Core.Utilities 2024-05-23 13:42:53 -04:00
Matt Nadareski
e1961612c0 Rename Protection to ProtectionTool 2024-05-23 13:41:43 -04:00
Matt Nadareski
0f1b23056c Fix build 2024-05-23 13:40:59 -04:00
Matt Nadareski
26254e6b32 Move SubmissionInfoTool to Core.Utilities 2024-05-23 13:39:35 -04:00
Matt Nadareski
505fbf2567 Move InfoTool to Core.Utilities 2024-05-23 13:38:05 -04:00
Matt Nadareski
1bb38ea987 Move processing queue to root of Core 2024-05-23 13:34:05 -04:00
Matt Nadareski
a3144b1537 Move event args to root of Core 2024-05-23 13:33:02 -04:00
Matt Nadareski
ad90e2b6f9 Merge EnumConverter and EnumExtensions 2024-05-23 13:29:31 -04:00
Matt Nadareski
705060fa70 Remove firmware output for Redumper 2024-05-22 21:30:43 -04:00
Matt Nadareski
f8e8c02fcf Remove options from UI 2024-05-22 20:48:11 -04:00
Matt Nadareski
eacee24d45 Remove automatic eject and reset options 2024-05-22 20:46:17 -04:00
Matt Nadareski
d980fffa09 Clean up usings 2024-05-22 16:56:43 -04:00
Matt Nadareski
853b8689b4 Make RunProtectionScanOnPath signature easier to read 2024-05-22 16:56:14 -04:00
Matt Nadareski
7e4089f79c Move GetLibCryptDetected back to DIC processor 2024-05-22 16:54:04 -04:00
Matt Nadareski
54ee2829f1 Make GetCopyProtection signature easier to read 2024-05-22 16:46:50 -04:00
Matt Nadareski
f89cac5400 Remove unnecessary GetAntiModchipDetected method 2024-05-22 16:45:28 -04:00
Matt Nadareski
b003203aef Reduce complexity of ProcessSystem method 2024-05-22 16:44:18 -04:00
Matt Nadareski
4e5c9a242e Simplify RequiredProgramsExist logic 2024-05-22 16:34:01 -04:00
Matt Nadareski
5edb70745a Make drive private to DumpEnvironment 2024-05-22 16:24:01 -04:00
Matt Nadareski
f474b339ac Make system private to DumpEnvironment 2024-05-22 16:20:17 -04:00
Matt Nadareski
bb9a344938 Make media type private to DumpEnvironment 2024-05-22 16:16:56 -04:00
Matt Nadareski
75ad9eae28 Make context private to DumpEnvironment 2024-05-22 16:13:14 -04:00
Matt Nadareski
2b3b029545 Make processor private to DumpEnvironment 2024-05-22 15:59:43 -04:00
Matt Nadareski
9843644dfc Remove other reference to execution context 2024-05-22 15:46:57 -04:00
Matt Nadareski
54103a1d7e Execution context is not needed to extract info 2024-05-22 15:45:16 -04:00
Matt Nadareski
5da277ae64 Move GetRedumpSystemFromVolumeLabel to InfoTool 2024-05-22 15:28:49 -04:00
Matt Nadareski
51461a958d Remove use of "this" in Drive 2024-05-22 15:26:55 -04:00
Matt Nadareski
6d1fd9d47d Seal all execution contexts 2024-05-22 15:14:48 -04:00
Matt Nadareski
6b6f888dc3 Use proper private variable naming in ProcessingQueue 2024-05-22 15:04:47 -04:00
Matt Nadareski
1c6a9da9c8 Remove use of "this" in ProcessingQueue 2024-05-22 15:03:55 -04:00
Matt Nadareski
c335cd2869 Make StringEventArgs internally consistent 2024-05-22 15:01:52 -04:00
Matt Nadareski
dbe521b719 Better handle interface constants 2024-05-22 14:59:57 -04:00
Matt Nadareski
9486cdeedb Reduce accessors for DumpEnvironment 2024-05-22 14:51:36 -04:00
Matt Nadareski
2b9b186be0 Rename Result to ResultEventArgs for consistency 2024-05-22 14:49:45 -04:00
Matt Nadareski
73a78c786f Make implicit Result bidirectional 2024-05-22 14:35:28 -04:00
Matt Nadareski
786f2177bd Make implicit StringEventArgs bidirectional 2024-05-22 14:33:45 -04:00
Matt Nadareski
ddaf5e35f3 Make StringEventArgs more complete 2024-05-22 14:29:37 -04:00
Matt Nadareski
b39542b651 Use StringEventArgs more broadly 2024-05-22 14:24:16 -04:00
Matt Nadareski
4479733421 Separate out StringEventArgs 2024-05-22 14:14:18 -04:00
Matt Nadareski
6907e5b6ac Clean up usings 2024-05-22 14:08:41 -04:00
Matt Nadareski
81f672ca42 Move EnumConverter to Core.Data 2024-05-22 14:05:57 -04:00
Matt Nadareski
611c33f302 Reduce processing queue sleep time 2024-05-21 21:30:01 -04:00
Matt Nadareski
9cffc80982 Fix net20, net35, and net40 2024-05-21 21:11:04 -04:00
Matt Nadareski
3ba4db8f0a Remove unused byte array constant 2024-05-21 21:00:04 -04:00
Matt Nadareski
26daa46486 Move string contents for UI to view model 2024-05-21 20:57:57 -04:00
Matt Nadareski
51b14874c7 Remove Chime 2024-05-21 20:54:36 -04:00
Matt Nadareski
a6014e1b58 Clean up usings after moving methods 2024-05-21 20:50:44 -04:00
Matt Nadareski
e4237fedef Remove another redundant GetFullFile 2024-05-21 20:49:26 -04:00
Matt Nadareski
8d334b7228 Move GetBase64 to InfoTool 2024-05-21 20:48:40 -04:00
Matt Nadareski
bb95112559 Remove duplicate GetFullFile method 2024-05-21 20:46:48 -04:00
Matt Nadareski
6e798aa565 Separate out copy protection run 2024-05-21 20:43:06 -04:00
Matt Nadareski
94f8d9709a Move PlayStation drive use mostly to helper 2024-05-21 20:34:37 -04:00
Matt Nadareski
37a2e5c957 Handle version like category 2024-05-21 19:54:33 -04:00
Matt Nadareski
e163b174ac Make GetLogFilePaths required 2024-05-21 19:53:40 -04:00
Matt Nadareski
db92acfdcc Reduce surface area of generation method 2024-05-21 17:09:24 -04:00
Matt Nadareski
26e65b428b Separate out artifact generation 2024-05-21 17:05:07 -04:00
Matt Nadareski
03c55216ca Move constants into related classes 2024-05-21 16:46:22 -04:00
Matt Nadareski
70ae5dd787 Slight tweak to Result class variables 2024-05-21 16:43:11 -04:00
Matt Nadareski
e2a5cf968d Remove odd code from Result class 2024-05-21 16:42:36 -04:00
Matt Nadareski
60f43de605 Split constants files into component parts 2024-05-21 16:38:53 -04:00
Matt Nadareski
4205a0baef Make options internal to dump environment 2024-05-21 16:32:58 -04:00
Matt Nadareski
a52ac9f7b5 Invert using statement in dump environment 2024-05-21 16:26:32 -04:00
Matt Nadareski
346dab0899 Remove dcdumper until further notice 2024-05-21 16:25:04 -04:00
Matt Nadareski
c3bfd02310 Make some methods required for override 2024-05-21 16:16:39 -04:00
Matt Nadareski
d688fc6975 Slight tweak to deal with net20 2024-05-21 16:07:41 -04:00
Matt Nadareski
521b8d656b Remove unnecessary field in execution contexts 2024-05-21 16:05:37 -04:00
Matt Nadareski
9456301168 Split some processing code 2024-05-21 16:01:51 -04:00
Matt Nadareski
fad425da29 Use Logiqx model instead of internal one 2024-05-21 15:42:38 -04:00
Matt Nadareski
6b177c618d Remove redundant BinaryReaderExtensions class 2024-05-21 15:25:50 -04:00
Matt Nadareski
ca26307dbf Fix subfolder issue from previous 2024-05-21 15:09:19 -04:00
Matt Nadareski
8a7079a159 Simplify mv command in build config 2024-05-21 15:08:50 -04:00
Matt Nadareski
c4814fc950 Update Redumper to build 329 2024-05-21 14:40:01 -04:00
Matt Nadareski
7deaa9e7af Update launch JSON 2024-05-21 14:34:00 -04:00
Matt Nadareski
1ad4738b60 Update to DIC 20240401 2024-05-21 14:32:19 -04:00
Matt Nadareski
4a82baa5d1 Ensure check-only implementations still work 2024-05-21 13:41:53 -04:00
Matt Nadareski
1c1740010d Rename Parameters to ExecutionContext 2024-05-21 13:37:09 -04:00
Matt Nadareski
955fc4b8a0 Simplify access within processors 2024-05-21 13:14:15 -04:00
Matt Nadareski
fad9fa5f72 Remove now-unneeded parameters classes 2024-05-21 13:12:11 -04:00
Matt Nadareski
9dc976e423 Migrate processor functionality 2024-05-21 13:10:02 -04:00
Matt Nadareski
c2c92b54d9 Seal XBC processor 2024-05-21 12:48:26 -04:00
Matt Nadareski
77ccdb0032 Move DataFile to Core.Data 2024-05-21 12:47:26 -04:00
Matt Nadareski
4e3046fadd Create currently-unused processors 2024-05-21 12:46:08 -04:00
Matt Nadareski
70114ee59e Fix overwriting placeholders in Redumper 2024-05-21 12:11:19 -04:00
Matt Nadareski
4bb02b88fc Fix dictionary error in Redumper parsing 2024-05-21 11:03:44 -04:00
Matt Nadareski
f97e293ad2 Bump version 2024-05-19 19:48:51 -04:00
Deterous
2a040effde Prefer PlayStation info from Redumper logs (#702)
* Prefer PlayStation info from Redumper logs

* Restrict parsing PS data to info field

* Typo

* Readd version field
2024-05-19 19:45:25 -04:00
Matt Nadareski
862e676590 Update BinaryObjectScanner to 3.1.12 2024-05-18 22:30:27 -04:00
Deterous
bffa70bcc9 Add Xbox Backup Creator support to MPF.Check (#701)
* Initial XBC support

* Complete but untested XBC support

* Update changelog

* Fix SS recreation bug

* Parse XeMID from DMI

* Nitpicks
2024-05-16 23:11:33 -04:00
Matt Nadareski
bb596c49f4 Use IO implementation of IniFile 2024-05-16 12:35:39 -04:00
Matt Nadareski
917986530b Remove now-unused Hash enum 2024-05-16 12:29:48 -04:00
Matt Nadareski
14bc7609c5 Update BinaryObjectScanner to 3.1.11 2024-05-15 20:44:15 -04:00
Matt Nadareski
a2361c34bc Update RedumpLib and related 2024-05-15 17:17:23 -04:00
Matt Nadareski
3d29eeb3c3 Add site code listing to Check 2024-05-15 15:49:40 -04:00
Matt Nadareski
c908a55ce6 Get volume label from UIC outputs 2024-05-15 11:57:34 -04:00
Deterous
c2b3932363 Trim PIC for XboxOne/XboxSX (#700) 2024-05-14 10:34:11 -04:00
Deterous
b4d47aea37 Fix XboxOne/XboxSX Filename bug (#698) 2024-05-10 09:13:38 -04:00
Deterous
f8d3ae7bc7 Fix CleanRip not pulling info (#697) 2024-05-10 08:09:20 -04:00
Matt Nadareski
9f50277888 Update Redumper to build 325 2024-05-09 09:32:06 -04:00
Matt Nadareski
96f826994a Bump version 2024-05-09 08:56:53 -04:00
Matt Nadareski
eda3c97465 Note 2024-05-08 23:36:27 -04:00
Matt Nadareski
ff380451db Note 2024-05-08 23:35:35 -04:00
Matt Nadareski
a9ee6667d0 Add _PFI.bin support for UIC (fixes #696) 2024-05-07 19:17:48 -04:00
Matt Nadareski
54415241d2 Critical update to BinaryObjectScanner 3.1.10 2024-05-07 09:03:42 -04:00
Matt Nadareski
79d2957ede Omit false positives on formatting protections 2024-05-06 22:58:23 -04:00
Matt Nadareski
0b5d52da7d Note 2024-05-06 22:04:26 -04:00
Matt Nadareski
274ad9fc9a Note 2024-05-06 22:01:39 -04:00
Matt Nadareski
a2217b536b Note 2024-05-06 21:51:14 -04:00
Deterous
43e7883ac9 Option for default Redumper leadin retries (#693)
* Option for default Redumper leadin retries

* Gate custom default leadin retries behind option

* typo

* False by default

* change wording

* whitespace?

* better whitespace?
2024-05-02 23:41:07 -04:00
Matt Nadareski
c37d098eee Bump version 2024-04-28 20:17:48 -04:00
Matt Nadareski
17c2ca6fa8 Critical update to BinaryObjectScanner 3.1.9 2024-04-28 19:57:10 -04:00
Matt Nadareski
4b2d30bc01 Bump version 2024-04-27 19:37:49 -04:00
Matt Nadareski
ec8b65a7fa Update packages 2024-04-26 22:21:41 -04:00
Matt Nadareski
ec5611f5ff Update packages 2024-04-24 18:12:05 -04:00
Deterous
3e350b666b Custom non-redump Redumper options (#691)
* Gate advanced Redumper options in UI, add read method + sector order

* Update changelog

* Fixed-width text/combo boxes
2024-04-16 10:11:09 -04:00
Deterous
e83f69fc3e Define better default categories (#689) 2024-04-08 09:37:31 -04:00
Deterous
6ecbbb6978 Fix parameter parsing for = symbol (#687) 2024-04-05 21:27:57 -04:00
Matt Nadareski
771483ac14 Bump version 2024-04-05 16:03:28 -04:00
Matt Nadareski
ccde878286 Update BinaryObjectScanner to 3.1.5 2024-04-05 15:58:44 -04:00
Matt Nadareski
e0ab3e048b Enable remaining fields for label-side information 2024-04-05 15:35:54 -04:00
Matt Nadareski
cf2ae163c4 Enable label-side mastering SID and toolstamp 2024-04-05 15:30:37 -04:00
Deterous
5025a3e91a Fix CleanRip hash output for Check (#685)
* ClrMamePro format is for CDs, dont assume hashes are in CleanRip logs

* Rename folder

* Rename folder again

* Update changelog

* Don't trust cleanrip log hashes if any are missing
2024-04-05 08:54:07 -04:00
Matt Nadareski
dab774dab3 Fix test project project includes 2024-04-02 22:58:02 -04:00
Matt Nadareski
04c6131d28 Enable Windows targeting for test project 2024-04-02 22:28:10 -04:00
Deterous
47561baee8 Detect Xbox Series X discs (#683)
* Detect Xbox Series X discs via catalog.js deserialization

* Update changelog
2024-04-02 19:02:05 -07:00
Matt Nadareski
a8b1a8342d Update BinaryObjectScanner to 3.1.4 2024-04-02 17:10:49 -04:00
Matt Nadareski
7b8ef00d59 Merge with main 2024-04-02 16:39:42 -04:00
Matt Nadareski
65cc502a94 Update packages 2024-04-02 16:38:51 -04:00
fuzzball
d38b465b08 Fix information pulling for redumper (#682)
* Fix dat pull failure

* Fix c2 error exception

* Update changelist
2024-03-30 09:00:58 -07:00
Matt Nadareski
783c323fd0 Update BinaryObjectScanner to 3.1.3 2024-03-27 12:09:19 -04:00
Matt Nadareski
04af8807e5 Language selections unchecked by default (fixes #681) 2024-03-23 12:17:37 -04:00
Matt Nadareski
1260dfdff2 Fix missing information in README 2024-03-18 12:45:11 -04:00
Matt Nadareski
e5b883fb73 Fix outdated information in README 2024-03-18 12:44:24 -04:00
Matt Nadareski
1c08451487 Add Konami Python 2 system detection (fixes #680) 2024-03-18 12:30:02 -04:00
Matt Nadareski
29b483f805 Read last instance of hash data from Redumper 2024-03-18 12:20:11 -04:00
Matt Nadareski
2eff4a7488 Read C2 error count from Redumper logs (fixes #666) 2024-03-18 12:15:56 -04:00
Matt Nadareski
5e94d02503 Handle .0.physical files from Redumper (fixes #679) 2024-03-17 19:23:25 -04:00
Matt Nadareski
ccf2166b72 Bump version 2024-03-16 11:50:02 -04:00
Matt Nadareski
024394bbec Update BinaryObjectScanner to 3.1.2 2024-03-16 11:46:32 -04:00
Matt Nadareski
301a0cb188 Bump version 2024-03-15 13:43:36 -04:00
Matt Nadareski
64231da666 Update to RedumpLib 1.3.6 2024-03-15 13:00:34 -04:00
Deterous
5f56977021 Add MPF version to Submission info (#678) 2024-03-15 09:38:02 -07:00
Deterous
436ccf7a34 Fix Redumper generic drive type (#677) 2024-03-15 06:56:54 -07:00
Matt Nadareski
ef7510804e Update packages 2024-03-14 13:29:14 -04:00
Deterous
8c61b87954 Update LibIRD to 0.9.0 (#674) 2024-03-12 21:32:20 -07:00
Deterous
17ba117949 Update LibIRD to 0.8.0 (#673) 2024-03-12 07:12:22 -07:00
Matt Nadareski
0737ba7641 Fix formatting output formatting 2024-03-09 21:36:12 -05:00
Deterous
e9dba0767e Fix Check UI deadlock (#672)
* Fix Check UI deadlock

* Add region

* Niceties
2024-03-07 02:04:07 -08:00
Deterous
2d142e9e9d Fix config access permissions (#671) 2024-03-06 23:08:37 -08:00
Matt Nadareski
7a928decff Try updating PR check action 2024-03-06 22:46:08 -05:00
Deterous
eb5409bdee Enable LibIRD for all .NET frameworks (#670) 2024-03-06 19:11:54 -08:00
Matt Nadareski
1578193068 Update packages to latest 2024-03-06 11:04:50 -05:00
Matt Nadareski
131c95e6ef Update to SabreTools.RedumpLib 1.3.5 2024-03-05 12:56:06 -05:00
Matt Nadareski
a7790a271f Use SabreTools.Hashing 2024-03-04 21:23:45 -05:00
Matt Nadareski
1b342d56ef Ensure no labels are empty (fixes #669) 2024-03-01 12:57:51 -05:00
Deterous
a500211129 Fix title normalization (#668)
* Perform title normalization properly

* Use strings for old .net
2024-03-01 06:25:16 -08:00
Deterous
4d798fa547 Hide Size in DIW if value is 0 (#664)
* Hide Size field in DIW when size=0

* Update CHANGELIST.md
2024-02-28 22:26:07 -08:00
Matt Nadareski
597ebdc973 Update changelog 2024-02-28 22:00:31 -05:00
Deterous
c6a8a9265f Add PS3 CFW support to MPF.Check (#663)
* Add PS3 CFW support to MPF.Check

* Do everything better
2024-02-28 18:59:49 -08:00
Matt Nadareski
393c53769d Don't link to AppVeyor artifacts page anymore 2024-02-27 11:33:44 -05:00
Matt Nadareski
fa21999d3f Add PR check workflow 2024-02-27 11:20:53 -05:00
Matt Nadareski
dafbb05b16 Remove GHA pull request builds 2024-02-27 11:13:07 -05:00
Matt Nadareski
1c1b23a84b Make GHA debug-only 2024-02-27 10:41:50 -05:00
Matt Nadareski
fd0fe4912d Hide layerbreaks if value is 0 (fixes #662) 2024-02-27 10:04:50 -05:00
Matt Nadareski
b5b54d13a2 Gate debug publishing behind use all flag 2024-02-27 09:57:30 -05:00
Matt Nadareski
da77987db3 Bump version 2024-02-27 09:31:10 -05:00
Deterous
774f44c8ce Pull PS3 Disc Key from redump (#656)
* Pull PS3 Disc Key from redump

* Bump RedumpLib to 1.3.3
2024-02-26 17:35:04 -08:00
Matt Nadareski
251b3754e4 Add Mattel HyperScan detection (fixes #661) 2024-02-26 13:17:46 -05:00
Matt Nadareski
963acc3336 Update to BinaryObjectScanner 3.1.0 2024-02-26 12:24:40 -05:00
Matt Nadareski
90588a0f8b Show hashes in readonly data (fixes #660) 2024-02-23 22:10:21 -05:00
Matt Nadareski
a56c212488 Change link to WIP builds in README 2024-02-23 21:18:46 -05:00
Matt Nadareski
6484ab5fe0 Remove generation, just in case 2024-02-23 21:04:17 -05:00
Matt Nadareski
1ff48258b8 Generate release notes automatically 2024-02-23 21:00:16 -05:00
Matt Nadareski
81019f9d56 Unified tag for rolling release 2024-02-23 20:57:46 -05:00
Matt Nadareski
d47c435236 Remove unnecessary empty section 2024-02-23 13:47:35 -05:00
Matt Nadareski
d59b114cba Don't omit body when setting body 2024-02-23 13:37:55 -05:00
Matt Nadareski
7f26dcba4e Use commit SHA as body of rolling releases 2024-02-23 13:35:20 -05:00
Matt Nadareski
5e2766f982 Change link to WIP builds in README 2024-02-23 13:32:26 -05:00
Matt Nadareski
c883f899bb Build artifact before upload 2024-02-23 13:28:45 -05:00
Matt Nadareski
8c9950d5fa Use newer download version 2024-02-23 13:11:33 -05:00
Matt Nadareski
3e842af273 Download all artifacts? 2024-02-23 13:06:19 -05:00
Matt Nadareski
b837623da2 Try using download-artifact 2024-02-23 13:01:03 -05:00
Matt Nadareski
6742901243 Revert artifact ID, use name? 2024-02-23 12:53:21 -05:00
Matt Nadareski
d6460a2b68 Use recommendation from upload-artifact 2024-02-23 12:46:23 -05:00
Matt Nadareski
7af59dacc6 Try fixing the artifact upload 2024-02-23 12:41:24 -05:00
Matt Nadareski
fc3ef36fef Attempt to add CD to existing actions 2024-02-23 12:36:55 -05:00
Matt Nadareski
6298487346 Fix link in README 2024-02-23 11:26:45 -05:00
Matt Nadareski
727d9844d5 Fix whitespace that got unwhitespaced 2024-02-23 11:18:36 -05:00
Matt Nadareski
72e7619e2d Remove net35 from MPF... again 2024-02-23 11:17:44 -05:00
Matt Nadareski
24b4647037 Remove now-unnecessary restore step 2024-02-23 11:16:44 -05:00
Matt Nadareski
713b3f0557 Fix net35 build issue 2024-02-23 11:11:48 -05:00
Matt Nadareski
f796a9b131 More tweaks to CI 2024-02-23 10:59:40 -05:00
Matt Nadareski
2cdf92bf92 Rename badges for GHA 2024-02-23 10:26:27 -05:00
Matt Nadareski
ccc1687f1a Add GHA CI status badges 2024-02-23 10:23:18 -05:00
Matt Nadareski
6057ec3a59 Split CI workflow files 2024-02-23 10:20:30 -05:00
Matt Nadareski
2a5e736285 Reorganize solution items 2024-02-23 10:11:39 -05:00
Deterous
010ef9016b Add CI via GitHub Workflows (#657)
* Create ci.yml

* Update ci.yml

* Rename to master

* Update CHANGELIST.md
2024-02-23 07:08:59 -08:00
Deterous
02606318b0 Opt-in automatic IRD creation after PS3 dump (#655)
* Opt-in automatic IRD creation after PS3 dump

* Add tabs before an endregion

* Prevent double checking for existing files

* Spin off IRD creation into new thread
2024-02-22 19:55:10 -08:00
Matt Nadareski
d4f641b122 Update README with current build instructions 2024-02-21 19:28:11 -05:00
Matt Nadareski
a1dd6e2d21 Fix misattributed artifact 2024-02-21 11:14:56 -05:00
Matt Nadareski
d35679d688 Make AppVeyor builds framework-dependent 2024-02-21 11:00:18 -05:00
Matt Nadareski
83f5083ce7 Add x86 builds to AppVeyor 2024-02-21 10:59:30 -05:00
Matt Nadareski
5b6457f4b7 Remove DIC and Aaru bundles from CI 2024-02-21 10:51:05 -05:00
Deterous
c6517d526b Hide unavailable dumping programs (#654) 2024-02-21 07:14:39 -08:00
Matt Nadareski
e35f1fc2ec Readd x86 builds by default 2024-02-21 00:52:40 -05:00
Matt Nadareski
14f4128d4a Fix double git hash version (feat. Deterous) 2024-02-21 00:03:39 -05:00
Matt Nadareski
5465252dc7 Port build script fixes from BOS 2024-02-20 23:16:22 -05:00
Matt Nadareski
2573b47a79 Remove debugging lines from build script 2024-02-20 20:52:49 -05:00
Matt Nadareski
fe20905524 Bump version 2024-02-20 10:34:48 -05:00
Deterous
88f19180a4 Update LibIRD, disable UI elements when creating IRD (#653)
* Update LibIRD, disable UI when creating IRD

* Update changelog
2024-02-20 07:25:03 -08:00
Deterous
de89968a1d Add a GUI for PS3 IRD Creation (#647)
* Create a non-functional Create IRD window

* Add PIC and getkey.log options for IRDs

* Disable IRD creation window for unsupport .NET versions

* Finalise UI and parse inputs

* Add LibIRD package

* Manually define PIC in IRD creation

* Better output file browser

* Bump LibIRD version

* Update changelog

* Custom Disc ID, bump LibIRD version

* Ignore custom Disc ID for BD-50

* Provide a status message when creating IRD

* Better logpath enabled logic

* Nicer PIC UX

* Scrollbar only appears for unusually tall PIC
2024-02-18 17:38:28 -08:00
Matt Nadareski
8fc53c91b0 Limit DVD protection outputs (fixes #651) 2024-02-17 23:23:00 -05:00
Matt Nadareski
1a1fbd4b40 Fix Aaru drive parameter generation (fixes #652) 2024-02-17 23:09:29 -05:00
Matt Nadareski
cac6c3049b Add funworld Photo Play detection (fixes #650) 2024-02-15 12:56:30 -05:00
Matt Nadareski
6a6871e922 Write outputs with UTF-8 2024-02-15 12:00:40 -05:00
Deterous
4a02a3efac Fix DIC log parsing for SS version (#649) 2024-02-12 08:30:50 -08:00
Matt Nadareski
f6eb961af4 Make Redumper the default for new users (fixes #638) 2024-02-06 12:57:26 -05:00
Matt Nadareski
faeaaef02a Remove .NET 6 from auto-builds (fixes #646) 2024-02-06 12:50:01 -05:00
Matt Nadareski
ebf393e634 Bump version and copyright 2024-02-06 11:20:57 -05:00
Deterous
3fbd4ea719 Fix compiler warning (#645)
* Fix compiler warning about PresentationFramework.Aero2

* Update changelog
2024-02-06 07:53:45 -08:00
Matt Nadareski
d09ff6cf1c Enable Windows builds on Linux and Mac 2024-02-05 00:41:11 -05:00
Matt Nadareski
1dc0d57d47 Remove -disc2 from Cleanrip serial (fixes #644) 2024-02-03 19:39:30 -05:00
Matt Nadareski
a748bd4d3a Fix build from rushed code 2024-02-01 11:11:13 -05:00
Matt Nadareski
35dec7fe57 Retrieve serial from Cleanrip (fixes #643) 2024-02-01 11:05:42 -05:00
Deterous
c22d16349a Verbose Redumper log by default (#642) 2024-01-30 19:12:30 -08:00
Deterous
0d77a8950c Exclude extra tracks when finding disc matches (#641) 2024-01-30 19:08:41 -08:00
Deterous
285e94ca69 Parse PSX/PS2/KP2 exe date from logs (#639)
* Parse EXE date from Redumper

* Parse EXE date from DIC logs

* Fix DIC exe date parsing

* Split PS EXE name from EXE info

* Remove redundant path splitting
2024-01-30 19:00:08 -08:00
Matt Nadareski
747ac4ea3b Detect Photo CD 2024-01-25 20:53:21 -05:00
Matt Nadareski
405ae7c7e4 Add UMD handling for the disc info window 2024-01-24 22:56:50 -05:00
Matt Nadareski
f5ebe968c0 Fix information pulling for CleanRip and UIC (fixes #637) 2024-01-24 22:50:16 -05:00
Deterous
06a61b17cb Add a GUI for MPF.Check (#635)
* Draft MPF.Check GUI window

* Functional MPF.Check GUI

* Update changelog

* Show DiscInformationWindow after Check Dump

* Change layout

* Refactor
2024-01-24 11:57:21 -08:00
Matt Nadareski
9e8e4f6e36 Skip warning line in Redumper log 2024-01-24 10:17:58 -05:00
Deterous
fa72211b57 Normalize Disc Title in Submission Info (#634)
* NormalizeDiscTitle for SubmissionInfo

* Update changelog
2024-01-19 09:53:52 -08:00
Deterous
d5f66000a9 Differentiate CD32 from CDTV (#633) 2024-01-18 20:28:23 -08:00
Deterous
a52ba0aa7a Detect CDTV discs (#632) 2024-01-18 20:00:45 -08:00
Deterous
eb045928f9 Prevent crashing on invalid parameters (#631)
* Prevent crashing on invalid parameters

* Parse hex strings properly

* Helper function for hex numbers

* remove region label
2024-01-18 19:16:09 -08:00
fuzzball
440302495b Correct missing space in PVD (#628)
* Remove trim

* Update changelist
2024-01-16 05:54:56 -08:00
Deterous
0732e9db78 Retrieve volume label from logs (#627)
* Retrieve volume label from DIC and redumper logs

* Fix logic

* Remove unnecessary using

* Update changelog

* Sanitise label somewhat

* Refactor
2024-01-15 19:14:34 -08:00
Deterous
a167652b2b Check for presence of complete dump from other programs (#625)
* Check for presence of complete dump from other programs

* Better changelog message

* Refactor
2024-01-10 19:24:17 -08:00
Deterous
cfa07c1918 Allow variables in output path (#624)
* Allow variables in output path and default output path

* Remove angle brackets when normalising path

* Add tooltip hover text for default output path

* Better tooltip formatting

* Use percent sign rather than angle brackets as variable delimiter

* Refactor
2024-01-10 16:42:34 -08:00
Deterous
53b31f91cf Use PSX/PS2 serial as filename when Volume Label not present (#623)
* Use PSX/PS2 serial as volume label if none found

* Refactor
2024-01-09 14:02:17 -08:00
Deterous
01cbd2cff5 Update Redumper to build 311 (#622)
* Update redumper to build 311

* Update changelog

* Deal with new redumper parameters properly
2024-01-08 17:45:08 -08:00
Deterous
65ad629ee0 Cleanup !protectionInfo.txt (#621)
* Remove drive letter from !protectionInfo.txt

* Sort files in !protectionInfo.txt

* Add option for removing drive letter

* Refactor niceties
2024-01-08 17:20:30 -08:00
fuzzball
06adbde715 Support ringcode and PIC for triple/quad-layer (#620)
* Support ringcodes for triple/quad-layer

* Increase PIC length of triple/quad-layer for dic

* Increase PIC length of triple/quad-layer for redumper

* Change the method of determining PIC length

* Update change logs

* Remove braces from if statements
2024-01-08 13:53:48 -08:00
Deterous
1e5000bd8a Support redumper skeleton and hash files (#616)
* Add .hash/.skeleton files to log zip, update redumper to build 306, update SabreTools.Serialization

* Improvements to .skeleton/.hash code

* Revert redumper update, remove redudant string creation

* Deal with nullable strings

* Update changelog

* Invert if for readability
2024-01-05 20:06:46 -08:00
Deterous
8cb0b37e80 Get BD PIC Identifier for redumper (#619)
* Get PIC Identifier for bluray redumper

* Update changelog
2024-01-02 17:50:48 -08:00
Matt Nadareski
32c12e1332 Make missing hash data clearer 2023-12-14 20:27:38 -05:00
Matt Nadareski
09b307aa24 Fix commented out code 2023-12-07 23:22:12 -05:00
Matt Nadareski
a5a8fbbf51 Update Redumper to build 294 2023-12-07 21:38:38 -05:00
Matt Nadareski
b366d236c8 Update RedumpLib 2023-12-05 11:18:58 -05:00
Matt Nadareski
a833e926f3 Bump version 2023-12-04 12:10:19 -05:00
Matt Nadareski
950be07bf0 Handle or suppress some messages 2023-12-01 23:58:01 -05:00
Matt Nadareski
4c5c1417e9 Remove .NET Framework 3.5 from build script 2023-12-01 23:31:59 -05:00
Matt Nadareski
6fdc3412e0 Fix build warning for NRE 2023-12-01 23:28:45 -05:00
Matt Nadareski
807b0c5f9e Fix using SHA-1 for track checks (fixes #613) 2023-12-01 20:46:38 -05:00
Matt Nadareski
9e0b64a1d1 Fix broken tests 2023-12-01 20:39:36 -05:00
Matt Nadareski
8cfbf2d9f1 Bump version 2023-12-01 12:49:43 -05:00
Matt Nadareski
0064737130 Handle most VS and dotnet differences 2023-11-30 23:34:44 -05:00
Matt Nadareski
292e3999c5 Reference .NET Framework 3.0 for 3.5 2023-11-30 20:51:04 -05:00
Matt Nadareski
5ed1e94d84 Import WinFX for .NET Framework 3.5 2023-11-30 18:00:45 -05:00
Matt Nadareski
5b094f57cb Update USE_ALL in Powershell script 2023-11-30 13:43:20 -05:00
Matt Nadareski
8066b5541e Update Redumper to build 271 2023-11-30 13:39:32 -05:00
Matt Nadareski
921d0207c2 Fix cross-framework UI styles 2023-11-30 13:12:56 -05:00
Matt Nadareski
4374ff7f74 Fix most .NET Framework 3.5 issues 2023-11-30 12:58:06 -05:00
Matt Nadareski
0be5825b5e Fix cross-framework UI rendering 2023-11-30 11:54:40 -05:00
Matt Nadareski
14c630bea7 Fix Powershell build script 2023-11-30 03:19:39 -05:00
Matt Nadareski
9a66c685fd Replace build script with Powershell
Thanks to Deterous for the original script conversion.
2023-11-30 00:48:20 -05:00
Matt Nadareski
5e0fa1ad47 Add Disc ID and Key fields in info window (fixes #609) 2023-11-30 00:08:39 -05:00
Matt Nadareski
79065dcc69 Read CSS for some copy protections (fixes #608) 2023-11-29 23:57:58 -05:00
Matt Nadareski
3d7355aee1 Bump version 2023-11-29 23:36:57 -05:00
Matt Nadareski
6e9a6724c3 Update Redumper to build 268 2023-11-29 17:30:46 -05:00
Matt Nadareski
be35acfb48 Support .NET Framework 3.5 in UI 2023-11-23 03:37:00 -05:00
Matt Nadareski
f1a46c2e82 Get UI building with Framework 4.0 again 2023-11-23 03:05:52 -05:00
Matt Nadareski
872959c889 Temporarily remove .NET Framework 4.0 from UI 2023-11-23 02:32:57 -05:00
Matt Nadareski
b848a401f8 Get UI building with Framework 4.0 2023-11-23 01:19:17 -05:00
Matt Nadareski
ee4762f8b3 Support .NET Framework 3.5 in UI.Core 2023-11-22 23:50:37 -05:00
Matt Nadareski
d68bcfb96a Support .NET Framework 2.0
This does not include the UI, as per the same reasons why .NET Framework 4.0 doesn't support it.
2023-11-22 23:38:59 -05:00
Matt Nadareski
d2433e4749 Update changelog 2023-11-22 23:28:57 -05:00
Matt Nadareski
56ec0e7057 Update compatibility libraries 2023-11-22 23:28:24 -05:00
Matt Nadareski
26e5d33d17 Support .NET Framework 3.5
This does not include the UI, as per the same reasons why .NET Framework 4.0 doesn't support it.
2023-11-22 16:26:31 -05:00
Matt Nadareski
8b8b51ace4 Re-enable .NET Framework 4.0 building in Check 2023-11-22 16:02:08 -05:00
Matt Nadareski
f350904441 Re-enable .NET Framework 4.0 building in UI.Core 2023-11-22 16:00:18 -05:00
Matt Nadareski
8e8e3368d0 Re-enable .NET Framework 4.0 building in Core 2023-11-22 15:56:43 -05:00
Matt Nadareski
4d8153dba1 Update to BinaryObjectScanner 3.0.2 2023-11-22 13:46:39 -05:00
Matt Nadareski
e4e4b5ecde Temporarily remove .NET Framework 4.0 2023-11-21 11:13:58 -05:00
Matt Nadareski
8373a6b8f5 Support proper async in .NET Framework 4.0 2023-11-20 16:46:54 -05:00
Matt Nadareski
45c51ebc80 Use TryGetValue on dictionaries 2023-11-20 13:24:17 -05:00
Matt Nadareski
af27085cc1 Get Check building with Framework 4.0 2023-11-20 13:20:48 -05:00
Matt Nadareski
82e3707dce Get UI.Core building with Framework 4.0 2023-11-20 13:19:30 -05:00
Matt Nadareski
85192e8d3e Get Core building with Framework 4.0 2023-11-20 13:15:06 -05:00
Matt Nadareski
6f784a352e Update Xunit packages 2023-11-20 12:29:33 -05:00
Matt Nadareski
ee707cf1af Update to BinaryObjectScanner 3.0.1 2023-11-20 12:28:52 -05:00
Matt Nadareski
a14c998b3b More C# 12 cleanup in Core 2023-11-16 15:33:37 -05:00
Matt Nadareski
004208df6a Perform some post-move cleanup 2023-11-16 15:20:19 -05:00
Matt Nadareski
2f765146d1 Update RedumpLib and use moved methods 2023-11-16 12:45:47 -05:00
Matt Nadareski
a7d548f7ce Trim PS3 serial and add unrelated notes (fixes #607) 2023-11-16 12:18:07 -05:00
Matt Nadareski
fbdb9875f3 Add C#12 syntax to tests 2023-11-15 16:39:52 -05:00
Matt Nadareski
39a524e3cc Fix reversed ringcode test 2023-11-15 16:32:23 -05:00
Matt Nadareski
9740ca3a7a Suppress deprecation warnings 2023-11-15 16:29:47 -05:00
Matt Nadareski
f8d81972bf Prepare XAML for ancient .NET support 2023-11-15 12:10:54 -05:00
Matt Nadareski
fe9302a553 Perform more ancient .NET support work 2023-11-15 11:58:53 -05:00
Matt Nadareski
c0ed7a7a0e Fix TLS for older .NET 2023-11-15 00:18:52 -05:00
Matt Nadareski
b0b48743ac Support ancient .NET in UI 2023-11-15 00:08:43 -05:00
Matt Nadareski
47e79dab31 Support ancient .NET in Check 2023-11-14 23:53:15 -05:00
Matt Nadareski
90edc42fdf Support C# 12 syntax 2023-11-14 23:40:41 -05:00
Matt Nadareski
45db365705 Support ancient .NET in UI Core 2023-11-14 23:14:33 -05:00
Matt Nadareski
952828dddd Support ancient .NET in Core
This does not include .NET Framework 4.0 due to some issues with libraries.
2023-11-14 23:09:55 -05:00
Matt Nadareski
4a1e953ffd Fix BE flag logic bug in DIC (fixes #606) 2023-11-14 21:27:09 -05:00
Matt Nadareski
25740c2936 Zip manufacturer files for Redumper (fixes #604) 2023-11-14 21:19:52 -05:00
Matt Nadareski
3696257940 Add Bandai Pippin detection (fixes #600) 2023-11-14 21:16:47 -05:00
Matt Nadareski
4d46b7db5c Bump version 2023-11-14 16:39:19 -05:00
Matt Nadareski
21f5f29ac0 Update to .NET 8 (fixes #593) 2023-11-14 16:37:41 -05:00
Matt Nadareski
436e198826 Bump library versions 2023-11-14 16:32:32 -05:00
Matt Nadareski
91eb8c96c3 Update changelog 2023-11-08 21:03:27 -05:00
Matt Nadareski
edf0bcb4fe Update documentation for BOS change 2023-11-08 21:03:09 -05:00
Matt Nadareski
1526714ab9 Remove Unshield reference 2023-11-07 14:32:18 -05:00
Matt Nadareski
767e0bb05b Remove .NET Framework 4.8 from issue report 2023-11-07 12:03:45 -05:00
Matt Nadareski
52e781329c Make releases less verbose 2023-11-07 11:13:12 -05:00
Matt Nadareski
0c1395d3ec Remove lingering script reference 2023-11-07 00:23:55 -05:00
Matt Nadareski
791d9cdb7b Consolidate build script information 2023-11-07 00:22:54 -05:00
Matt Nadareski
7d7dc4ee4e Even more README cleanup 2023-11-07 00:18:54 -05:00
Matt Nadareski
97fd04b13a Remove 4.8 note from build script 2023-11-06 23:38:27 -05:00
Matt Nadareski
899db4c8c0 Remove redundant information 2023-11-06 23:15:27 -05:00
Matt Nadareski
bba204cbfe Update README for Legacy 2023-11-06 23:13:08 -05:00
Matt Nadareski
145660e9f9 Address lingering modern .NET syntax 2023-11-06 23:06:11 -05:00
Matt Nadareski
24de14aea5 Remove .NET Framework 4.8 gated code 2023-11-06 22:07:40 -05:00
Matt Nadareski
d57161e4d1 Remove .NET Framework 4.8 from projects 2023-11-06 21:00:07 -05:00
Matt Nadareski
a066a5234a Remove .NET Framework 4.8 from build 2023-11-06 20:57:03 -05:00
Matt Nadareski
229db5dda2 Bump version 2023-11-06 10:14:16 -05:00
Deterous
4f2a8d354a Update to MMI 3.0.0 (#603) 2023-11-06 07:10:25 -08:00
Matt Nadareski
b886471d72 Update changelog 2023-11-05 19:03:52 -05:00
Deterous
2bab266ae2 Enable browsing for Redumper path (#602) 2023-11-05 15:54:09 -08:00
Matt Nadareski
6c5fd9bac8 Fix default layerbreak output (fixes #601) 2023-11-05 11:39:56 -05:00
Matt Nadareski
08e93d7f13 Update changelog 2023-11-03 23:35:41 -04:00
Deterous
7a510e084b Pull PS3 Firmware Version (#599)
* Attempt to read PS3 firmware version

* Improve PS3 Firmware Version parsing

* Enable PS3 Firmware Version detection for all 3 Programs

* Big endian byte location

* Contents field not Comments field
2023-11-03 20:35:24 -07:00
Matt Nadareski
da46d20ffc Fix PS3 version finding 2023-11-03 22:41:22 -04:00
Matt Nadareski
234c0bfbab Try to get PS3 data from SFB 2023-11-03 15:34:05 -04:00
Matt Nadareski
82d60dbf4a Update changelog 2023-11-03 11:23:28 -04:00
Deterous
6dffb80609 Focus main window after child window closes (#596) 2023-11-03 08:23:11 -07:00
Matt Nadareski
267c0e3184 Update Redumper to build 247 2023-11-01 13:07:36 -04:00
Matt Nadareski
033ccbbe67 Update changelog 2023-10-31 19:59:38 -04:00
Deterous
c31b3f5894 Remove psxt001z Pkg Ref in MPF.Test (#592) 2023-10-31 16:58:43 -07:00
Matt Nadareski
9b1a303fea Bump version 2023-10-31 14:21:46 -04:00
Matt Nadareski
80a0f6da35 Attempt to fix window owner issue 2023-10-30 21:59:30 -04:00
Matt Nadareski
0c30eb7a60 Enable HD-DVD for Redumper in UI 2023-10-30 21:55:03 -04:00
Matt Nadareski
7a8125bb71 Update Redumper to build 246 2023-10-30 21:52:34 -04:00
Matt Nadareski
c4beffd845 Add PIC output for Redumper 2023-10-30 21:43:43 -04:00
Matt Nadareski
f97c112a53 Remove duplicate check 2023-10-30 18:44:08 -04:00
Matt Nadareski
5ef43ab6be Fix build 2023-10-30 18:40:17 -04:00
Matt Nadareski
2c399f99bf Update changelog 2023-10-30 18:38:03 -04:00
Deterous
42e9eb0b96 Fix typo in ProgramSupportsMeida (#591) 2023-10-30 15:36:51 -07:00
Matt Nadareski
e67d65f908 Remove .manufacturer for Bluray 2023-10-30 18:32:58 -04:00
Matt Nadareski
4ec8954b14 Handle a couple of messages 2023-10-30 16:42:15 -04:00
Matt Nadareski
1a6abb039c Compile most regex statements 2023-10-30 16:31:50 -04:00
Matt Nadareski
bb5d1e5ac8 Remove now-obsolete notes 2023-10-30 13:07:29 -04:00
Matt Nadareski
03c4c475eb Add Bluray layerbreak support for Redumper 2023-10-30 12:56:58 -04:00
Matt Nadareski
04d7817d28 Enable Bluray dumping with Redumper 2023-10-30 12:45:19 -04:00
Matt Nadareski
7cd100bc53 Update Redumper to build 244 2023-10-30 12:09:38 -04:00
Matt Nadareski
019924232a Remove and Sort Usings 2023-10-30 01:55:56 -04:00
Matt Nadareski
b5fc9f0275 Ignore empty protection results (fixes #590) 2023-10-30 01:05:15 -04:00
Matt Nadareski
44509b72ed Fix whitespace 2023-10-26 12:37:36 -04:00
Matt Nadareski
d532a63dbd Version-gate new switch statement 2023-10-26 12:36:44 -04:00
Matt Nadareski
227785b079 Remove unncessary summary 2023-10-26 12:33:28 -04:00
Matt Nadareski
0e364be998 Separate out static hashing 2023-10-26 12:16:42 -04:00
Matt Nadareski
7ae1f64ee3 Move all hashing to Hasher 2023-10-26 11:56:38 -04:00
Matt Nadareski
92463a103d Make Hasher more consistent 2023-10-26 11:54:13 -04:00
Matt Nadareski
101cdb7b34 Avoid unncessary allocation in hashing 2023-10-26 11:42:36 -04:00
Matt Nadareski
e924299f85 Add other non-cryptographic hashes 2023-10-26 11:37:41 -04:00
Matt Nadareski
b983f7eb4a Move Hash enum and simplify 2023-10-26 11:30:00 -04:00
Matt Nadareski
33b4be8b24 Bump version 2023-10-26 09:35:25 -04:00
Matt Nadareski
71a4edc8ba Update changelog 2023-10-26 09:18:13 -04:00
Deterous
ceb305eb54 Use relative path internally (#589) 2023-10-26 06:17:17 -07:00
Matt Nadareski
0b0d13dcf3 Use Array.Empty in hasher 2023-10-26 01:25:34 -04:00
Matt Nadareski
9f02368622 Fix two small nullability issues 2023-10-26 01:00:09 -04:00
Matt Nadareski
152010ee14 Update to MMI 3.0.0-preview.4 2023-10-26 00:58:44 -04:00
Matt Nadareski
c6d5f0aea5 Update to BurnOutSharp 2.9.0 2023-10-26 00:57:23 -04:00
Matt Nadareski
8c2ad64bb8 Update XUnit packages 2023-10-25 23:19:44 -04:00
Matt Nadareski
fa54d694b6 Fix CRC32 hashing (fixes #587) 2023-10-25 22:38:30 -04:00
Matt Nadareski
dc35b08624 Attempt to parse out PS5 params.json 2023-10-25 16:56:13 -04:00
Matt Nadareski
4429515ba2 Update package versions (fixes #586) 2023-10-25 16:22:32 -04:00
Matt Nadareski
fdbc7b34e5 Update changelog 2023-10-19 20:58:15 -04:00
Deterous
a1ab442cf0 Set UDF CD threshold at 800MB (#585)
* Set UDF CD threshold at 800MB

* Condense DriveFormat checks
2023-10-19 17:56:58 -07:00
Matt Nadareski
9ed5c297f6 Expose suffix setting (fixes #428) 2023-10-18 22:23:40 -04:00
Matt Nadareski
4ce9b214b0 Wire through filename suffix 2023-10-18 22:19:25 -04:00
Matt Nadareski
7dcdadda75 Add filename suffix setting (nw) 2023-10-18 22:04:15 -04:00
Matt Nadareski
f87a4d9fe2 Fix up DumpEnvironment a bit 2023-10-18 21:54:04 -04:00
Matt Nadareski
e4e5d173f0 Rearrange OptionsWindow to be easier to navigate 2023-10-18 16:35:34 -04:00
Matt Nadareski
115b242d59 Add optional file deletion (fixes #126) 2023-10-18 15:49:57 -04:00
Matt Nadareski
706bf8a431 Add deleteable file lists for Redumper and DIC 2023-10-18 15:41:51 -04:00
Matt Nadareski
87ecf1aa99 Add framework for deleteable files 2023-10-18 15:33:32 -04:00
Matt Nadareski
b5cf274333 Simply theme application 2023-10-18 10:31:58 -04:00
Matt Nadareski
4f4b6879b6 Fix drive letter check (fixes #584) 2023-10-18 10:22:05 -04:00
Matt Nadareski
3b19463913 Create method for applying theme 2023-10-18 10:21:40 -04:00
Matt Nadareski
37386cd182 Fix multiple handler invocation 2023-10-18 03:28:41 -04:00
Matt Nadareski
e04bdad16c Add first-run Options title, fix saving bug 2023-10-18 02:59:41 -04:00
Matt Nadareski
e37f12705d Fix drive letter issue in UI 2023-10-18 02:30:38 -04:00
Matt Nadareski
5c8dc2c23a Show options window on first run (fixes #467) 2023-10-18 02:10:29 -04:00
Matt Nadareski
e9121f3b03 Create skeleton for first-run 2023-10-18 01:59:55 -04:00
Matt Nadareski
d68175db4e Convert Drive to use paths internally 2023-10-18 01:47:42 -04:00
Matt Nadareski
9d8181b0e2 Add path variants for PlayStation info 2023-10-18 01:29:26 -04:00
Matt Nadareski
6d657f268a Split InfoTool into 2 classes 2023-10-18 01:17:12 -04:00
Matt Nadareski
3b3c5f823d Bump version 2023-10-17 20:53:07 -04:00
Matt Nadareski
09fc313492 Support Redumper 231 outputs 2023-10-17 20:51:48 -04:00
Matt Nadareski
316d0f6e54 Clean up issue templates 2023-10-16 00:44:57 -04:00
Matt Nadareski
a0033238bd Get SecuROM data from Redumper (fixes #583) 2023-10-16 00:38:56 -04:00
Matt Nadareski
5b1c6a7f46 Update changlog 2023-10-15 21:51:51 -04:00
fuzzball
8c0dff6552 Correct the condition (#582) 2023-10-15 18:51:23 -07:00
Matt Nadareski
43b230c84a Update Redumper to build 230 2023-10-15 21:42:45 -04:00
Matt Nadareski
f1b657011d Enable parameters checkbox by default (fixes #580) 2023-10-15 15:33:18 -04:00
Matt Nadareski
e4d8ac8e1c Fix Redumper retry count not showing 2023-10-14 23:04:05 -04:00
Matt Nadareski
08f44173dd Update changelog 2023-10-13 10:56:10 -04:00
Deterous
54765c71fd Remove code for getting UH from DIC logs (#577) 2023-10-13 07:55:52 -07:00
Matt Nadareski
01f8b49214 Update changelog 2023-10-13 10:54:57 -04:00
Deterous
e8b0b3efaa Improve check for which program supports which media (#578)
* Move ProgramSupportsMedia to MPF.Core.Utilities.Tools

* Implement ProgramSupportsMedia slightly less naively

* ProgramSupportsMedia only considers MPF-supported types
2023-10-13 07:54:10 -07:00
Matt Nadareski
f637938858 Update changelog 2023-10-12 15:47:13 -04:00
Deterous
ae326c1d2f Disable dumping button when Redumper selected with unsupported media type (#576)
* Disable dumping button when HDDVD + Redumper selected

* Exclude Bluray+Redumper as well

* Move program-supports-mediatype logic to helper function

* Fix for net48

* Fix for net48

* Undo fixes for net48
2023-10-12 12:46:44 -07:00
Matt Nadareski
a4a1e6bf0a Suppress some unnecessary messages 2023-10-12 01:27:54 -04:00
Matt Nadareski
ecee44966e Gate some switch expressions 2023-10-12 01:19:47 -04:00
Matt Nadareski
83437977ba Update changelog 2023-10-11 23:56:00 -04:00
Matt Nadareski
8fcac1d425 Cleanup and gated code 2023-10-11 23:55:50 -04:00
Matt Nadareski
705b5f1049 Fix options loading for Check 2023-10-11 16:37:10 -04:00
359 changed files with 53791 additions and 29996 deletions

167
.editorconfig Normal file
View File

@@ -0,0 +1,167 @@
# top-most EditorConfig file
root = true
# C# files
[*.cs]
# Indentation and spacing
charset = utf-8
indent_size = 4
indent_style = space
tab_width = 4
trim_trailing_whitespace = true
# New line preferences
end_of_line = lf
insert_final_newline = true
max_line_length = unset
# using directive preferences
csharp_using_directive_placement = outside_namespace
dotnet_diagnostic.IDE0005.severity = error
# Code-block preferences
csharp_style_namespace_declarations = block_scoped
csharp_style_prefer_method_group_conversion = true
csharp_style_prefer_top_level_statements = false
# Expression-level preferences
csharp_prefer_simple_default_expression = true
csharp_style_inlined_variable_declaration = true
csharp_style_unused_value_assignment_preference = discard_variable
csharp_style_unused_value_expression_statement_preference = discard_variable
dotnet_diagnostic.IDE0001.severity = warning
dotnet_diagnostic.IDE0002.severity = warning
dotnet_diagnostic.IDE0004.severity = warning
dotnet_diagnostic.IDE0010.severity = error
dotnet_diagnostic.IDE0051.severity = warning
dotnet_diagnostic.IDE0052.severity = warning
dotnet_diagnostic.IDE0072.severity = warning
dotnet_diagnostic.IDE0080.severity = warning
dotnet_diagnostic.IDE0100.severity = error
dotnet_diagnostic.IDE0110.severity = error
dotnet_diagnostic.IDE0120.severity = warning
dotnet_diagnostic.IDE0121.severity = warning
dotnet_diagnostic.IDE0240.severity = error
dotnet_diagnostic.IDE0241.severity = error
dotnet_style_coalesce_expression = true
dotnet_style_namespace_match_folder = false
dotnet_style_null_propagation = true
dotnet_style_prefer_auto_properties = true
dotnet_style_prefer_collection_expression = when_types_loosely_match
dotnet_style_prefer_is_null_check_over_reference_equality_method = true
dotnet_style_prefer_compound_assignment = true
csharp_style_prefer_simple_property_accessors = true
dotnet_style_prefer_simplified_interpolation = true
dotnet_style_prefer_simplified_boolean_expressions = true
csharp_style_prefer_unbound_generic_type_in_nameof = true
# Field preferences
dotnet_diagnostic.IDE0044.severity = warning
dotnet_style_readonly_field = true
# Language keyword vs. framework types preferences
dotnet_diagnostic.IDE0049.severity = error
dotnet_style_predefined_type_for_locals_parameters_members = true
dotnet_style_predefined_type_for_member_access = true
# Modifier preferences
csharp_prefer_static_local_function = true
csharp_style_prefer_readonly_struct = true
dotnet_diagnostic.IDE0036.severity = warning
dotnet_diagnostic.IDE0040.severity = error
dotnet_diagnostic.IDE0380.severity = error
dotnet_style_require_accessibility_modifiers = always
# New-line preferences
dotnet_diagnostic.IDE2000.severity = warning
dotnet_diagnostic.IDE2002.severity = warning
dotnet_diagnostic.IDE2003.severity = warning
dotnet_diagnostic.IDE2004.severity = warning
dotnet_diagnostic.IDE2005.severity = warning
dotnet_diagnostic.IDE2006.severity = warning
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = false
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = false
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false
dotnet_style_allow_multiple_blank_lines_experimental = false
dotnet_style_allow_statement_immediately_after_block_experimental = false
# Null-checking preferences
csharp_style_conditional_delegate_call = true
# Parameter preferences
dotnet_code_quality_unused_parameters = all
dotnet_diagnostic.IDE0280.severity = error
# Parentheses preferences
dotnet_diagnostic.IDE0047.severity = warning
dotnet_diagnostic.IDE0048.severity = warning
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
dotnet_style_parentheses_in_other_operators = always_for_clarity
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity
# Pattern-matching preferences
dotnet_diagnostic.IDE0019.severity = warning
dotnet_diagnostic.IDE0020.severity = warning
dotnet_diagnostic.IDE0038.severity = warning
dotnet_diagnostic.IDE0066.severity = none
dotnet_diagnostic.IDE0083.severity = warning
dotnet_diagnostic.IDE0260.severity = warning
csharp_style_pattern_matching_over_as_with_null_check = true
csharp_style_pattern_matching_over_is_with_cast_check = true
csharp_style_prefer_not_pattern = true
csharp_style_prefer_pattern_matching = true
# this. and Me. preferences
dotnet_style_qualification_for_event = false
dotnet_style_qualification_for_field = false
dotnet_style_qualification_for_method = false
dotnet_style_qualification_for_property = false
# var preferences
csharp_style_var_for_built_in_types = false
csharp_style_var_when_type_is_apparent = true
# .NET formatting options
dotnet_separate_import_directive_groups = false
dotnet_sort_system_directives_first = true
# C# formatting options
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = false
csharp_indent_labels = one_less_than_current
csharp_indent_switch_labels = true
csharp_new_line_before_catch = true
csharp_new_line_before_else = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_open_brace = all
csharp_new_line_between_query_expression_clauses = true
csharp_preserve_single_line_blocks = true
csharp_preserve_single_line_statements = true
csharp_space_after_cast = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_comma = true
csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_semicolon_in_for_statement = true
csharp_space_around_binary_operators = before_and_after
csharp_space_around_declaration_statements = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
csharp_space_before_open_square_brackets = false
csharp_space_before_semicolon_in_for_statement = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false

View File

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

View File

@@ -8,9 +8,9 @@ assignees: mnadareski
---
**Before You Submit**
- Remember to try the [latest WIP build](https://ci.appveyor.com/project/mnadareski/mpf/build/artifacts) to see if the feature already exists.
- Is it copy protection related? If so, report the issue [here](https://github.com/mnadareski/BurnOutSharp/issues) instead.
- .NET 6.0 has known limitations, so make sure that what you're giving information on isn't already in another build.
- Remember to try the [latest WIP build](https://github.com/SabreTools/MPF/releases/tag/rolling) to see if the feature already exists.
- Is it copy protection related? If so, report the issue [here](https://github.com/SabreTools/BinaryObjectScanner/issues) instead.
- Check [previous issues](https://github.com/SabreTools/MPF/issues) to see if any of those are related to what you're about to ask for.
If none of those apply, then continue...
@@ -19,4 +19,4 @@ If none of those apply, then continue...
A clear and concise description of what the information is. Ex. With the latest build of DumpingProgram, it [...]
**Additional context**
Add any other context or screenshots about the information here.
Add any other context or screenshots about the information here.

View File

@@ -8,16 +8,16 @@ assignees: mnadareski
---
**Before You Submit**
- Remember to try the [latest WIP build](https://ci.appveyor.com/project/mnadareski/mpf/build/artifacts) to see if the issue has already been addressed.
- Is it copy protection related? If so, report the issue [here](https://github.com/mnadareski/BurnOutSharp/issues) instead.
- .NET 6.0 has known issues, please try using another build to reproduce the error
- Remember to try the [latest WIP build](https://github.com/SabreTools/MPF/releases/tag/rolling) to see if the issue has already been addressed.
- Is it copy protection related? If so, report the issue [here](https://github.com/SabreTools/BinaryObjectScanner/issues) instead.
- Check multiple discs to help narrow down the issue
- Check the Options to see if changing any of those affects your issue.
If all of those fail, then continue...
**Version**
What version are you using?
What version are you using?
- [ ] Stable release (version here)
- [ ] WIP release (version here)
@@ -25,14 +25,14 @@ What version are you using?
**Build**
What runtime version are you using?
- [ ] .NET Framework 4.8 running on (Operating System)
- [ ] .NET 6.0 running on (Operating System)
- [ ] .NET 10 running on (Operating System)
**Describe the issue**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'

59
.github/workflows/build_and_test.yml vendored Normal file
View File

@@ -0,0 +1,59 @@
name: Build and Test
on:
push:
branches: ["master"]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@v1.3.1
with:
dotnet: false
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: |
8.0.x
9.0.x
10.0.x
- name: Run tests
run: dotnet test
- name: Run publish script
run: ./publish-nix.sh -dp
- name: Update rolling tag
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -f rolling
git push origin :refs/tags/rolling || true
git push origin rolling --force
- name: Upload to rolling
uses: ncipollo/release-action@v1.20.0
with:
allowUpdates: True
artifacts: "*.nupkg,*.snupkg,*.zip"
body: "Last built commit: ${{ github.sha }}
## UI Builds
[Windows x64 UI Release](https://github.com/SabreTools/MPF/releases/download/rolling/MPF.UI_net10.0-windows_win-x64_release.zip)
[Windows x64 UI Debug](https://github.com/SabreTools/MPF/releases/download/rolling/MPF.UI_net10.0-windows_win-x64_debug.zip)"
name: "Rolling Release"
prerelease: True
replacesArtifacts: True
tag: "rolling"
updateOnlyUnreleased: True

31
.github/workflows/check_pr.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: Build PR
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@v1.3.1
with:
dotnet: false
- uses: actions/checkout@v5
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: |
8.0.x
9.0.x
10.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build
- name: Test
run: dotnet test

1
.gitignore vendored
View File

@@ -68,7 +68,6 @@ artifacts/
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds

0
.gitmodules vendored
View File

35
.vscode/launch.json vendored
View File

@@ -5,17 +5,46 @@
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (console)",
"name": ".NET Core Launch (Check)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/MPF.Check/bin/Debug/net6.0/MPF.Check.dll",
"program": "${workspaceFolder}/MPF.Check/bin/Debug/net10.0/MPF.Check.dll",
"args": [],
"cwd": "${workspaceFolder}/MPF.Check",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false
"stopAtEntry": false,
"justMyCode": false
},
{
"name": ".NET Core Launch (CLI)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/MPF.CLI/bin/Debug/net10.0/MPF.CLI.dll",
"args": [],
"cwd": "${workspaceFolder}/MPF.CLI",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false,
"justMyCode": false
},
{
"name": ".NET Core Launch (UI)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/MPF.UI/bin/Debug/net10.0-windows/MPF.dll",
"args": [],
"cwd": "${workspaceFolder}/MPF.UI",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false,
"justMyCode": false
},
{
"name": ".NET Core Attach",

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,315 @@
using System;
using System.IO;
#if NET40
using System.Threading.Tasks;
#endif
using MPF.Frontend;
using MPF.Frontend.Tools;
using SabreTools.RedumpLib.Data;
using SabreTools.RedumpLib.Web;
using LogCompression = MPF.Processors.LogCompression;
namespace MPF.CLI.Features
{
internal abstract class BaseFeature : SabreTools.CommandLine.Feature
{
#region Properties
/// <summary>
/// User-defined options
/// </summary>
public Options Options { get; protected set; }
/// <summary>
/// Currently-selected system
/// </summary>
public RedumpSystem? System { get; protected set; }
/// <summary>
/// Media type to dump
/// </summary>
/// <remarks>Required for DIC and if custom parameters not set</remarks>
public MediaType? MediaType { get; protected set; }
/// <summary>
/// Path to the device to dump
/// </summary>
/// <remarks>Required if custom parameters are not set</remarks>
public string? DevicePath { get; protected set; }
/// <summary>
/// Path to the mounted filesystem to check
/// </summary>
/// <remarks>Should only be used when the device path is not readable</remarks>
public string? MountedPath { get; protected set; }
/// <summary>
/// Path to the output file
/// </summary>
/// <remarks>Required if custom parameters are not set</remarks>
public string? FilePath { get; protected set; }
/// <summary>
/// Override drive speed
/// </summary>
public int? DriveSpeed { get; protected set; }
/// <summary>
/// Custom parameters for dumping
/// </summary>
public string? CustomParams { get; protected set; }
#endregion
protected BaseFeature(string name, string[] flags, string description, string? detailed = null)
: base(name, flags, description, detailed)
{
Options = new Options()
{
// Internal Program
InternalProgram = InternalProgram.NONE,
// Extra Dumping Options
ScanForProtection = false,
AddPlaceholders = true,
PullAllInformation = false,
AddFilenameSuffix = false,
OutputSubmissionJSON = false,
IncludeArtifacts = false,
CompressLogFiles = false,
LogCompression = LogCompression.DeflateMaximum,
DeleteUnnecessaryFiles = false,
CreateIRDAfterDumping = false,
// Protection Scanning Options
ScanArchivesForProtection = true,
IncludeDebugProtectionInformation = false,
HideDriveLetters = false,
// Redump Login Information
RetrieveMatchInformation = true,
RedumpUsername = null,
RedumpPassword = null,
};
}
/// <inheritdoc/>
public override bool Execute()
{
// Validate a system type is provided
if (System == null)
{
Console.Error.WriteLine("A system name needs to be provided");
return false;
}
// Log the system being used, in case it came from config
Console.WriteLine($"Using system: {System.LongName()}");
// Validate the supplied credentials
if (Options.RetrieveMatchInformation
&& !string.IsNullOrEmpty(Options.RedumpUsername)
&& !string.IsNullOrEmpty(Options.RedumpPassword))
{
bool? validated = RedumpClient.ValidateCredentials(Options.RedumpUsername!, Options.RedumpPassword!).GetAwaiter().GetResult();
string message = validated switch
{
true => "Redump username and password accepted!",
false => "Redump username and password denied!",
null => "An error occurred validating your credentials!",
};
Console.WriteLine(message);
}
// Validate the internal program
#pragma warning disable IDE0010
switch (Options.InternalProgram)
{
case InternalProgram.Aaru:
if (!File.Exists(Options.AaruPath))
{
Console.Error.WriteLine("A path needs to be supplied in config.json for Aaru, exiting...");
return false;
}
break;
case InternalProgram.DiscImageCreator:
if (!File.Exists(Options.DiscImageCreatorPath))
{
Console.Error.WriteLine("A path needs to be supplied in config.json for DIC, exiting...");
return false;
}
break;
// case InternalProgram.Dreamdump:
// if (!File.Exists(Options.DreamdumpPath))
// {
// Console.Error.WriteLine("A path needs to be supplied in config.json for Dreamdump, exiting...");
// return false;
// }
// break;
case InternalProgram.Redumper:
if (!File.Exists(Options.RedumperPath))
{
Console.Error.WriteLine("A path needs to be supplied in config.json for Redumper, exiting...");
return false;
}
break;
default:
Console.Error.WriteLine($"{Options.InternalProgram} is not a supported dumping program, exiting...");
break;
}
#pragma warning restore IDE0010
// Ensure we have the values we need
if (CustomParams is null && DevicePath is null)
{
Console.Error.WriteLine("Either custom parameters or a device path need to be provided, exiting...");
return false;
}
if (Options.InternalProgram == InternalProgram.DiscImageCreator
&& CustomParams is null
&& (MediaType is null || MediaType == SabreTools.RedumpLib.Data.MediaType.NONE))
{
Console.Error.WriteLine("Media type is required for DiscImageCreator, exiting...");
return false;
}
// If no media type is provided, use a default
if (CustomParams is null && (MediaType is null || MediaType == SabreTools.RedumpLib.Data.MediaType.NONE))
{
// Get reasonable default values based on the current system
var mediaTypes = System.MediaTypes();
MediaType = mediaTypes.Count > 0 ? mediaTypes[0] : SabreTools.RedumpLib.Data.MediaType.CDROM;
if (MediaType == SabreTools.RedumpLib.Data.MediaType.NONE)
MediaType = SabreTools.RedumpLib.Data.MediaType.CDROM;
Console.WriteLine($"No media type was provided, using {MediaType.LongName()}");
}
// Normalize the file path
if (DevicePath is not null && FilePath is null)
{
string defaultFileName = $"track_{DateTime.Now:yyyyMMdd-HHmm}";
FilePath = Path.Combine(defaultFileName, $"{defaultFileName}.bin");
if (Options.DefaultOutputPath is not null)
FilePath = Path.Combine(Options.DefaultOutputPath, FilePath);
}
if (FilePath is not null)
FilePath = FrontendTool.NormalizeOutputPaths(FilePath, getFullPath: true);
// Get the speed from the options
int speed = DriveSpeed ?? FrontendTool.GetDefaultSpeedForMediaType(MediaType, Options);
// Populate an environment
var drive = Drive.Create(null, DevicePath ?? string.Empty);
var env = new DumpEnvironment(Options,
FilePath,
drive,
System,
Options.InternalProgram);
env.SetExecutionContext(MediaType, null);
env.SetProcessor();
// Process the parameters
string? paramStr = CustomParams ?? env.GetFullParameters(MediaType, speed);
if (string.IsNullOrEmpty(paramStr))
{
Console.Error.WriteLine("No valid environment could be created, exiting...");
return false;
}
env.SetExecutionContext(MediaType, paramStr);
// Invoke the dumping program
Console.WriteLine($"Invoking {Options.InternalProgram} using '{paramStr}'");
var dumpResult = env.Run(MediaType).GetAwaiter().GetResult();
Console.WriteLine(dumpResult.Message);
if (dumpResult == false)
return false;
// If it was not a dumping command
if (!env.IsDumpingCommand())
{
Console.Error.WriteLine();
Console.WriteLine("Execution not recognized as dumping command, skipping processing...");
return true;
}
// If we have a mounted path, replace the environment
if (MountedPath is not null && Directory.Exists(MountedPath))
{
drive = Drive.Create(null, MountedPath);
env = new DumpEnvironment(Options,
FilePath,
drive,
System,
internalProgram: null);
env.SetExecutionContext(MediaType, null);
env.SetProcessor();
}
// Finally, attempt to do the output dance
var verifyResult = env.VerifyAndSaveDumpOutput()
.ConfigureAwait(false).GetAwaiter().GetResult();
Console.WriteLine(verifyResult.Message);
return true;
}
/// <summary>
/// Display help for MPF.CLI
/// </summary>
/// <param name="error">Error string to prefix the help text with</param>
public static void DisplayHelp()
{
Console.WriteLine("Usage:");
Console.WriteLine("MPF.CLI <system> [options]");
Console.WriteLine();
Console.WriteLine("Standalone Options:");
Console.WriteLine("?, h, help Show this help text");
Console.WriteLine("version Print the program version");
Console.WriteLine("lc, listcodes List supported comment/content site codes");
Console.WriteLine("lo, listconfig List current configuration values");
Console.WriteLine("lm, listmedia List supported media types");
Console.WriteLine("ls, listsystems List supported system types");
Console.WriteLine("lp, listprograms List supported dumping program outputs");
Console.WriteLine("i, interactive Enable interactive mode");
Console.WriteLine();
Console.WriteLine("CLI Options:");
Console.WriteLine("-u, --use <program> Override configured dumping program name");
Console.WriteLine("-t, --mediatype <mediatype> Set media type for dumping (Required for DIC)");
Console.WriteLine("-d, --device <devicepath> Physical drive path (Required if no custom parameters set)");
Console.WriteLine("-m, --mounted <dirpath> Mounted filesystem path for additional checks");
Console.WriteLine("-f, --file \"<filepath>\" Output file path (Recommended, uses defaults otherwise)");
Console.WriteLine("-s, --speed <speed> Override default dumping speed");
Console.WriteLine("-c, --custom \"<params>\" Custom parameters to use");
Console.WriteLine();
Console.WriteLine("Dumping program paths and other settings can be found in the config.json file");
Console.WriteLine("generated next to the program by default. Ensure that all settings are to user");
Console.WriteLine("preference before running MPF.CLI.");
Console.WriteLine();
Console.WriteLine("Custom dumping parameters, if used, will fully replace the default parameters.");
Console.WriteLine("All dumping parameters need to be supplied if doing this.");
Console.WriteLine("Otherwise, a drive path is required.");
Console.WriteLine();
Console.WriteLine("Mounted filesystem path is only recommended on OSes that require block");
Console.WriteLine("device dumping, usually Linux and macOS.");
Console.WriteLine();
}
}
}

View File

@@ -0,0 +1,196 @@
using System;
using System.IO;
using MPF.Frontend;
using MPF.Frontend.Tools;
using SabreTools.RedumpLib.Data;
namespace MPF.CLI.Features
{
internal sealed class InteractiveFeature : BaseFeature
{
#region Feature Definition
public const string DisplayName = "interactive";
private static readonly string[] _flags = ["i", "interactive"];
private const string _description = "Enable interactive mode";
#endregion
public InteractiveFeature()
: base(DisplayName, _flags, _description)
{
}
/// <inheritdoc/>
public override bool ProcessArgs(string[] args, int index)
{
// Cache all args as inputs
for (int i = 1; i < args.Length; i++)
{
Inputs.Add(args[i]);
}
// Read the options from config, if possible
Options = OptionsLoader.LoadFromConfig();
// Create return values
MediaType = SabreTools.RedumpLib.Data.MediaType.NONE;
string defaultFileName = $"track_{DateTime.Now:yyyyMMdd-HHmm}";
#if NET20 || NET35
FilePath = Path.Combine(Options.DefaultOutputPath ?? "ISO", Path.Combine(defaultFileName, $"{defaultFileName}.bin"));
#else
FilePath = Path.Combine(Options.DefaultOutputPath ?? "ISO", defaultFileName, $"{defaultFileName}.bin");
#endif
System = Options.DefaultSystem;
// Create state values
string? result;
root:
Console.Clear();
Console.WriteLine("MPF.CLI Interactive Mode - Main Menu");
Console.WriteLine("-------------------------");
Console.WriteLine();
Console.WriteLine($"1) Set system (Currently '{System}')");
Console.WriteLine($"2) Set dumping program (Currently '{Options.InternalProgram}')");
Console.WriteLine($"3) Set media type (Currently '{MediaType}')");
Console.WriteLine($"4) Set device path (Currently '{DevicePath}')");
Console.WriteLine($"5) Set mounted path (Currently '{MountedPath}')");
Console.WriteLine($"6) Set file path (Currently '{FilePath}')");
Console.WriteLine($"7) Set override speed (Currently '{DriveSpeed}')");
Console.WriteLine($"8) Set custom parameters (Currently '{CustomParams}')");
Console.WriteLine();
Console.WriteLine($"Q) Exit the program");
Console.WriteLine($"X) Start dumping");
Console.Write("> ");
result = Console.ReadLine();
switch (result)
{
case "1":
goto system;
case "2":
goto dumpingProgram;
case "3":
goto mediaType;
case "4":
goto devicePath;
case "5":
goto mountedPath;
case "6":
goto filePath;
case "7":
goto overrideSpeed;
case "8":
goto customParams;
case "q":
case "Q":
Environment.Exit(0);
break;
case "x":
case "X":
Console.Clear();
goto exit;
case "z":
case "Z":
Console.WriteLine("It is pitch black. You are likely to be eaten by a grue.");
Console.Write("> ");
Console.ReadLine();
goto root;
default:
Console.WriteLine($"Invalid selection: {result}");
Console.ReadLine();
goto root;
}
system:
Console.WriteLine();
Console.WriteLine("For possible inputs, use the List Systems commandline option");
Console.WriteLine();
Console.WriteLine("Input the system and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
System = result.ToRedumpSystem();
goto root;
dumpingProgram:
Console.WriteLine();
Console.WriteLine("Options:");
Console.WriteLine($"{InternalProgram.Redumper.ToString().ToLowerInvariant(),-15} => {InternalProgram.Redumper.LongName()}");
Console.WriteLine($"{InternalProgram.DiscImageCreator.ToString().ToLowerInvariant(),-15} => {InternalProgram.DiscImageCreator.LongName()}");
Console.WriteLine($"{InternalProgram.Aaru.ToString().ToLowerInvariant(),-15} => {InternalProgram.Aaru.LongName()}");
// Console.WriteLine($"{InternalProgram.Dreamdump.ToString().ToLowerInvariant(),-15} => {InternalProgram.Dreamdump.LongName()}");
Console.WriteLine();
Console.WriteLine("Input the dumping program and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
Options.InternalProgram = result.ToInternalProgram();
goto root;
mediaType:
Console.WriteLine();
Console.WriteLine("For possible inputs, use the List Media commandline option");
Console.WriteLine();
Console.WriteLine("Input the media type and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
MediaType = OptionsLoader.ToMediaType(result);
goto root;
devicePath:
Console.WriteLine();
Console.WriteLine("Input the device path and press Enter:");
Console.Write("> ");
DevicePath = Console.ReadLine();
goto root;
mountedPath:
Console.WriteLine();
Console.WriteLine("Input the mounted path and press Enter:");
Console.Write("> ");
MountedPath = Console.ReadLine();
goto root;
filePath:
Console.WriteLine();
Console.WriteLine("Input the file path and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
if (!string.IsNullOrEmpty(result))
result = Path.GetFullPath(result!);
FilePath = result;
goto root;
overrideSpeed:
Console.WriteLine();
Console.WriteLine("Input the override speed and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
if (!int.TryParse(result, out int speed))
speed = -1;
DriveSpeed = speed;
goto root;
customParams:
Console.WriteLine();
Console.WriteLine("Input the custom parameters and press Enter:");
Console.Write("> ");
CustomParams = Console.ReadLine();
goto root;
exit:
return true;
}
/// <inheritdoc/>
public override bool VerifyInputs() => true;
}
}

View File

@@ -0,0 +1,115 @@
using MPF.Frontend;
using MPF.Frontend.Tools;
using SabreTools.CommandLine.Inputs;
using SabreTools.RedumpLib.Data;
namespace MPF.CLI.Features
{
internal sealed class MainFeature : BaseFeature
{
#region Feature Definition
public const string DisplayName = "main";
/// <remarks>Flags are unused</remarks>
private static readonly string[] _flags = [];
/// <remarks>Description is unused</remarks>
private const string _description = "";
#endregion
#region Inputs
private const string _customName = "custom";
internal readonly StringInput CustomInput = new(_customName, ["-c", "--custom"], "Custom parameters to use");
private const string _deviceName = "device";
internal readonly StringInput DeviceInput = new(_deviceName, ["-d", "--device"], "Physical drive path (Required if no custom parameters set)");
private const string _fileName = "file";
internal readonly StringInput FileInput = new(_fileName, ["-f", "--file"], "Output file path (Required if no custom parameters set)");
private const string _mediaTypeName = "media-type";
internal readonly StringInput MediaTypeInput = new(_mediaTypeName, ["-t", "--mediatype"], "Set media type for dumping (Required for DIC)");
private const string _mountedName = "mounted";
internal readonly StringInput MountedInput = new(_mountedName, ["-m", "--mounted"], "Mounted filesystem path for additional checks");
private const string _speedName = "speed";
internal readonly Int32Input SpeedInput = new(_speedName, ["-s", "--speed"], "Override default dumping speed");
private const string _useName = "use";
internal readonly StringInput UseInput = new(_useName, ["-u", "--use"], "Override configured dumping program name");
#endregion
public MainFeature()
: base(DisplayName, _flags, _description)
{
Add(UseInput);
Add(MediaTypeInput);
Add(DeviceInput);
Add(MountedInput);
Add(FileInput);
Add(SpeedInput);
Add(CustomInput);
}
/// <inheritdoc/>
public override bool ProcessArgs(string[] args, int index)
{
// If we have no arguments, just return
if (args is null || args.Length == 0)
return true;
// Read the options from config, if possible
Options = OptionsLoader.LoadFromConfig();
// The first argument is the system type
System = args[0].Trim('"').ToRedumpSystem();
// Loop through the arguments and parse out values
for (index = 1; index < args.Length; index++)
{
// Use specific program
if (UseInput.ProcessInput(args, ref index))
Options.InternalProgram = UseInput.Value.ToInternalProgram();
// Set a media type
else if (MediaTypeInput.ProcessInput(args, ref index))
MediaType = OptionsLoader.ToMediaType(MediaTypeInput.Value?.Trim('"'));
// Use a device path
else if (DeviceInput.ProcessInput(args, ref index))
DevicePath = DeviceInput.Value;
// Use a mounted path for physical checks
else if (MountedInput.ProcessInput(args, ref index))
MountedPath = MountedInput.Value;
// Use a file path
else if (FileInput.ProcessInput(args, ref index))
FilePath = FileInput.Value;
// Set an override speed
else if (SpeedInput.ProcessInput(args, ref index))
DriveSpeed = SpeedInput.Value;
// Use a custom parameters
else if (CustomInput.ProcessInput(args, ref index))
CustomParams = CustomInput.Value;
// Default, add to inputs
else
Inputs.Add(args[index]);
}
return true;
}
/// <inheritdoc/>
public override bool VerifyInputs() => true;
}
}

50
MPF.CLI/MPF.CLI.csproj Normal file
View File

@@ -0,0 +1,50 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Assembly Properties -->
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
<OutputType>Exe</OutputType>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<LangVersion>latest</LangVersion>
<NoWarn>NU1902;NU1903</NoWarn>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<VersionPrefix>3.6.0</VersionPrefix>
<!-- Package Properties -->
<Title>MPF CLI</Title>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Description>CLI frontend for various dumping programs</Description>
<Copyright>Copyright (c) Matt Nadareski 2019-2025</Copyright>
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
<RepositoryType>git</RepositoryType>
</PropertyGroup>
<!-- Support All Frameworks -->
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net4`))">
<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith(`netcoreapp`)) OR $(TargetFramework.StartsWith(`net5`))">
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net6`)) OR $(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`)) OR $(TargetFramework.StartsWith(`net9`)) OR $(TargetFramework.StartsWith(`net10`))">
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(RuntimeIdentifier.StartsWith(`osx-arm`))">
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MPF.Frontend\MPF.Frontend.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.CommandLine" Version="[1.4.0]" />
<PackageReference Include="SabreTools.RedumpLib" Version="[1.9.1]" />
</ItemGroup>
</Project>

143
MPF.CLI/Program.cs Normal file
View File

@@ -0,0 +1,143 @@
using System;
using System.Collections.Generic;
#if NET40
using System.Threading.Tasks;
#endif
using MPF.CLI.Features;
using MPF.Frontend.Features;
using MPF.Frontend.Tools;
using SabreTools.CommandLine;
using SabreTools.CommandLine.Features;
namespace MPF.CLI
{
public class Program
{
public static void Main(string[] args)
{
// Load options from the config file
var options = OptionsLoader.LoadFromConfig();
if (options.FirstRun)
{
// Reset first run
options.FirstRun = false;
OptionsLoader.SaveToConfig(options);
// Display non-error message
Console.WriteLine("First-run detected! Please verify the generated config.json and run again.");
return;
}
// Create the command set
var mainFeature = new MainFeature();
var commandSet = CreateCommands(mainFeature);
// If we have no args, show the help and quit
if (args is null || args.Length == 0)
{
BaseFeature.DisplayHelp();
return;
}
// Get the first argument as a feature flag
string featureName = args[0];
// Try processing the standalone arguments
var topLevel = commandSet.GetTopLevel(featureName);
switch (topLevel)
{
// Standalone Options
case Help: BaseFeature.DisplayHelp(); return;
case VersionFeature version: version.Execute(); return;
case ListCodesFeature lc: lc.Execute(); return;
case ListConfigFeature lc: lc.Execute(); return;
case ListMediaTypesFeature lm: lm.Execute(); return;
case ListProgramsFeature lp: lp.Execute(); return;
case ListSystemsFeature ls: ls.Execute(); return;
// Interactive Mode
case InteractiveFeature interactive:
if (!interactive.ProcessArgs(args, 0))
{
BaseFeature.DisplayHelp();
return;
}
if (!interactive.Execute())
{
BaseFeature.DisplayHelp();
return;
}
break;
// Default Behavior
default:
if (!mainFeature.ProcessArgs(args, 0))
{
BaseFeature.DisplayHelp();
return;
}
if (!mainFeature.Execute())
{
BaseFeature.DisplayHelp();
return;
}
break;
}
}
/// <summary>
/// Create the command set for the program
/// </summary>
private static CommandSet CreateCommands(MainFeature mainFeature)
{
List<string> header = [
"MPF.CLI [standalone|system] [options] <path> ...",
string.Empty,
];
List<string> footer = [
string.Empty,
"Dumping program paths and other settings can be found in the config.json file",
"generated next to the program by default. Ensure that all settings are to user",
"preference before running MPF.CLI.",
string.Empty,
"Custom dumping parameters, if used, will fully replace the default parameters.",
"All dumping parameters need to be supplied if doing this.",
"Otherwise, both a drive path and output file path are required.",
string.Empty,
"Mounted filesystem path is only recommended on OSes that require block",
"device dumping, usually Linux and macOS.",
string.Empty,
];
var commandSet = new CommandSet(header, footer);
// Standalone Options
commandSet.Add(new Help());
commandSet.Add(new VersionFeature());
commandSet.Add(new ListCodesFeature());
commandSet.Add(new ListConfigFeature());
commandSet.Add(new ListMediaTypesFeature());
commandSet.Add(new ListSystemsFeature());
commandSet.Add(new ListProgramsFeature());
commandSet.Add(new InteractiveFeature());
// CLI Options
commandSet.Add(mainFeature.UseInput);
commandSet.Add(mainFeature.MediaTypeInput);
commandSet.Add(mainFeature.DeviceInput);
commandSet.Add(mainFeature.MountedInput);
commandSet.Add(mainFeature.FileInput);
commandSet.Add(mainFeature.SpeedInput);
commandSet.Add(mainFeature.CustomInput);
return commandSet;
}
}
}

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/>
</startup>
</configuration>

View File

@@ -0,0 +1,187 @@
using System;
using System.IO;
#if NET40
using System.Threading.Tasks;
#endif
using MPF.Frontend;
using SabreTools.RedumpLib.Data;
using SabreTools.RedumpLib.Web;
using LogCompression = MPF.Processors.LogCompression;
namespace MPF.Check.Features
{
internal abstract class BaseFeature : SabreTools.CommandLine.Feature
{
#region Properties
/// <summary>
/// User-defined options
/// </summary>
public Options Options { get; protected set; }
/// <summary>
/// Currently-selected system
/// </summary>
public RedumpSystem? System { get; protected set; }
/// <summary>
/// Seed submission info from an input file
/// </summary>
public SubmissionInfo? Seed { get; protected set; }
/// <summary>
/// Path to the device to scan
/// </summary>
public string? DevicePath { get; protected set; }
#endregion
protected BaseFeature(string name, string[] flags, string description, string? detailed = null)
: base(name, flags, description, detailed)
{
Options = new Options()
{
// Internal Program
InternalProgram = InternalProgram.NONE,
// Extra Dumping Options
ScanForProtection = false,
AddPlaceholders = true,
PullAllInformation = false,
AddFilenameSuffix = false,
OutputSubmissionJSON = false,
IncludeArtifacts = false,
CompressLogFiles = false,
LogCompression = LogCompression.DeflateMaximum,
DeleteUnnecessaryFiles = false,
CreateIRDAfterDumping = false,
// Protection Scanning Options
ScanArchivesForProtection = true,
IncludeDebugProtectionInformation = false,
HideDriveLetters = false,
// Redump Login Information
RetrieveMatchInformation = true,
RedumpUsername = null,
RedumpPassword = null,
};
}
/// <inheritdoc/>
public override bool Execute()
{
// Validate a system type is provided
if (System == null)
{
Console.Error.WriteLine("A system name needs to be provided");
return false;
}
// Log the system being used, in case it came from config
Console.WriteLine($"Using system: {System.LongName()}");
// Validate a program is provided
if (Options.InternalProgram == InternalProgram.NONE)
{
Console.Error.WriteLine("A program name needs to be provided");
return false;
}
// Validate the supplied credentials
if (Options.RetrieveMatchInformation
&& !string.IsNullOrEmpty(Options.RedumpUsername)
&& !string.IsNullOrEmpty(Options.RedumpPassword))
{
bool? validated = RedumpClient.ValidateCredentials(Options.RedumpUsername!, Options.RedumpPassword!).GetAwaiter().GetResult();
string message = validated switch
{
true => "Redump username and password accepted!",
false => "Redump username and password denied!",
null => "An error occurred validating your credentials!",
};
Console.WriteLine(message);
}
// Loop through all the rest of the args
for (int i = 0; i < Inputs.Count; i++)
{
// Get the full file path
string filepath = Path.GetFullPath(Inputs[i].Trim('"'));
// Now populate an environment
Drive? drive = null;
if (!string.IsNullOrEmpty(DevicePath))
drive = Drive.Create(null, DevicePath!);
var env = new DumpEnvironment(Options,
filepath,
drive,
System,
internalProgram: null);
env.SetProcessor();
// Finally, attempt to do the output dance
var result = env.VerifyAndSaveDumpOutput(seedInfo: Seed)
.ConfigureAwait(false).GetAwaiter().GetResult();
Console.WriteLine(result.Message);
}
return true;
}
/// <summary>
/// Display help for MPF.Check
/// </summary>
/// <param name="error">Error string to prefix the help text with</param>
public static void DisplayHelp()
{
Console.WriteLine("Usage:");
Console.WriteLine("MPF.Check <system> [options] </path/to/output.cue|iso|_logs.zip> ...");
Console.WriteLine();
Console.WriteLine("Standalone Options:");
Console.WriteLine("?, h, help Show this help text");
Console.WriteLine("version Print the program version");
Console.WriteLine("lc, listcodes List supported comment/content site codes");
Console.WriteLine("lo, listconfig List current configuration values");
Console.WriteLine("lm, listmedia List supported media types");
Console.WriteLine("ls, listsystems List supported system types");
Console.WriteLine("lp, listprograms List supported dumping program outputs");
Console.WriteLine("i, interactive Enable interactive mode");
Console.WriteLine();
Console.WriteLine("Check Options:");
Console.WriteLine("-u, --use <program> Dumping program output type [REQUIRED]");
Console.WriteLine(" --load-seed <path> Load a seed submission JSON for user information");
Console.WriteLine(" --no-placeholders Disable placeholder values in submission info");
Console.WriteLine(" --create-ird Create IRD from output files (PS3 only)");
Console.WriteLine(" --no-retrieve Disable retrieving match information from Redump");
Console.WriteLine("-c, --credentials <user> <pw> Redump username and password (incompatible with --no-retrieve) [WILL BE REMOVED]");
Console.WriteLine("-U, --username <user> Redump username (incompatible with --no-retrieve)");
Console.WriteLine("-P, --password <pw> Redump password (incompatible with --no-retrieve)");
Console.WriteLine(" --pull-all Pull all information from Redump (requires --username and --password)");
Console.WriteLine("-p, --path <drivepath> Physical drive path for additional checks");
Console.WriteLine("-s, --scan Enable copy protection scan (requires --path)");
Console.WriteLine(" --disable-archives Disable scanning archives (requires --scan)");
Console.WriteLine(" --enable-debug Enable debug protection information (requires --scan)");
Console.WriteLine(" --hide-drive-letters Hide drive letters from scan output (requires --scan)");
Console.WriteLine("-x, --suffix Enable adding filename suffix");
Console.WriteLine("-j, --json Enable submission JSON output");
Console.WriteLine(" --include-artifacts Include artifacts in JSON (requires --json)");
Console.WriteLine("-z, --zip Enable log file compression");
Console.WriteLine(" --log-compression Set the log compression type (requires compression enabled)");
Console.WriteLine("-d, --delete Enable unnecessary file deletion");
Console.WriteLine();
Console.WriteLine("WARNING: If using a configuration file alongside any of the above options");
Console.WriteLine("then flag options will act as toggles instead of always enabling.");
Console.WriteLine("For example, if log compression is enabled in your configuration file, then");
Console.WriteLine("providing the --zip option would disable compression.");
Console.WriteLine();
Console.WriteLine("WARNING: Check will overwrite both any existing submission information files as well");
Console.WriteLine("as any log archives. Please make backups of those if you need to before running Check.");
Console.WriteLine();
}
}
}

View File

@@ -0,0 +1,288 @@
using System;
using MPF.Frontend;
using MPF.Frontend.Tools;
using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;
using LogCompression = MPF.Processors.LogCompression;
namespace MPF.Check.Features
{
internal sealed class InteractiveFeature : BaseFeature
{
#region Feature Definition
public const string DisplayName = "interactive";
private static readonly string[] _flags = ["i", "interactive"];
private const string _description = "Enable interactive mode";
#endregion
public InteractiveFeature()
: base(DisplayName, _flags, _description)
{
}
/// <inheritdoc/>
public override bool ProcessArgs(string[] args, int index)
{
// Cache all args as inputs
for (int i = 1; i < args.Length; i++)
{
Inputs.Add(args[i]);
}
// Read the options from config, if possible
Options = OptionsLoader.LoadFromConfig();
if (Options.FirstRun)
{
Options = new Options()
{
// Internal Program
InternalProgram = InternalProgram.NONE,
// Extra Dumping Options
ScanForProtection = false,
AddPlaceholders = true,
PullAllInformation = false,
AddFilenameSuffix = false,
OutputSubmissionJSON = false,
IncludeArtifacts = false,
CompressLogFiles = false,
LogCompression = LogCompression.DeflateMaximum,
DeleteUnnecessaryFiles = false,
CreateIRDAfterDumping = false,
// Protection Scanning Options
ScanArchivesForProtection = true,
IncludeDebugProtectionInformation = false,
HideDriveLetters = false,
// Redump Login Information
RetrieveMatchInformation = true,
RedumpUsername = null,
RedumpPassword = null,
};
}
// Create return values
System = null;
// These values require multiple parts to be active
bool scan = false,
enableArchives = true,
enableDebug = false,
hideDriveLetters = false;
// Create state values
string? result;
root:
Console.Clear();
Console.WriteLine("MPF.Check Interactive Mode - Main Menu");
Console.WriteLine("-------------------------");
Console.WriteLine();
Console.WriteLine($"1) Set system (Currently '{System}')");
Console.WriteLine($"2) Set dumping program (Currently '{Options.InternalProgram}')");
Console.WriteLine($"3) Set seed path (Currently '{Seed}')");
Console.WriteLine($"4) Add placeholders (Currently '{Options.AddPlaceholders}')");
Console.WriteLine($"5) Create IRD (Currently '{Options.CreateIRDAfterDumping}')");
Console.WriteLine($"6) Attempt Redump matches (Currently '{Options.RetrieveMatchInformation}')");
Console.WriteLine($"7) Redump credentials (Currently '{Options.RedumpUsername}')");
Console.WriteLine($"8) Pull all information (Currently '{Options.PullAllInformation}')");
Console.WriteLine($"9) Set device path (Currently '{DevicePath}')");
Console.WriteLine($"A) Scan for protection (Currently '{scan}')");
Console.WriteLine($"B) Scan archives for protection (Currently '{enableArchives}')");
Console.WriteLine($"C) Debug protection scan output (Currently '{enableDebug}')");
Console.WriteLine($"D) Hide drive letters in protection output (Currently '{hideDriveLetters}')");
Console.WriteLine($"E) Hide filename suffix (Currently '{Options.AddFilenameSuffix}')");
Console.WriteLine($"F) Output submission JSON (Currently '{Options.OutputSubmissionJSON}')");
Console.WriteLine($"G) Include JSON artifacts (Currently '{Options.IncludeArtifacts}')");
Console.WriteLine($"H) Compress logs (Currently '{Options.CompressLogFiles}')");
Console.WriteLine($"I) Log compression (Currently '{Options.LogCompression.LongName()}')");
Console.WriteLine($"J) Delete unnecessary files (Currently '{Options.DeleteUnnecessaryFiles}')");
Console.WriteLine();
Console.WriteLine($"Q) Exit the program");
Console.WriteLine($"X) Start checking");
Console.Write("> ");
result = Console.ReadLine();
switch (result)
{
case "1":
goto system;
case "2":
goto dumpingProgram;
case "3":
goto seedPath;
case "4":
Options.AddPlaceholders = !Options.AddPlaceholders;
goto root;
case "5":
Options.CreateIRDAfterDumping = !Options.CreateIRDAfterDumping;
goto root;
case "6":
Options.RetrieveMatchInformation = !Options.RetrieveMatchInformation;
goto root;
case "7":
goto redumpCredentials;
case "8":
Options.PullAllInformation = !Options.PullAllInformation;
goto root;
case "9":
goto devicePath;
case "a":
case "A":
scan = !scan;
goto root;
case "b":
case "B":
enableArchives = !enableArchives;
goto root;
case "c":
case "C":
enableDebug = !enableDebug;
goto root;
case "d":
case "D":
hideDriveLetters = !hideDriveLetters;
goto root;
case "e":
case "E":
Options.AddFilenameSuffix = !Options.AddFilenameSuffix;
goto root;
case "f":
case "F":
Options.OutputSubmissionJSON = !Options.OutputSubmissionJSON;
goto root;
case "g":
case "G":
Options.IncludeArtifacts = !Options.IncludeArtifacts;
goto root;
case "h":
case "H":
Options.CompressLogFiles = !Options.CompressLogFiles;
goto root;
case "i":
case "I":
goto logCompression;
case "j":
case "J":
Options.DeleteUnnecessaryFiles = !Options.DeleteUnnecessaryFiles;
goto root;
case "q":
case "Q":
Environment.Exit(0);
break;
case "x":
case "X":
Console.Clear();
goto exit;
case "z":
case "Z":
Console.WriteLine("It is pitch black. You are likely to be eaten by a grue.");
Console.Write("> ");
Console.ReadLine();
goto root;
default:
Console.WriteLine($"Invalid selection: {result}");
Console.ReadLine();
goto root;
}
system:
Console.WriteLine();
Console.WriteLine("For possible inputs, use the List Systems commandline option");
Console.WriteLine();
Console.WriteLine("Input the system and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
System = result.ToRedumpSystem();
goto root;
dumpingProgram:
Console.WriteLine();
Console.WriteLine("Options:");
foreach (var program in (InternalProgram[])Enum.GetValues(typeof(InternalProgram)))
{
// Skip the placeholder values
if (program == InternalProgram.NONE)
continue;
Console.WriteLine($"{program.ToString().ToLowerInvariant(),-15} => {program.LongName()}");
}
Console.WriteLine();
Console.WriteLine("Input the dumping program and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
Options.InternalProgram = result.ToInternalProgram();
goto root;
seedPath:
Console.WriteLine();
Console.WriteLine("Input the seed path and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
Seed = Builder.CreateFromFile(result);
goto root;
redumpCredentials:
Console.WriteLine();
Console.WriteLine("Enter your Redump username and press Enter:");
Console.Write("> ");
Options.RedumpUsername = Console.ReadLine();
Console.WriteLine("Enter your Redump password (hidden) and press Enter:");
Console.Write("> ");
Options.RedumpPassword = string.Empty;
while (true)
{
var key = Console.ReadKey(true);
if (key.Key == ConsoleKey.Enter)
break;
Options.RedumpPassword += key.KeyChar;
}
goto root;
devicePath:
Console.WriteLine();
Console.WriteLine("Input the device path and press Enter:");
Console.Write("> ");
DevicePath = Console.ReadLine();
goto root;
logCompression:
Console.WriteLine();
Console.WriteLine("Options:");
foreach (var compressionType in (LogCompression[])Enum.GetValues(typeof(LogCompression)))
{
Console.WriteLine($"{compressionType.ToString().ToLowerInvariant(),-15} => {compressionType.LongName()}");
}
Console.WriteLine();
Console.WriteLine("Input the log compression type and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
Options.LogCompression = result.ToLogCompression();
goto root;
exit:
// Now deal with the complex options
Options.ScanForProtection = scan && !string.IsNullOrEmpty(DevicePath);
Options.ScanArchivesForProtection = enableArchives && scan && !string.IsNullOrEmpty(DevicePath);
Options.IncludeDebugProtectionInformation = enableDebug && scan && !string.IsNullOrEmpty(DevicePath);
Options.HideDriveLetters = hideDriveLetters && scan && !string.IsNullOrEmpty(DevicePath);
return true;
}
/// <inheritdoc/>
public override bool VerifyInputs() => Inputs.Count > 0;
}
}

View File

@@ -0,0 +1,272 @@
using System;
using MPF.Frontend;
using MPF.Frontend.Tools;
using SabreTools.CommandLine.Inputs;
using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;
using LogCompression = MPF.Processors.LogCompression;
namespace MPF.Check.Features
{
internal sealed class MainFeature : BaseFeature
{
#region Feature Definition
public const string DisplayName = "main";
/// <remarks>Flags are unused</remarks>
private static readonly string[] _flags = [];
/// <remarks>Description is unused</remarks>
private const string _description = "";
#endregion
#region Inputs
private const string _createIrdName = "create-ird";
internal readonly FlagInput CreateIrdInput = new(_createIrdName, "--create-ird", "Create IRD from output files (PS3 only)");
private const string _deleteName = "delete";
internal readonly FlagInput DeleteInput = new(_deleteName, ["-d", "--delete"], "Enable unnecessary file deletion");
private const string _disableArchivesName = "disable-archives";
internal readonly FlagInput DisableArchivesInput = new(_disableArchivesName, "--disable-archives", "Disable scanning archives (requires --scan)");
private const string _enableDebugName = "enable-debug";
internal readonly FlagInput EnableDebugInput = new(_enableDebugName, "--enable-debug", "Enable debug protection information (requires --scan)");
private const string _hideDriveLettersName = "hide-drive-letters";
internal readonly FlagInput HideDriveLettersInput = new(_hideDriveLettersName, "--hide-drive-letters", "Hide drive letters from scan output (requires --scan)");
private const string _includeArtifactsName = "include-artifacts";
internal readonly FlagInput IncludeArtifactsInput = new(_includeArtifactsName, "--include-artifacts", "Include artifacts in JSON (requires --json)");
private const string _jsonName = "json";
internal readonly FlagInput JsonInput = new(_jsonName, ["-j", "--json"], "Enable submission JSON output");
private const string _loadSeedName = "load-seed";
internal readonly StringInput LoadSeedInput = new(_loadSeedName, "--load-seed", "Load a seed submission JSON for user information");
private const string _logCompressionName = "log-compression";
internal readonly StringInput LogCompressionInput = new(_logCompressionName, "--log-compression", "Set the log compression type (requires compression enabled)");
private const string _noPlaceholdersName = "no-placeholders";
internal readonly FlagInput NoPlaceholdersInput = new(_noPlaceholdersName, "--no-placeholders", "Disable placeholder values in submission info");
private const string _noRetrieveName = "no-retrieve";
internal readonly FlagInput NoRetrieveInput = new(_noRetrieveName, "--no-retrieve", "Disable retrieving match information from Redump");
private const string _passwordName = "password";
internal readonly StringInput PasswordInput = new(_passwordName, ["-P", "--password"], "Redump password (incompatible with --no-retrieve)");
private const string _pathName = "path";
internal readonly StringInput PathInput = new(_pathName, ["-p", "--path"], "Physical drive path for additional checks");
private const string _pullAllName = "pull-all";
internal readonly FlagInput PullAllInput = new(_pullAllName, "--pull-all", "Pull all information from Redump (requires --username and --password)");
private const string _scanName = "scan";
internal readonly FlagInput ScanInput = new(_scanName, ["-s", "--scan"], "Enable copy protection scan (requires --path)");
private const string _suffixName = "suffix";
internal readonly FlagInput SuffixInput = new(_suffixName, ["-x", "--suffix"], "Enable adding filename suffix");
private const string _useName = "use";
internal readonly StringInput UseInput = new(_useName, ["-u", "--use"], "Override configured dumping program name");
private const string _usernameName = "username";
internal readonly StringInput UsernameInput = new(_usernameName, ["-U", "--username"], "Redump username (incompatible with --no-retrieve)");
private const string _zipName = "zip";
internal readonly FlagInput ZipInput = new(_zipName, ["-z", "--zip"], "Enable log file compression");
#endregion
public MainFeature()
: base(DisplayName, _flags, _description)
{
Add(UseInput);
Add(LoadSeedInput);
Add(NoPlaceholdersInput);
Add(CreateIrdInput);
Add(NoRetrieveInput);
// TODO: Figure out how to work with the credentials input
Add(PullAllInput);
Add(PathInput);
Add(ScanInput);
Add(DisableArchivesInput);
Add(EnableDebugInput);
Add(HideDriveLettersInput);
Add(SuffixInput);
Add(JsonInput);
Add(IncludeArtifactsInput);
Add(ZipInput);
Add(LogCompressionInput);
Add(DeleteInput);
}
/// <inheritdoc/>
public override bool ProcessArgs(string[] args, int index)
{
// These values require multiple parts to be active
bool scan = false,
enableArchives = true,
enableDebug = false,
hideDriveLetters = false;
// If we have no arguments, just return
if (args is null || args.Length == 0)
return true;
// Read the options from config, if possible
Options = OptionsLoader.LoadFromConfig();
if (Options.FirstRun)
{
Options = new Options()
{
// Internal Program
InternalProgram = InternalProgram.NONE,
// Extra Dumping Options
ScanForProtection = false,
AddPlaceholders = true,
PullAllInformation = false,
AddFilenameSuffix = false,
OutputSubmissionJSON = false,
IncludeArtifacts = false,
CompressLogFiles = false,
LogCompression = LogCompression.DeflateMaximum,
DeleteUnnecessaryFiles = false,
CreateIRDAfterDumping = false,
// Protection Scanning Options
ScanArchivesForProtection = true,
IncludeDebugProtectionInformation = false,
HideDriveLetters = false,
// Redump Login Information
RetrieveMatchInformation = true,
RedumpUsername = null,
RedumpPassword = null,
};
}
else
{
Console.WriteLine("Options will be loaded from found configuration file!");
}
// The first argument is the system type
System = args[0].Trim('"').ToRedumpSystem();
// Loop through the arguments and parse out values
for (index = 1; index < args.Length; index++)
{
// Use specific program
if (UseInput.ProcessInput(args, ref index))
Options.InternalProgram = UseInput.Value.ToInternalProgram();
// Include seed info file
else if (LoadSeedInput.ProcessInput(args, ref index))
Seed = Builder.CreateFromFile(LoadSeedInput.Value);
// Disable placeholder values in submission info
else if (NoPlaceholdersInput.ProcessInput(args, ref index))
Options.AddPlaceholders = !Options.AddPlaceholders;
// Create IRD from output files (PS3 only)
else if (CreateIrdInput.ProcessInput(args, ref index))
Options.CreateIRDAfterDumping = !Options.CreateIRDAfterDumping;
// Set the log compression type (requires compression enabled)
else if (LogCompressionInput.ProcessInput(args, ref index))
Options.LogCompression = LogCompressionInput.Value.ToLogCompression();
// Retrieve Redump match information
else if (NoRetrieveInput.ProcessInput(args, ref index))
Options.RetrieveMatchInformation = !Options.RetrieveMatchInformation;
// Redump login
else if (args[index].StartsWith("-c=") || args[index].StartsWith("--credentials="))
{
string[] credentials = args[index].Split('=')[1].Split(';');
Options.RedumpUsername = credentials[0];
Options.RedumpPassword = credentials[1];
}
else if (args[index] == "-c" || args[index] == "--credentials")
{
Options.RedumpUsername = args[index + 1];
Options.RedumpPassword = args[index + 2];
index += 2;
}
// Redump username
else if (UsernameInput.ProcessInput(args, ref index))
Options.RedumpUsername = UsernameInput.Value;
// Redump password
else if (PasswordInput.ProcessInput(args, ref index))
Options.RedumpPassword = PasswordInput.Value;
// Pull all information (requires Redump login)
else if (PullAllInput.ProcessInput(args, ref index))
Options.PullAllInformation = !Options.PullAllInformation;
// Use a device path for physical checks
else if (PathInput.ProcessInput(args, ref index))
DevicePath = PathInput.Value;
// Scan for protection (requires device path)
else if (ScanInput.ProcessInput(args, ref index))
scan = true;
// Disable scanning archives (requires --scan)
else if (ScanInput.ProcessInput(args, ref index))
enableArchives = false;
// Enable debug protection information (requires --scan)
else if (EnableDebugInput.ProcessInput(args, ref index))
enableDebug = true;
// Hide drive letters from scan output (requires --scan)
else if (HideDriveLettersInput.ProcessInput(args, ref index))
hideDriveLetters = true;
// Add filename suffix
else if (SuffixInput.ProcessInput(args, ref index))
Options.AddFilenameSuffix = !Options.AddFilenameSuffix;
// Output submission JSON
else if (JsonInput.ProcessInput(args, ref index))
Options.OutputSubmissionJSON = !Options.OutputSubmissionJSON;
// Include JSON artifacts
else if (IncludeArtifactsInput.ProcessInput(args, ref index))
Options.IncludeArtifacts = !Options.IncludeArtifacts;
// Compress log and extraneous files
else if (ZipInput.ProcessInput(args, ref index))
Options.CompressLogFiles = !Options.CompressLogFiles;
// Delete unnecessary files
else if (DeleteInput.ProcessInput(args, ref index))
Options.DeleteUnnecessaryFiles = !Options.DeleteUnnecessaryFiles;
// Default, add to inputs
else
Inputs.Add(args[index]);
}
// Now deal with the complex options
Options.ScanForProtection = scan && !string.IsNullOrEmpty(DevicePath);
Options.ScanArchivesForProtection = enableArchives && scan && !string.IsNullOrEmpty(DevicePath);
Options.IncludeDebugProtectionInformation = enableDebug && scan && !string.IsNullOrEmpty(DevicePath);
Options.HideDriveLetters = hideDriveLetters && scan && !string.IsNullOrEmpty(DevicePath);
return true;
}
/// <inheritdoc/>
public override bool VerifyInputs() => Inputs.Count > 0;
}
}

View File

@@ -1,37 +1,50 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;net6.0;net7.0</TargetFrameworks>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<OutputType>Exe</OutputType>
<Title>MPF Check</Title>
<Description>Validator for various dumping programs</Description>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2023</Copyright>
<VersionPrefix>2.7.1</VersionPrefix>
</PropertyGroup>
<PropertyGroup>
<!-- Assembly Properties -->
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
<OutputType>Exe</OutputType>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<LangVersion>latest</LangVersion>
<NoWarn>NU1902;NU1903</NoWarn>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<VersionPrefix>3.6.0</VersionPrefix>
<PropertyGroup Condition="'$(TargetFramework)'!='net48'">
<Nullable>enable</Nullable>
</PropertyGroup>
<!-- Package Properties -->
<Title>MPF Check</Title>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Description>Validator for various dumping programs</Description>
<Copyright>Copyright (c) Matt Nadareski 2019-2025</Copyright>
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
<RepositoryType>git</RepositoryType>
</PropertyGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<!-- Support All Frameworks -->
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net4`))">
<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith(`netcoreapp`)) OR $(TargetFramework.StartsWith(`net5`))">
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net6`)) OR $(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`)) OR $(TargetFramework.StartsWith(`net9`)) OR $(TargetFramework.StartsWith(`net10`))">
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(RuntimeIdentifier.StartsWith(`osx-arm`))">
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MPF.Frontend\MPF.Frontend.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="2.8.0" GeneratePathProperty="true">
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="SabreTools.RedumpLib" Version="1.1.1" />
</ItemGroup>
<ItemGroup>
<Content Include="$(PkgBurnOutSharp)\content\**" PackagePath="contentFiles\any\any;content" CopyToOutputDirectory="Always" PackageCopyToOutput="true" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.CommandLine" Version="[1.4.0]" />
<PackageReference Include="SabreTools.RedumpLib" Version="[1.9.1]" />
</ItemGroup>
</Project>

View File

@@ -1,11 +1,12 @@
using System;
using System.IO;
using BurnOutSharp;
using MPF.Core;
using MPF.Core.Data;
using MPF.Core.Utilities;
using SabreTools.RedumpLib.Data;
using SabreTools.RedumpLib.Web;
using System.Collections.Generic;
#if NET40
using System.Threading.Tasks;
#endif
using MPF.Check.Features;
using MPF.Frontend.Features;
using SabreTools.CommandLine;
using SabreTools.CommandLine.Features;
namespace MPF.Check
{
@@ -13,106 +14,132 @@ namespace MPF.Check
{
public static void Main(string[] args)
{
// Create the command set
var mainFeature = new MainFeature();
var commandSet = CreateCommands(mainFeature);
// If we have no args, show the help and quit
if (args is null || args.Length == 0)
{
BaseFeature.DisplayHelp();
return;
}
// Get the first argument as a feature flag
string featureName = args[0];
// Try processing the standalone arguments
bool? standaloneProcessed = OptionsLoader.ProcessStandaloneArguments(args);
if (standaloneProcessed != false)
var topLevel = commandSet.GetTopLevel(featureName);
switch (topLevel)
{
if (standaloneProcessed == null)
DisplayHelp();
return;
}
// Standalone Options
case Help: BaseFeature.DisplayHelp(); return;
case VersionFeature version: version.Execute(); return;
case ListCodesFeature lc: lc.Execute(); return;
case ListConfigFeature lc: lc.Execute(); return;
case ListMediaTypesFeature lm: lm.Execute(); return;
case ListProgramsFeature lp: lp.Execute(); return;
case ListSystemsFeature ls: ls.Execute(); return;
// Try processing the common arguments
(bool success, MediaType mediaType, RedumpSystem? knownSystem, var error) = OptionsLoader.ProcessCommonArguments(args);
if (!success)
{
DisplayHelp(error);
return;
}
// Interactive Mode
case InteractiveFeature interactive:
if (!interactive.ProcessArgs(args, 0))
{
BaseFeature.DisplayHelp();
return;
}
// Loop through and process options
(var options, var seedInfo, var path, int startIndex) = OptionsLoader.LoadFromArguments(args, startIndex: 2);
if (options.InternalProgram == InternalProgram.NONE)
{
DisplayHelp("A program name needs to be provided");
return;
}
if (!interactive.VerifyInputs())
{
Console.Error.WriteLine("At least one input is required");
BaseFeature.DisplayHelp();
return;
}
// Make new Progress objects
var resultProgress = new Progress<Result>();
resultProgress.ProgressChanged += ConsoleLogger.ProgressUpdated;
var protectionProgress = new Progress<ProtectionProgress>();
protectionProgress.ProgressChanged += ConsoleLogger.ProgressUpdated;
if (!interactive.Execute())
{
BaseFeature.DisplayHelp();
return;
}
// Validate the supplied credentials
#if NET48
(bool? _, string message) = RedumpWebClient.ValidateCredentials(options?.RedumpUsername, options?.RedumpPassword);
#else
(bool? _, string? message) = RedumpHttpClient.ValidateCredentials(options.RedumpUsername ?? string.Empty, options.RedumpPassword ?? string.Empty).ConfigureAwait(false).GetAwaiter().GetResult();
#endif
if (!string.IsNullOrWhiteSpace(message))
Console.WriteLine(message);
break;
// Loop through all the rest of the args
for (int i = startIndex; i < args.Length; i++)
{
// Check for a file
if (!File.Exists(args[i].Trim('"')))
{
DisplayHelp($"{args[i].Trim('"')} does not exist");
return;
}
// Default Behavior
default:
if (!mainFeature.ProcessArgs(args, 0))
{
BaseFeature.DisplayHelp();
return;
}
// Get the full file path
string filepath = Path.GetFullPath(args[i].Trim('"'));
if (!mainFeature.VerifyInputs())
{
Console.Error.WriteLine("At least one input is required");
BaseFeature.DisplayHelp();
return;
}
// Now populate an environment
#if NET48
Drive drive = null;
#else
Drive? drive = null;
#endif
if (!string.IsNullOrWhiteSpace(path))
drive = Drive.Create(null, path);
if (!mainFeature.Execute())
{
BaseFeature.DisplayHelp();
return;
}
var env = new DumpEnvironment(options, filepath, drive, knownSystem, mediaType, internalProgram: null, parameters: null);
// Finally, attempt to do the output dance
var result = env.VerifyAndSaveDumpOutput(resultProgress, protectionProgress).ConfigureAwait(false).GetAwaiter().GetResult();
Console.WriteLine(result.Message);
break;
}
}
/// <summary>
/// Display help for MPF.Check
/// Create the command set for the program
/// </summary>
/// <param name="error">Error string to prefix the help text with</param>
#if NET48
private static void DisplayHelp(string error = null)
#else
private static void DisplayHelp(string? error = null)
#endif
private static CommandSet CreateCommands(MainFeature mainFeature)
{
if (error != null)
Console.WriteLine(error);
List<string> header = [
"MPF.CLI [standalone|system] [options] <path> ...",
string.Empty,
];
Console.WriteLine("Usage:");
Console.WriteLine("MPF.Check.exe <mediatype> <system> [options] </path/to/output.cue/iso> ...");
Console.WriteLine();
Console.WriteLine("Standalone Options:");
Console.WriteLine("-h, -? Show this help text");
Console.WriteLine("-lm, --listmedia List supported media types");
Console.WriteLine("-ls, --listsystems List supported system types");
Console.WriteLine("-lp, --listprograms List supported dumping program outputs");
Console.WriteLine();
List<string> footer = [
string.Empty,
"WARNING: Check will overwrite both any existing submission information files as well",
"as any log archives. Please make backups of those if you need to before running Check.",
string.Empty,
];
Console.WriteLine("Check Options:");
var supportedArguments = OptionsLoader.PrintSupportedArguments();
foreach (string argument in supportedArguments)
{
Console.WriteLine(argument);
}
Console.WriteLine();
var commandSet = new CommandSet(header, footer);
// Standalone Options
commandSet.Add(new Help());
commandSet.Add(new VersionFeature());
commandSet.Add(new ListCodesFeature());
commandSet.Add(new ListConfigFeature());
commandSet.Add(new ListMediaTypesFeature());
commandSet.Add(new ListSystemsFeature());
commandSet.Add(new ListProgramsFeature());
commandSet.Add(new InteractiveFeature());
// Check Options
commandSet.Add(mainFeature.UseInput);
commandSet.Add(mainFeature.LoadSeedInput);
commandSet.Add(mainFeature.NoPlaceholdersInput);
commandSet.Add(mainFeature.CreateIrdInput);
commandSet.Add(mainFeature.NoRetrieveInput);
commandSet.Add(mainFeature.UsernameInput);
commandSet.Add(mainFeature.PasswordInput);
commandSet.Add(mainFeature.PullAllInput);
commandSet.Add(mainFeature.PathInput);
commandSet.Add(mainFeature.ScanInput);
commandSet.Add(mainFeature.DisableArchivesInput);
commandSet.Add(mainFeature.EnableDebugInput);
commandSet.Add(mainFeature.HideDriveLettersInput);
commandSet.Add(mainFeature.SuffixInput);
commandSet.Add(mainFeature.JsonInput);
commandSet.Add(mainFeature.IncludeArtifactsInput);
commandSet.Add(mainFeature.ZipInput);
commandSet.Add(mainFeature.LogCompressionInput);
commandSet.Add(mainFeature.DeleteInput);
return commandSet;
}
}
}

View File

@@ -1,7 +0,0 @@
{
"profiles": {
"MPF.Check": {
"commandName": "Project"
}
}
}

View File

@@ -1,345 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Reflection;
using MPF.Core.Data;
using SabreTools.RedumpLib.Data;
namespace MPF.Core.Converters
{
public static class EnumConverter
{
#region Cross-enumeration conversions
/// <summary>
/// Convert drive type to internal version, if possible
/// </summary>
/// <param name="driveType">DriveType value to check</param>
/// <returns>InternalDriveType, if possible, null on error</returns>
public static InternalDriveType? ToInternalDriveType(this DriveType driveType)
{
switch (driveType)
{
case DriveType.CDRom:
return InternalDriveType.Optical;
case DriveType.Fixed:
return InternalDriveType.HardDisk;
case DriveType.Removable:
return InternalDriveType.Removable;
default:
return null;
}
}
#endregion
#region Convert to Long Name
/// <summary>
/// Long name method cache
/// </summary>
#if NET48
private static readonly ConcurrentDictionary<Type, MethodInfo> LongNameMethods = new ConcurrentDictionary<Type, MethodInfo>();
#else
private static readonly ConcurrentDictionary<Type, MethodInfo?> LongNameMethods = new ConcurrentDictionary<Type, MethodInfo?>();
#endif
/// <summary>
/// Get the string representation of a generic enumerable value
/// </summary>
/// <param name="value">Enum value to convert</param>
/// <returns>String representation of that value if possible, empty string on error</returns>
public static string GetLongName(Enum value)
{
try
{
var sourceType = value.GetType();
sourceType = Nullable.GetUnderlyingType(sourceType) ?? sourceType;
if (!LongNameMethods.TryGetValue(sourceType, out var method))
{
method = typeof(Extensions).GetMethod("LongName", new[] { typeof(Nullable<>).MakeGenericType(sourceType) });
if (method == null)
method = typeof(EnumConverter).GetMethod("LongName", new[] { typeof(Nullable<>).MakeGenericType(sourceType) });
LongNameMethods.TryAdd(sourceType, method);
}
if (method != null)
return method.Invoke(null, new[] { value }) as string ?? string.Empty;
else
return string.Empty;
}
catch
{
// Converter is not implemented for the given type
return string.Empty;
}
}
/// <summary>
/// Get the string representation of the InternalProgram enum values
/// </summary>
/// <param name="prog">InternalProgram value to convert</param>
/// <returns>String representing the value, if possible</returns>
public static string LongName(this InternalProgram? prog)
{
switch (prog)
{
#region Dumping support
case InternalProgram.Aaru:
return "Aaru";
case InternalProgram.DiscImageCreator:
return "DiscImageCreator";
case InternalProgram.Redumper:
return "redumper";
#endregion
#region Verification support only
case InternalProgram.CleanRip:
return "CleanRip";
case InternalProgram.DCDumper:
return "DCDumper";
case InternalProgram.UmdImageCreator:
return "UmdImageCreator";
#endregion
case InternalProgram.NONE:
default:
return "Unknown";
}
}
#endregion
#region Convert From String
/// <summary>
/// Get the InternalProgram enum value for a given string
/// </summary>
/// <param name="internalProgram">String value to convert</param>
/// <returns>InternalProgram represented by the string, if possible</returns>
#if NET48
public static InternalProgram ToInternalProgram(string internalProgram)
#else
public static InternalProgram ToInternalProgram(string? internalProgram)
#endif
{
switch (internalProgram?.ToLowerInvariant())
{
// Dumping support
case "aaru":
case "chef":
case "dichef":
case "discimagechef":
return InternalProgram.Aaru;
case "creator":
case "dic":
case "dicreator":
case "discimagecreator":
return InternalProgram.DiscImageCreator;
case "rd":
case "redumper":
return InternalProgram.Redumper;
// Verification support only
case "cleanrip":
case "cr":
return InternalProgram.CleanRip;
case "dc":
case "dcd":
case "dcdumper":
return InternalProgram.DCDumper;
case "uic":
case "umd":
case "umdcreator":
case "umdimagecreator":
return InternalProgram.UmdImageCreator;
default:
return InternalProgram.NONE;
}
}
/// <summary>
/// Get the MediaType enum value for a given string
/// </summary>
/// <param name="type">String value to convert</param>
/// <returns>MediaType represented by the string, if possible</returns>
public static MediaType ToMediaType(string type)
{
switch (type.ToLowerInvariant())
{
#region Punched Media
case "aperture":
case "aperturecard":
case "aperture card":
return MediaType.ApertureCard;
case "jacquardloom":
case "jacquardloomcard":
case "jacquard loom card":
return MediaType.JacquardLoomCard;
case "magneticstripe":
case "magneticstripecard":
case "magnetic stripe card":
return MediaType.MagneticStripeCard;
case "opticalphone":
case "opticalphonecard":
case "optical phonecard":
return MediaType.OpticalPhonecard;
case "punchcard":
case "punchedcard":
case "punched card":
return MediaType.PunchedCard;
case "punchtape":
case "punchedtape":
case "punched tape":
return MediaType.PunchedTape;
#endregion
#region Tape
case "openreel":
case "openreeltape":
case "open reel tape":
return MediaType.OpenReel;
case "datacart":
case "datacartridge":
case "datatapecartridge":
case "data tape cartridge":
return MediaType.DataCartridge;
case "cassette":
case "cassettetape":
case "cassette tape":
return MediaType.Cassette;
#endregion
#region Disc / Disc
case "bd":
case "bdrom":
case "bd-rom":
case "bluray":
return MediaType.BluRay;
case "cd":
case "cdrom":
case "cd-rom":
return MediaType.CDROM;
case "dvd":
case "dvd5":
case "dvd-5":
case "dvd9":
case "dvd-9":
case "dvdrom":
case "dvd-rom":
return MediaType.DVD;
case "fd":
case "floppy":
case "floppydisk":
case "floppy disk":
case "floppy diskette":
return MediaType.FloppyDisk;
case "floptical":
return MediaType.Floptical;
case "gd":
case "gdrom":
case "gd-rom":
return MediaType.GDROM;
case "hddvd":
case "hd-dvd":
case "hddvdrom":
case "hd-dvd-rom":
return MediaType.HDDVD;
case "hdd":
case "harddisk":
case "hard disk":
return MediaType.HardDisk;
case "bernoullidisk":
case "iomegabernoullidisk":
case "bernoulli disk":
case "iomega bernoulli disk":
return MediaType.IomegaBernoulliDisk;
case "jaz":
case "iomegajaz":
case "iomega jaz":
return MediaType.IomegaJaz;
case "zip":
case "zipdisk":
case "iomegazip":
case "iomega zip":
return MediaType.IomegaZip;
case "ldrom":
case "lvrom":
case "ld-rom":
case "lv-rom":
case "laserdisc":
case "laservision":
case "ld-rom / lv-rom":
return MediaType.LaserDisc;
case "64dd":
case "n64dd":
case "64dddisk":
case "n64dddisk":
case "64dd disk":
case "n64dd disk":
return MediaType.Nintendo64DD;
case "fds":
case "famicom":
case "nfds":
case "nintendofamicom":
case "famicomdisksystem":
case "famicom disk system":
case "famicom disk system disk":
return MediaType.NintendoFamicomDiskSystem;
case "gc":
case "gamecube":
case "nintendogamecube":
case "nintendo gamecube":
case "gamecube disc":
case "gamecube game disc":
return MediaType.NintendoGameCubeGameDisc;
case "wii":
case "nintendowii":
case "nintendo wii":
case "nintendo wii disc":
case "wii optical disc":
return MediaType.NintendoWiiOpticalDisc;
case "wiiu":
case "nintendowiiu":
case "nintendo wiiu":
case "nintendo wiiu disc":
case "wiiu optical disc":
case "wii u optical disc":
return MediaType.NintendoWiiUOpticalDisc;
case "umd":
return MediaType.UMD;
#endregion
// Unsorted Formats
case "cartridge":
return MediaType.Cartridge;
case "ced":
case "rcaced":
case "rca ced":
case "videodisc":
case "rca videodisc":
return MediaType.CED;
default:
return MediaType.NONE;
}
}
#endregion
}
}

View File

@@ -1,121 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using SabreTools.RedumpLib.Data;
namespace MPF.Core.Data
{
/// <summary>
/// Constant values for UI
/// </summary>
public static class Interface
{
// Button values
public const string StartDumping = "Start Dumping";
public const string StopDumping = "Stop Dumping";
// Byte arrays for signatures
public static readonly byte[] SaturnSectorZeroStart = new byte[] { 0x53, 0x45, 0x47, 0x41, 0x20, 0x53, 0x45, 0x47, 0x41, 0x53, 0x41, 0x54, 0x55, 0x52, 0x4E, 0x20 };
// Lists of known drive speed ranges
public static IReadOnlyList<int> CD { get; } = new List<int> { 1, 2, 3, 4, 6, 8, 12, 16, 20, 24, 32, 40, 44, 48, 52, 56, 72 };
public static IReadOnlyList<int> DVD { get; } = CD.Where(s => s <= 24).ToList();
public static IReadOnlyList<int> HDDVD { get; } = CD.Where(s => s <= 24).ToList();
public static IReadOnlyList<int> BD { get; } = CD.Where(s => s <= 16).ToList();
public static IReadOnlyList<int> Unknown { get; } = new List<int> { 1 };
/// <summary>
/// Get list of all drive speeds for a given MediaType
/// </summary>
/// <param name="type">MediaType? that represents the current item</param>
/// <returns>Read-only list of drive speeds</returns>
public static IReadOnlyList<int> GetSpeedsForMediaType(MediaType? type)
{
switch (type)
{
case MediaType.CDROM:
case MediaType.GDROM:
return CD;
case MediaType.DVD:
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
return DVD;
case MediaType.HDDVD:
return HDDVD;
case MediaType.BluRay:
return BD;
default:
return Unknown;
}
}
}
/// <summary>
/// Template field values for submission info
/// </summary>
public static class Template
{
// Manual information
public const string TitleField = "Title";
public const string ForeignTitleField = "Foreign Title (Non-latin)";
public const string DiscNumberField = "Disc Number / Letter";
public const string DiscTitleField = "Disc Title";
public const string SystemField = "System";
public const string MediaTypeField = "Media Type";
public const string CategoryField = "Category";
public const string RegionField = "Region";
public const string LanguagesField = "Languages";
public const string PlaystationLanguageSelectionViaField = "Language Selection Via";
public const string DiscSerialField = "Disc Serial";
public const string BarcodeField = "Barcode";
public const string CommentsField = "Comments";
public const string ContentsField = "Contents";
public const string VersionField = "Version";
public const string EditionField = "Edition/Release";
public const string PlayStation3WiiDiscKeyField = "Disc Key";
public const string PlayStation3DiscIDField = "Disc ID";
public const string GameCubeWiiBCAField = "BCA";
public const string CopyProtectionField = "Copy Protection";
public const string MasteringRingField = "Mastering Code (laser branded/etched)";
public const string MasteringSIDField = "Mastering SID Code";
public const string MouldSIDField = "Mould SID Code";
public const string AdditionalMouldField = "Additional Mould";
public const string ToolstampField = "Toolstamp or Mastering Code (engraved/stamped)";
// Automatic Information
public const string DumpingProgramField = "Dumping Program";
public const string DumpingDateField = "Date";
public const string DumpingDriveManufacturer = "Manufacturer";
public const string DumpingDriveModel = "Model";
public const string DumpingDriveFirmware = "Firmware";
public const string ReportedDiscType = "Reported Disc Type";
public const string PVDField = "Primary Volume Descriptor (PVD)";
public const string DATField = "DAT";
public const string SizeField = "Size";
public const string CRC32Field = "CRC32";
public const string MD5Field = "MD5";
public const string SHA1Field = "SHA1";
public const string FullyMatchingIDField = "Fully Matching ID";
public const string PartiallyMatchingIDsField = "Partially Matching IDs";
public const string ErrorCountField = "Error Count";
public const string CuesheetField = "Cuesheet";
public const string SubIntentionField = "SubIntention Data (SecuROM/LibCrypt)";
public const string WriteOffsetField = "Write Offset";
public const string LayerbreakField = "Layerbreak";
public const string EXEDateBuildDate = "EXE/Build Date";
public const string HeaderField = "Header";
public const string PICField = "Permanent Information & Control (PIC)";
public const string PlayStationEDCField = "EDC";
public const string PlayStationAntiModchipField = "Anti-modchip";
public const string PlayStationLibCryptField = "LibCrypt";
public const string XBOXSSRanges = "Security Sector Ranges";
// Default values
public const string RequiredValue = "(REQUIRED)";
public const string RequiredIfExistsValue = "(REQUIRED, IF EXISTS)";
public const string OptionalValue = "(OPTIONAL)";
public const string DiscNotDetected = "Disc Not Detected";
}
}

View File

@@ -1,672 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Management.Infrastructure;
using Microsoft.Management.Infrastructure.Generic;
using MPF.Core.Converters;
using MPF.Core.Utilities;
using SabreTools.RedumpLib.Data;
namespace MPF.Core.Data
{
/// <summary>
/// Represents information for a single drive
/// </summary>
/// <remarks>
/// TODO: This needs to be less Windows-centric. Devices do not always have a single letter that can be used.
/// TODO: Can the Aaru models be used instead of the ones I've created here?
/// </remarks>
public class Drive
{
#region Fields
/// <summary>
/// Represents drive type
/// </summary>
public InternalDriveType? InternalDriveType { get; set; }
/// <summary>
/// Drive partition format
/// </summary>
#if NET48
public string DriveFormat { get; private set; } = null;
#else
public string? DriveFormat { get; private set; } = null;
#endif
/// <summary>
/// Windows drive path
/// </summary>
#if NET48
public string Name { get; private set; } = null;
#else
public string? Name { get; private set; } = null;
#endif
/// <summary>
/// Represents if Windows has marked the drive as active
/// </summary>
public bool MarkedActive { get; private set; } = false;
/// <summary>
/// Represents the total size of the drive
/// </summary>
public long TotalSize { get; private set; } = default;
/// <summary>
/// Media label as read by Windows
/// </summary>
/// <remarks>The try/catch is needed because Windows will throw an exception if the drive is not marked as active</remarks>
#if NET48
public string VolumeLabel { get; private set; } = null;
#else
public string? VolumeLabel { get; private set; } = null;
#endif
#endregion
#region Derived Fields
/// <summary>
/// Media label as read by Windows, formatted to avoid odd outputs
/// </summary>
#if NET48
public string FormattedVolumeLabel
#else
public string? FormattedVolumeLabel
#endif
{
get
{
string volumeLabel = Template.DiscNotDetected;
if (this.MarkedActive)
{
if (string.IsNullOrWhiteSpace(this.VolumeLabel))
volumeLabel = "track";
else
volumeLabel = this.VolumeLabel;
}
foreach (char c in Path.GetInvalidFileNameChars())
volumeLabel = volumeLabel.Replace(c, '_');
return volumeLabel;
}
}
/// <summary>
/// Windows drive letter
/// </summary>
public char Letter => this.Name == null || this.Name.Length == 0 ? '\0' : this.Name[0];
#endregion
/// <summary>
/// Protected constructor
/// </summary>
protected Drive() { }
/// <summary>
/// Create a new Drive object from a drive type and device path
/// </summary>
/// <param name="driveType">InternalDriveType value representing the drive type</param>
/// <param name="devicePath">Path to the device according to the local machine</param>
#if NET48
public static Drive Create(InternalDriveType? driveType, string devicePath)
#else
public static Drive? Create(InternalDriveType? driveType, string devicePath)
#endif
{
// Create a new, empty drive object
var drive = new Drive()
{
InternalDriveType = driveType,
};
// If we have an invalid device path, return null
if (string.IsNullOrWhiteSpace(devicePath))
return null;
// Sanitize a Windows-formatted long device path
if (devicePath.StartsWith("\\\\.\\"))
#if NET48
devicePath = devicePath.Substring("\\\\.\\".Length);
#else
devicePath = devicePath["\\\\.\\".Length..];
#endif
// Create and validate the drive info object
var driveInfo = new DriveInfo(devicePath);
if (driveInfo == null || driveInfo == default)
return null;
// Fill in the rest of the data
drive.PopulateFromDriveInfo(driveInfo);
return drive;
}
/// <summary>
/// Populate all fields from a DriveInfo object
/// </summary>
/// <param name="driveInfo">DriveInfo object to populate from</param>
#if NET48
private void PopulateFromDriveInfo(DriveInfo driveInfo)
#else
private void PopulateFromDriveInfo(DriveInfo? driveInfo)
#endif
{
// If we have an invalid DriveInfo, just return
if (driveInfo == null || driveInfo == default)
return;
// Populate the data fields
this.Name = driveInfo.Name;
this.MarkedActive = driveInfo.IsReady;
if (this.MarkedActive)
{
this.DriveFormat = driveInfo.DriveFormat;
this.TotalSize = driveInfo.TotalSize;
this.VolumeLabel = driveInfo.VolumeLabel;
}
else
{
this.DriveFormat = string.Empty;
this.TotalSize = default;
this.VolumeLabel = string.Empty;
}
}
#region Public Functionality
/// <summary>
/// Create a list of active drives matched to their volume labels
/// </summary>
/// <param name="ignoreFixedDrives">True to ignore fixed drives from population, false otherwise</param>
/// <returns>Active drives, matched to labels, if possible</returns>
public static List<Drive> CreateListOfDrives(bool ignoreFixedDrives)
{
var drives = GetDriveList(ignoreFixedDrives);
drives = drives.OrderBy(i => i == null ? '\0' : i.Letter).ToList();
return drives;
}
/// <summary>
/// Get the current media type from drive letter
/// </summary>
/// <param name="system"></param>
/// <returns></returns>
#if NET48
public (MediaType?, string) GetMediaType(RedumpSystem? system)
#else
public (MediaType?, string?) GetMediaType(RedumpSystem? system)
#endif
{
// Take care of the non-optical stuff first
switch (this.InternalDriveType)
{
case Data.InternalDriveType.Floppy:
return (MediaType.FloppyDisk, null);
case Data.InternalDriveType.HardDisk:
return (MediaType.HardDisk, null);
case Data.InternalDriveType.Removable:
return (MediaType.FlashDrive, null);
}
// Some systems should default to certain media types
switch (system)
{
// CD
case RedumpSystem.Panasonic3DOInteractiveMultiplayer:
case RedumpSystem.PhilipsCDi:
case RedumpSystem.SegaDreamcast:
case RedumpSystem.SegaSaturn:
case RedumpSystem.SonyPlayStation:
case RedumpSystem.VideoCD:
return (MediaType.CDROM, null);
// DVD
case RedumpSystem.DVDAudio:
case RedumpSystem.DVDVideo:
case RedumpSystem.MicrosoftXbox:
case RedumpSystem.MicrosoftXbox360:
return (MediaType.DVD, null);
// HD-DVD
case RedumpSystem.HDDVDVideo:
return (MediaType.HDDVD, null);
// Blu-ray
case RedumpSystem.BDVideo:
case RedumpSystem.MicrosoftXboxOne:
case RedumpSystem.MicrosoftXboxSeriesXS:
case RedumpSystem.SonyPlayStation3:
case RedumpSystem.SonyPlayStation4:
case RedumpSystem.SonyPlayStation5:
return (MediaType.BluRay, null);
// GameCube
case RedumpSystem.NintendoGameCube:
return (MediaType.NintendoGameCubeGameDisc, null);
// Wii
case RedumpSystem.NintendoWii:
return (MediaType.NintendoWiiOpticalDisc, null);
// WiiU
case RedumpSystem.NintendoWiiU:
return (MediaType.NintendoWiiUOpticalDisc, null);
// PSP
case RedumpSystem.SonyPlayStationPortable:
return (MediaType.UMD, null);
}
// Handle optical media by size and filesystem
if (this.TotalSize >= 0 && this.TotalSize < 800_000_000 && this.DriveFormat == "CDFS")
return (MediaType.CDROM, null);
else if (this.TotalSize >= 0 && this.TotalSize < 400_000_000 && this.DriveFormat == "UDF")
return (MediaType.CDROM, null);
else if (this.TotalSize >= 800_000_000 && this.TotalSize <= 8_540_000_000 && this.DriveFormat == "CDFS")
return (MediaType.DVD, null);
else if (this.TotalSize >= 400_000_000 && this.TotalSize <= 8_540_000_000 && this.DriveFormat == "UDF")
return (MediaType.DVD, null);
else if (this.TotalSize > 8_540_000_000)
return (MediaType.BluRay, null);
return (null, "Could not determine media type!");
}
/// <summary>
/// Get the current system from drive
/// </summary>
/// <param name="defaultValue"></param>
/// <returns></returns>
public RedumpSystem? GetRedumpSystem(RedumpSystem? defaultValue)
{
string drivePath = $"{this.Letter}:\\";
// If we can't read the media in that drive, we can't do anything
if (!Directory.Exists(drivePath))
return defaultValue;
// We're going to assume for floppies, HDDs, and removable drives
// TODO: Try to be smarter about this
if (this.InternalDriveType != Data.InternalDriveType.Optical)
return RedumpSystem.IBMPCcompatible;
// Check volume labels first
RedumpSystem? systemFromLabel = GetRedumpSystemFromVolumeLabel();
if (systemFromLabel != null)
return systemFromLabel;
// Get a list of files for quicker checking
#region Consoles
// Bandai Playdia Quick Interactive System
try
{
List<string> files = Directory.EnumerateFiles(drivePath, "*", SearchOption.TopDirectoryOnly).ToList();
if (files.Any(f => f.EndsWith(".AJS", StringComparison.OrdinalIgnoreCase))
&& files.Any(f => f.EndsWith(".GLB", StringComparison.OrdinalIgnoreCase)))
{
return RedumpSystem.BandaiPlaydiaQuickInteractiveSystem;
}
}
catch { }
// Mattel Fisher-Price iXL
if (File.Exists(Path.Combine(drivePath, "iXL", "iXLUpdater.exe")))
{
return RedumpSystem.MattelFisherPriceiXL;
}
// Microsoft Xbox 360
try
{
if (Directory.Exists(Path.Combine(drivePath, "$SystemUpdate"))
&& Directory.EnumerateFiles(Path.Combine(drivePath, "$SystemUpdate")).Any()
&& this.TotalSize <= 500_000_000)
{
return RedumpSystem.MicrosoftXbox360;
}
}
catch { }
// Microsoft Xbox One
try
{
if (Directory.Exists(Path.Combine(drivePath, "MSXC"))
&& Directory.EnumerateFiles(Path.Combine(drivePath, "MSXC")).Any())
{
return RedumpSystem.MicrosoftXboxOne;
}
}
catch { }
// Sega Dreamcast
if (File.Exists(Path.Combine(drivePath, "IP.BIN")))
{
return RedumpSystem.SegaDreamcast;
}
// Sega Mega-CD / Sega-CD
if (File.Exists(Path.Combine(drivePath, "_BOOT", "IP.BIN"))
|| File.Exists(Path.Combine(drivePath, "_BOOT", "SP.BIN"))
|| File.Exists(Path.Combine(drivePath, "_BOOT", "SP_AS.BIN"))
|| File.Exists(Path.Combine(drivePath, "FILESYSTEM.BIN")))
{
return RedumpSystem.SegaMegaCDSegaCD;
}
// Sega Saturn
try
{
var sector = ReadSector(0);
if (sector != null)
{
if (sector.StartsWith(Interface.SaturnSectorZeroStart))
return RedumpSystem.SegaSaturn;
}
}
catch { }
// Sony PlayStation and Sony PlayStation 2
string psxExePath = Path.Combine(drivePath, "PSX.EXE");
string systemCnfPath = Path.Combine(drivePath, "SYSTEM.CNF");
if (File.Exists(systemCnfPath))
{
// Check for either BOOT or BOOT2
var systemCnf = new IniFile(systemCnfPath);
if (systemCnf.ContainsKey("BOOT"))
return RedumpSystem.SonyPlayStation;
else if (systemCnf.ContainsKey("BOOT2"))
return RedumpSystem.SonyPlayStation2;
}
else if (File.Exists(psxExePath))
{
return RedumpSystem.SonyPlayStation;
}
// Sony PlayStation 3
try
{
if (Directory.Exists(Path.Combine(drivePath, "PS3_GAME"))
|| Directory.Exists(Path.Combine(drivePath, "PS3_UPDATE"))
|| File.Exists(Path.Combine(drivePath, "PS3_DISC.SFB")))
{
return RedumpSystem.SonyPlayStation3;
}
}
catch { }
// Sony PlayStation 4
// There are more possible paths that could be checked.
// There are some entries that can be found on most PS4 discs:
// "/app/GAME_SERIAL/app.pkg"
// "/bd/param.sfo"
// "/license/rif"
// There are also extra files that can be found on some discs:
// "/patch/GAME_SERIAL/patch.pkg" can be found in Redump entry 66816.
// Originally on disc as "/patch/CUSA11302/patch.pkg".
// Is used as an on-disc update for the base game app without needing to get update from the internet.
// "/addcont/GAME_SERIAL/CONTENT_ID/ac.pkg" can be found in Redump entry 97619.
// Originally on disc as "/addcont/CUSA00288/FFXIVEXPS400001A/ac.pkg".
if (File.Exists(Path.Combine(drivePath, "PS4", "UPDATE", "PS4UPDATE.PUP")))
{
return RedumpSystem.SonyPlayStation4;
}
// V.Tech V.Flash / V.Smile Pro
if (File.Exists(Path.Combine(drivePath, "0SYSTEM")))
{
return RedumpSystem.VTechVFlashVSmilePro;
}
#endregion
#region Computers
// Sharp X68000
if (File.Exists(Path.Combine(drivePath, "COMMAND.X")))
{
return RedumpSystem.SharpX68000;
}
#endregion
#region Video Formats
// BD-Video
if (Directory.Exists(Path.Combine(drivePath, "BDMV")))
{
// Technically BD-Audio has this as well, but it's hard to split that out right now
return RedumpSystem.BDVideo;
}
// DVD-Audio and DVD-Video
try
{
if (Directory.Exists(Path.Combine(drivePath, "AUDIO_TS"))
&& Directory.EnumerateFiles(Path.Combine(drivePath, "AUDIO_TS")).Any())
{
return RedumpSystem.DVDAudio;
}
else if (Directory.Exists(Path.Combine(drivePath, "VIDEO_TS"))
&& Directory.EnumerateFiles(Path.Combine(drivePath, "VIDEO_TS")).Any())
{
return RedumpSystem.DVDVideo;
}
}
catch { }
// HD-DVD-Video
try
{
if (Directory.Exists(Path.Combine(drivePath, "HVDVD_TS"))
&& Directory.EnumerateFiles(Path.Combine(drivePath, "HVDVD_TS")).Any())
{
return RedumpSystem.HDDVDVideo;
}
}
catch { }
// VCD
try
{
if (Directory.Exists(Path.Combine(drivePath, "VCD"))
&& Directory.EnumerateFiles(Path.Combine(drivePath, "VCD")).Any())
{
return RedumpSystem.VideoCD;
}
}
catch { }
#endregion
// Default return
return defaultValue;
}
/// <summary>
/// Get the current system from the drive volume label
/// </summary>
/// <returns>The system based on volume label, null if none detected</returns>
public RedumpSystem? GetRedumpSystemFromVolumeLabel()
{
// If the volume label is empty, we can't do anything
if (string.IsNullOrWhiteSpace(this.VolumeLabel))
return null;
// Audio CD
if (this.VolumeLabel.Equals("Audio CD", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.AudioCD;
// Microsoft Xbox
if (this.VolumeLabel.Equals("SEP13011042", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.MicrosoftXbox;
else if (this.VolumeLabel.Equals("SEP13011042072", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.MicrosoftXbox;
// Microsoft Xbox 360
if (this.VolumeLabel.Equals("XBOX360", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.MicrosoftXbox360;
else if (this.VolumeLabel.Equals("XGD2DVD_NTSC", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.MicrosoftXbox360;
// Microsoft Xbox 360 - Too overly broad even if a lot of discs use this
//if (this.VolumeLabel.Equals("CD_ROM", StringComparison.OrdinalIgnoreCase))
// return RedumpSystem.MicrosoftXbox360; // Also for Xbox One?
//if (this.VolumeLabel.Equals("DVD_ROM", StringComparison.OrdinalIgnoreCase))
// return RedumpSystem.MicrosoftXbox360;
// Sega Mega-CD / Sega-CD
if (this.VolumeLabel.Equals("Sega_CD", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.SegaMegaCDSegaCD;
// Sony PlayStation 3
if (this.VolumeLabel.Equals("PS3VOLUME", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.SonyPlayStation3;
// Sony PlayStation 4
if (this.VolumeLabel.Equals("PS4VOLUME", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.SonyPlayStation4;
// Sony PlayStation 5
if (this.VolumeLabel.Equals("PS5VOLUME", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.SonyPlayStation5;
return null;
}
/// <summary>
/// Read a sector with a specified size from the drive
/// </summary>
/// <param name="num">Sector number, non-negative</param>
/// <param name="size">Size of a sector in bytes</param>
/// <returns>Byte array representing the sector, null on error</returns>
#if NET48
public byte[] ReadSector(long num, int size = 2048)
#else
public byte[]? ReadSector(long num, int size = 2048)
#endif
{
// Missing drive leter is not supported
if (string.IsNullOrEmpty(this.Name))
return null;
// We don't support negative sectors
if (num < 0)
return null;
// Wrap the following in case of device access errors
#if NET48
Stream fs = null;
#else
Stream? fs = null;
#endif
try
{
// Open the drive as a device
fs = File.OpenRead($"\\\\?\\{this.Letter}:");
// Seek to the start of the sector, if possible
long start = num * size;
fs.Seek(start, SeekOrigin.Begin);
// Read and return the sector
byte[] buffer = new byte[size];
fs.Read(buffer, 0, size);
return buffer;
}
catch
{
return null;
}
finally
{
fs?.Dispose();
}
}
/// <summary>
/// Refresh the current drive information based on path
/// </summary>
public void RefreshDrive()
{
var driveInfo = DriveInfo.GetDrives().FirstOrDefault(d => d?.Name == this.Name);
this.PopulateFromDriveInfo(driveInfo);
}
#endregion
#region Helpers
/// <summary>
/// Get all current attached Drives
/// </summary>
/// <param name="ignoreFixedDrives">True to ignore fixed drives from population, false otherwise</param>
/// <returns>List of drives, null on error</returns>
/// <remarks>
/// https://stackoverflow.com/questions/3060796/how-to-distinguish-between-usb-and-floppy-devices?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
/// https://msdn.microsoft.com/en-us/library/aa394173(v=vs.85).aspx
/// </remarks>
private static List<Drive> GetDriveList(bool ignoreFixedDrives)
{
var desiredDriveTypes = new List<DriveType>() { DriveType.CDRom };
if (!ignoreFixedDrives)
{
desiredDriveTypes.Add(DriveType.Fixed);
desiredDriveTypes.Add(DriveType.Removable);
}
// TODO: Reduce reliance on `DriveInfo`
// https://github.com/aaru-dps/Aaru/blob/5164a154e2145941472f2ee0aeb2eff3338ecbb3/Aaru.Devices/Windows/ListDevices.cs#L66
// Create an output drive list
var drives = new List<Drive>();
// Get all standard supported drive types
try
{
drives = DriveInfo.GetDrives()
.Where(d => desiredDriveTypes.Contains(d.DriveType))
.Select(d => Create(EnumConverter.ToInternalDriveType(d.DriveType), d.Name) ?? new Drive())
.ToList();
}
catch
{
return drives;
}
// Find and update all floppy drives
try
{
CimSession session = CimSession.Create(null);
var collection = session.QueryInstances("root\\CIMV2", "WQL", "SELECT * FROM Win32_LogicalDisk");
foreach (CimInstance instance in collection)
{
CimKeyedCollection<CimProperty> properties = instance.CimInstanceProperties;
uint? mediaType = properties["MediaType"]?.Value as uint?;
if (mediaType != null && ((mediaType > 0 && mediaType < 11) || (mediaType > 12 && mediaType < 22)))
{
char devId = (properties["Caption"].Value as string ?? string.Empty)[0];
drives.ForEach(d => { if (d?.Letter == devId) { d.InternalDriveType = Data.InternalDriveType.Floppy; } });
}
}
}
catch
{
// No-op
}
return drives;
}
#endregion
}
}

View File

@@ -1,42 +0,0 @@
namespace MPF.Core.Data
{
/// <summary>
/// Drive type for dumping
/// </summary>
public enum InternalDriveType
{
Optical,
Floppy,
HardDisk,
Removable,
}
/// <summary>
/// Program that is being used to dump media
/// </summary>
public enum InternalProgram
{
NONE = 0,
// Dumping support
Aaru,
DiscImageCreator,
Redumper,
// Verification support only
CleanRip,
DCDumper,
UmdImageCreator,
}
/// <summary>
/// Log level for output
/// </summary>
public enum LogLevel
{
USER,
VERBOSE,
ERROR,
SECRET,
}
}

View File

@@ -1,304 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace MPF.Core.Data
{
public class IniFile : IDictionary<string, string>
{
private Dictionary<string, string> _keyValuePairs = new Dictionary<string, string>();
public string this[string key]
{
get
{
if (_keyValuePairs == null)
_keyValuePairs = new Dictionary<string, string>();
key = key.ToLowerInvariant();
if (_keyValuePairs.ContainsKey(key))
return _keyValuePairs[key];
return string.Empty;
}
set
{
if (_keyValuePairs == null)
_keyValuePairs = new Dictionary<string, string>();
key = key.ToLowerInvariant();
_keyValuePairs[key] = value;
}
}
/// <summary>
/// Create an empty INI file
/// </summary>
public IniFile()
{
}
/// <summary>
/// Populate an INI file from path
/// </summary>
public IniFile(string path)
{
this.Parse(path);
}
/// <summary>
/// Populate an INI file from stream
/// </summary>
public IniFile(Stream stream)
{
this.Parse(stream);
}
/// <summary>
/// Add or update a key and value to the INI file
/// </summary>
public void AddOrUpdate(string key, string value)
{
_keyValuePairs[key.ToLowerInvariant()] = value;
}
/// <summary>
/// Remove a key from the INI file
/// </summary>
public void Remove(string key)
{
_keyValuePairs.Remove(key.ToLowerInvariant());
}
/// <summary>
/// Read an INI file based on the path
/// </summary>
public bool Parse(string path)
{
// If we don't have a file, we can't read it
if (!File.Exists(path))
return false;
using (var fileStream = File.OpenRead(path))
{
return Parse(fileStream);
}
}
/// <summary>
/// Read an INI file from a stream
/// </summary>
public bool Parse(Stream stream)
{
// If the stream is invalid or unreadable, we can't process it
if (stream == null || !stream.CanRead || stream.Position >= stream.Length - 1)
return false;
// Keys are case-insensitive by default
try
{
using (StreamReader sr = new StreamReader(stream))
{
string section = string.Empty;
while (!sr.EndOfStream)
{
var line = sr.ReadLine()?.Trim();
// Empty lines are skipped
if (string.IsNullOrWhiteSpace(line))
{
// No-op, we don't process empty lines
}
// Comments start with ';'
else if (line.StartsWith(";"))
{
// No-op, we don't process comments
}
// Section titles are surrounded by square brackets
else if (line.StartsWith("["))
{
section = line.TrimStart('[').TrimEnd(']');
}
// Valid INI lines are in the format key=value
else if (line.Contains("="))
{
// Split the line by '=' for key-value pairs
string[] data = line.Split('=');
// If the value field contains an '=', we need to put them back in
string key = data[0].Trim();
string value = string.Join("=", data.Skip(1)).Trim();
// Section names are prepended to the key with a '.' separating
if (!string.IsNullOrEmpty(section))
key = $"{section}.{key}";
// Set or overwrite keys in the returned dictionary
_keyValuePairs[key.ToLowerInvariant()] = value;
}
// All other lines are ignored
}
}
}
catch
{
// We don't care what the error was, just catch and return
return false;
}
return true;
}
/// <summary>
/// Write an INI file to a path
/// </summary>
public bool Write(string path)
{
// If we don't have a valid dictionary with values, we can't write out
if (_keyValuePairs == null || _keyValuePairs.Count == 0)
return false;
using (var fileStream = File.OpenWrite(path))
{
return Write(fileStream);
}
}
/// <summary>
/// Write an INI file to a stream
/// </summary>
public bool Write(Stream stream)
{
// If we don't have a valid dictionary with values, we can't write out
if (_keyValuePairs == null || _keyValuePairs.Count == 0)
return false;
// If the stream is invalid or unwritable, we can't output to it
if (stream == null || !stream.CanWrite || stream.Position >= stream.Length - 1)
return false;
try
{
using (StreamWriter sw = new StreamWriter(stream))
{
// Order the dictionary by keys to link sections together
var orderedKeyValuePairs = _keyValuePairs.OrderBy(kvp => kvp.Key);
string section = string.Empty;
foreach (var keyValuePair in orderedKeyValuePairs)
{
// Extract the key and value
string key = keyValuePair.Key;
string value = keyValuePair.Value;
// We assume '.' is a section name separator
if (key.Contains('.'))
{
// Split the key by '.'
string[] data = keyValuePair.Key.Split('.');
// If the key contains an '.', we need to put them back in
string newSection = data[0].Trim();
key = string.Join(".", data.Skip(1)).Trim();
// If we have a new section, write it out
if (!string.Equals(newSection, section, StringComparison.OrdinalIgnoreCase))
{
sw.WriteLine($"[{newSection}]");
section = newSection;
}
}
// Now write out the key and value in a standardized way
sw.WriteLine($"{key}={value}");
}
}
}
catch
{
// We don't care what the error was, just catch and return
return false;
}
return true;
}
#region IDictionary Impelementations
public ICollection<string> Keys => ((IDictionary<string, string>)_keyValuePairs).Keys;
public ICollection<string> Values => ((IDictionary<string, string>)_keyValuePairs).Values;
public int Count => ((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Count;
public bool IsReadOnly => ((ICollection<KeyValuePair<string, string>>)_keyValuePairs).IsReadOnly;
public void Add(string key, string value)
{
((IDictionary<string, string>)_keyValuePairs).Add(key.ToLowerInvariant(), value);
}
bool IDictionary<string, string>.Remove(string key)
{
return ((IDictionary<string, string>)_keyValuePairs).Remove(key.ToLowerInvariant());
}
public bool TryGetValue(string key, out string value)
{
bool result = ((IDictionary<string, string>)_keyValuePairs).TryGetValue(key.ToLowerInvariant(), out var temp);
value = temp ?? string.Empty;
return result;
}
public void Add(KeyValuePair<string, string> item)
{
var newItem = new KeyValuePair<string, string>(item.Key.ToLowerInvariant(), item.Value);
((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Add(newItem);
}
public void Clear()
{
((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Clear();
}
public bool Contains(KeyValuePair<string, string> item)
{
var newItem = new KeyValuePair<string, string>(item.Key.ToLowerInvariant(), item.Value);
return ((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Contains(newItem);
}
public bool ContainsKey(string key)
{
return _keyValuePairs.ContainsKey(key.ToLowerInvariant());
}
public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex)
{
((ICollection<KeyValuePair<string, string>>)_keyValuePairs).CopyTo(array, arrayIndex);
}
public bool Remove(KeyValuePair<string, string> item)
{
var newItem = new KeyValuePair<string, string>(item.Key.ToLowerInvariant(), item.Value);
return ((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Remove(newItem);
}
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
{
return ((IEnumerable<KeyValuePair<string, string>>)_keyValuePairs).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_keyValuePairs).GetEnumerator();
}
#endregion
}
}

View File

@@ -1,75 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
namespace MPF.Core.Data
{
public class ProcessingQueue<T> : IDisposable
{
/// <summary>
/// Internal queue to hold data to process
/// </summary>
private readonly ConcurrentQueue<T> InternalQueue;
/// <summary>
/// Custom processing step for dequeued data
/// </summary>
private readonly Action<T> CustomProcessing;
/// <summary>
/// Cancellation method for the processing task
/// </summary>
private readonly CancellationTokenSource TokenSource;
public ProcessingQueue(Action<T> customProcessing)
{
this.InternalQueue = new ConcurrentQueue<T>();
this.CustomProcessing = customProcessing;
this.TokenSource = new CancellationTokenSource();
Task.Run(() => ProcessQueue(), this.TokenSource.Token);
}
/// <summary>
/// Dispose the current instance
/// </summary>
public void Dispose() => this.TokenSource.Cancel();
/// <summary>
/// Enqueue a new item for processing
/// </summary>
/// <param name="item"></param>
public void Enqueue(T item)
{
// Only accept new data when not cancelled
if (item != null && !this.TokenSource.IsCancellationRequested)
this.InternalQueue.Enqueue(item);
}
/// <summary>
/// Process
/// </summary>
private void ProcessQueue()
{
while (true)
{
// Nothing in the queue means we get to idle
if (this.InternalQueue.Count == 0)
{
if (this.TokenSource.IsCancellationRequested)
break;
Thread.Sleep(10);
continue;
}
// Get the next item from the queue
if (!this.InternalQueue.TryDequeue(out var nextItem))
continue;
// Invoke the lambda, if possible
this.CustomProcessing?.Invoke(nextItem);
}
}
}
}

View File

@@ -1,60 +0,0 @@
namespace MPF.Core.Data
{
/// <summary>
/// Generic success/failure result object, with optional message
/// </summary>
public class Result
{
/// <summary>
/// Internal representation of success
/// </summary>
private readonly bool success;
/// <summary>
/// Optional message for the result
/// </summary>
public string Message { get; private set; }
private Result(bool success, string message)
{
this.success = success;
this.Message = message;
}
/// <summary>
/// Create a default success result with no message
/// </summary>
public static Result Success() => new Result(true, "");
/// <summary>
/// Create a success result with a custom message
/// </summary>
/// <param name="message">String to add as a message</param>
#if NET48
public static Result Success(string message) => new Result(true, message);
#else
public static Result Success(string? message) => new Result(true, message ?? string.Empty);
#endif
/// <summary>
/// Create a default failure result with no message
/// </summary>
/// <returns></returns>
public static Result Failure() => new Result(false, "");
/// <summary>
/// Create a failure result with a custom message
/// </summary>
/// <param name="message">String to add as a message</param>
#if NET48
public static Result Failure(string message) => new Result(false, message);
#else
public static Result Failure(string? message) => new Result(false, message ?? string.Empty);
#endif
/// <summary>
/// Results can be compared to boolean values based on the success value
/// </summary>
public static implicit operator bool(Result result) => result.success;
}
}

View File

@@ -1,200 +0,0 @@
using SabreTools.RedumpLib.Data;
namespace MPF.Core.Data
{
/// <summary>
/// Contains information specific to an XGD disc
/// </summary>
public class XgdInfo
{
#region Fields
/// <summary>
/// Indicates whether the information in this object is fully instantiated or not
/// </summary>
public bool Initialized { get; private set; }
/// <summary>
/// Raw XMID/XeMID string that all other information is derived from
/// </summary>
#if NET48
public string RawXMID { get; private set; }
#else
public string? RawXMID { get; private set; }
#endif
/// <summary>
/// XGD1 XMID
/// </summary>
#if NET48
public SabreTools.Models.Xbox.XMID XMID { get; private set; }
#else
public SabreTools.Models.Xbox.XMID? XMID { get; private set; }
#endif
/// <summary>
/// XGD2/3 XeMID
/// </summary>
#if NET48
public SabreTools.Models.Xbox.XeMID XeMID { get; private set; }
#else
public SabreTools.Models.Xbox.XeMID? XeMID { get; private set; }
#endif
#endregion
/// <summary>
/// Populate a set of XGD information from a Master ID (XMID/XeMID) string
/// </summary>
/// <param name="xmid">XMID/XeMID string representing the DMI information</param>
public XgdInfo(string xmid)
{
this.Initialized = false;
if (string.IsNullOrWhiteSpace(xmid))
return;
this.RawXMID = xmid.TrimEnd('\0');
if (string.IsNullOrWhiteSpace(this.RawXMID))
return;
// XGD1 information is 8 characters
if (this.RawXMID.Length == 8)
this.Initialized = ParseXGD1XMID(this.RawXMID);
// XGD2/3 information is semi-variable length
else if (this.RawXMID.Length == 13 || this.RawXMID.Length == 14 || this.RawXMID.Length == 21 || this.RawXMID.Length == 22)
this.Initialized = ParseXGD23XeMID(this.RawXMID);
}
/// <summary>
/// Get the human-readable serial string
/// </summary>
/// <returns>Formatted serial string, null on error</returns>
#if NET48
public string GetSerial()
#else
public string? GetSerial()
#endif
{
if (!this.Initialized)
return null;
try
{
// XGD1 doesn't use PlatformIdentifier
if (XMID != null)
return $"{XMID.PublisherIdentifier}-{XMID.GameID}";
// XGD2/3 uses a specific identifier
else if (XeMID?.PlatformIdentifier == '2')
return $"{XeMID.PublisherIdentifier}-{XeMID.PlatformIdentifier}{XeMID.GameID}";
return null;
}
catch
{
return null;
}
}
/// <summary>
/// Get the human-readable version string
/// </summary>
/// <returns>Formatted version string, null on error</returns>
/// <remarks>This may differ for XGD2/3 in the future</remarks>
#if NET48
public string GetVersion()
#else
public string? GetVersion()
#endif
{
if (!this.Initialized)
return null;
try
{
// XGD1 doesn't use PlatformIdentifier
if (XMID != null)
return $"1.{XMID.VersionNumber}";
// XGD2/3 uses a specific identifier
else if (XeMID?.PlatformIdentifier == '2')
return $"1.{XeMID.SKU}";
return null;
}
catch
{
return null;
}
}
/// <summary>
/// Parse an XGD1 XMID string
/// </summary>
/// <param name="rawXmid">XMID string to attempt to parse</param>
/// <returns>True if the XMID could be parsed, false otherwise</returns>
private bool ParseXGD1XMID(string rawXmid)
{
try
{
var xmid = new SabreTools.Serialization.Files.XMID().Deserialize(rawXmid);
if (xmid == null)
return false;
this.XMID = xmid;
return true;
}
catch
{
return false;
}
}
/// <summary>
/// Parse an XGD2/3 XeMID string
/// </summary>
/// <param name="rawXemid">XeMID string to attempt to parse</param>
/// <returns>True if the XeMID could be parsed, false otherwise</returns>
private bool ParseXGD23XeMID(string rawXemid)
{
try
{
var xemid = new SabreTools.Serialization.Files.XeMID().Deserialize(rawXemid);
if (xemid == null)
return false;
this.XeMID = xemid;
return true;
}
catch
{
return false;
}
}
#region Helpers
/// <summary>
/// Determine the region based on the XGD serial character
/// </summary>
/// <param name="region">Character denoting the region</param>
/// <returns>Region, if possible</returns>
public static Region? GetRegion(char? region)
{
switch (region)
{
case 'W': return Region.World;
case 'A': return Region.UnitedStatesOfAmerica;
case 'J': return Region.JapanAsia;
case 'E': return Region.Europe;
case 'K': return Region.USAJapan;
case 'L': return Region.USAEurope;
case 'H': return Region.JapanEurope;
default: return null;
}
}
#endregion
}
}

View File

@@ -1,737 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using BurnOutSharp;
using MPF.Core.Data;
using MPF.Core.Utilities;
using MPF.Core.Modules;
using SabreTools.RedumpLib.Data;
namespace MPF.Core
{
/// <summary>
/// Represents the state of all settings to be used during dumping
/// </summary>
public class DumpEnvironment
{
#region Output paths
/// <summary>
/// Base output file path to write files to
/// </summary>
public string OutputPath { get; private set; }
#endregion
#region UI information
/// <summary>
/// Drive object representing the current drive
/// </summary>
#if NET48
public Drive Drive { get; private set; }
#else
public Drive? Drive { get; private set; }
#endif
/// <summary>
/// Currently selected system
/// </summary>
public RedumpSystem? System { get; private set; }
/// <summary>
/// Currently selected media type
/// </summary>
public MediaType? Type { get; private set; }
/// <summary>
/// Currently selected dumping program
/// </summary>
public InternalProgram InternalProgram { get; private set; }
/// <summary>
/// Options object representing user-defined options
/// </summary>
public Data.Options Options { get; private set; }
/// <summary>
/// Parameters object representing what to send to the internal program
/// </summary>
#if NET48
public BaseParameters Parameters { get; private set; }
#else
public BaseParameters? Parameters { get; private set; }
#endif
#endregion
#region Event Handlers
/// <summary>
/// Generic way of reporting a message
/// </summary>
#if NET48
public EventHandler<string> ReportStatus;
#else
public EventHandler<string>? ReportStatus;
#endif
/// <summary>
/// Queue of items that need to be logged
/// </summary>
#if NET48
private ProcessingQueue<string> outputQueue;
#else
private ProcessingQueue<string>? outputQueue;
#endif
/// <summary>
/// Event handler for data returned from a process
/// </summary>
#if NET48
private void OutputToLog(object proc, string args) => outputQueue?.Enqueue(args);
#else
private void OutputToLog(object? proc, string args) => outputQueue?.Enqueue(args);
#endif
/// <summary>
/// Process the outputs in the queue
/// </summary>
private void ProcessOutputs(string nextOutput) => ReportStatus?.Invoke(this, nextOutput);
#endregion
/// <summary>
/// Constructor for a full DumpEnvironment object from user information
/// </summary>
/// <param name="options"></param>
/// <param name="outputPath"></param>
/// <param name="drive"></param>
/// <param name="system"></param>
/// <param name="type"></param>
/// <param name="internalProgram"></param>
/// <param name="parameters"></param>
public DumpEnvironment(Data.Options options,
string outputPath,
#if NET48
Drive drive,
#else
Drive? drive,
#endif
RedumpSystem? system,
MediaType? type,
InternalProgram? internalProgram,
#if NET48
string parameters)
#else
string? parameters)
#endif
{
// Set options object
this.Options = options;
// Output paths
this.OutputPath = InfoTool.NormalizeOutputPaths(outputPath, true);
// UI information
this.Drive = drive;
this.System = system ?? options.DefaultSystem;
this.Type = type ?? MediaType.NONE;
this.InternalProgram = internalProgram ?? options.InternalProgram;
// Dumping program
SetParameters(parameters);
}
#region Public Functionality
/// <summary>
/// Adjust output paths if we're using DiscImageCreator
/// </summary>
public void AdjustPathsForDiscImageCreator()
{
// Only DiscImageCreator has issues with paths
if (this.Parameters?.InternalProgram != InternalProgram.DiscImageCreator)
return;
try
{
// Normalize the output path
string outputPath = InfoTool.NormalizeOutputPaths(this.OutputPath, true);
// Replace all instances in the output directory
var outputDirectory = Path.GetDirectoryName(outputPath);
outputDirectory = outputDirectory?.Replace(".", "_");
// Replace all instances in the output filename
string outputFilename = Path.GetFileNameWithoutExtension(outputPath);
outputFilename = outputFilename.Replace(".", "_");
// Get the extension for recreating the path
string outputExtension = Path.GetExtension(outputPath).TrimStart('.');
// Rebuild the output path
if (string.IsNullOrWhiteSpace(outputDirectory))
{
if (string.IsNullOrWhiteSpace(outputExtension))
this.OutputPath = outputFilename;
else
this.OutputPath = $"{outputFilename}.{outputExtension}";
}
else
{
if (string.IsNullOrWhiteSpace(outputExtension))
this.OutputPath = Path.Combine(outputDirectory, outputFilename);
else
this.OutputPath = Path.Combine(outputDirectory, $"{outputFilename}.{outputExtension}");
}
// Assign the path to the filename as well for dumping
((Modules.DiscImageCreator.Parameters)this.Parameters).Filename = this.OutputPath;
}
catch { }
}
/// <summary>
/// Set the parameters object based on the internal program and parameters string
/// </summary>
/// <param name="parameters">String representation of the parameters</param>
#if NET48
public void SetParameters(string parameters)
#else
public void SetParameters(string? parameters)
#endif
{
switch (this.InternalProgram)
{
// Dumping support
case InternalProgram.Aaru:
this.Parameters = new Modules.Aaru.Parameters(parameters) { ExecutablePath = Options.AaruPath };
break;
case InternalProgram.DiscImageCreator:
this.Parameters = new Modules.DiscImageCreator.Parameters(parameters) { ExecutablePath = Options.DiscImageCreatorPath };
break;
case InternalProgram.Redumper:
this.Parameters = new Modules.Redumper.Parameters(parameters) { ExecutablePath = Options.RedumperPath };
break;
// Verification support only
case InternalProgram.CleanRip:
this.Parameters = new Modules.CleanRip.Parameters(parameters) { ExecutablePath = null };
break;
case InternalProgram.DCDumper:
this.Parameters = null; // TODO: Create correct parameter type when supported
break;
case InternalProgram.UmdImageCreator:
this.Parameters = new Modules.UmdImageCreator.Parameters(parameters) { ExecutablePath = null };
break;
// This should never happen, but it needs a fallback
default:
this.Parameters = new Modules.DiscImageCreator.Parameters(parameters) { ExecutablePath = Options.DiscImageCreatorPath };
break;
}
// Set system and type
if (this.Parameters != null)
{
this.Parameters.System = this.System;
this.Parameters.Type = this.Type;
}
}
/// <summary>
/// Get the full parameter string for either DiscImageCreator or Aaru
/// </summary>
/// <param name="driveSpeed">Nullable int representing the drive speed</param>
/// <returns>String representing the params, null on error</returns>
#if NET48
public string GetFullParameters(int? driveSpeed)
#else
public string? GetFullParameters(int? driveSpeed)
#endif
{
// Populate with the correct params for inputs (if we're not on the default option)
if (System != null && Type != MediaType.NONE)
{
// If drive letter is invalid, skip this
if (Drive == null)
return null;
// Set the proper parameters
switch (this.InternalProgram)
{
case InternalProgram.Aaru:
Parameters = new Modules.Aaru.Parameters(System, Type, Drive.Letter, this.OutputPath, driveSpeed, Options);
break;
case InternalProgram.DiscImageCreator:
Parameters = new Modules.DiscImageCreator.Parameters(System, Type, Drive.Letter, this.OutputPath, driveSpeed, Options);
break;
case InternalProgram.Redumper:
Parameters = new Modules.Redumper.Parameters(System, Type, Drive.Letter, this.OutputPath, driveSpeed, Options);
break;
// This should never happen, but it needs a fallback
default:
Parameters = new Modules.DiscImageCreator.Parameters(System, Type, Drive.Letter, this.OutputPath, driveSpeed, Options);
break;
}
// Generate and return the param string
return Parameters.GenerateParameters();
}
return null;
}
#endregion
#region Dumping
/// <summary>
/// Cancel an in-progress dumping process
/// </summary>
public void CancelDumping() => Parameters?.KillInternalProgram();
/// <summary>
/// Eject the disc using DiscImageCreator
/// </summary>
#if NET48
public async Task<string> EjectDisc() =>
#else
public async Task<string?> EjectDisc() =>
#endif
await RunStandaloneDiscImageCreatorCommand(Modules.DiscImageCreator.CommandStrings.Eject);
/// <summary>
/// Reset the current drive using DiscImageCreator
/// </summary>
#if NET48
public async Task<string> ResetDrive() =>
#else
public async Task<string?> ResetDrive() =>
#endif
await RunStandaloneDiscImageCreatorCommand(Modules.DiscImageCreator.CommandStrings.Reset);
/// <summary>
/// Execute the initial invocation of the dumping programs
/// </summary>
/// <param name="progress">Optional result progress callback</param>
#if NET48
public async Task<Result> Run(IProgress<Result> progress = null)
#else
public async Task<Result> Run(IProgress<Result>? progress = null)
#endif
{
// If we don't have parameters
if (this.Parameters == null)
return Result.Failure("Error! Current configuration is not supported!");
// Check that we have the basics for dumping
Result result = IsValidForDump();
if (!result)
return result;
// Invoke output processing, if needed
if (!Options.ToolsInSeparateWindow)
{
outputQueue = new ProcessingQueue<string>(ProcessOutputs);
if (Parameters.ReportStatus != null)
Parameters.ReportStatus += OutputToLog;
}
// Execute internal tool
progress?.Report(Result.Success($"Executing {this.InternalProgram}... {(Options.ToolsInSeparateWindow ? "please wait!" : "see log for output!")}"));
var directoryName = Path.GetDirectoryName(this.OutputPath);
if (!string.IsNullOrWhiteSpace(directoryName))
Directory.CreateDirectory(directoryName);
await Task.Run(() => Parameters.ExecuteInternalProgram(Options.ToolsInSeparateWindow));
progress?.Report(Result.Success($"{this.InternalProgram} has finished!"));
// Execute additional tools
progress?.Report(Result.Success("Running any additional tools... see log for output!"));
result = await Task.Run(() => ExecuteAdditionalTools());
progress?.Report(result);
// Remove event handler if needed
if (!Options.ToolsInSeparateWindow)
{
outputQueue?.Dispose();
Parameters.ReportStatus -= OutputToLog;
}
return result;
}
/// <summary>
/// Verify that the current environment has a complete dump and create submission info is possible
/// </summary>
/// <param name="resultProgress">Optional result progress callback</param>
/// <param name="protectionProgress">Optional protection progress callback</param>
/// <param name="processUserInfo">Optional user prompt to deal with submission information</param>
/// <param name="seedInfo">A seed SubmissionInfo object that contains user data</param>
/// <returns>Result instance with the outcome</returns>
public async Task<Result> VerifyAndSaveDumpOutput(
#if NET48
IProgress<Result> resultProgress = null,
IProgress<ProtectionProgress> protectionProgress = null,
Func<SubmissionInfo, (bool?, SubmissionInfo)> processUserInfo = null,
SubmissionInfo seedInfo = null)
#else
IProgress<Result>? resultProgress = null,
IProgress<ProtectionProgress>? protectionProgress = null,
Func<SubmissionInfo?, (bool?, SubmissionInfo?)>? processUserInfo = null,
SubmissionInfo? seedInfo = null)
#endif
{
resultProgress?.Report(Result.Success("Gathering submission information... please wait!"));
// Get the output directory and filename separately
var outputDirectory = Path.GetDirectoryName(this.OutputPath);
var outputFilename = Path.GetFileName(this.OutputPath);
// Check to make sure that the output had all the correct files
(bool foundFiles, List<string> missingFiles) = InfoTool.FoundAllFiles(outputDirectory, outputFilename, this.Parameters, false);
if (!foundFiles)
{
resultProgress?.Report(Result.Failure($"There were files missing from the output:\n{string.Join("\n", missingFiles)}"));
return Result.Failure("Error! Please check output directory as dump may be incomplete!");
}
// Extract the information from the output files
resultProgress?.Report(Result.Success("Extracting output information from output files..."));
var submissionInfo = await InfoTool.ExtractOutputInformation(
this.OutputPath,
this.Drive,
this.System,
this.Type,
this.Options,
this.Parameters,
resultProgress,
protectionProgress);
resultProgress?.Report(Result.Success("Extracting information complete!"));
// Inject seed submission info data, if necessary
if (seedInfo != null)
{
resultProgress?.Report(Result.Success("Injecting user-supplied information..."));
InjectSubmissionInformation(submissionInfo, seedInfo);
resultProgress?.Report(Result.Success("Information injection complete!"));
}
// Eject the disc automatically if configured to
if (Options.EjectAfterDump == true)
{
resultProgress?.Report(Result.Success($"Ejecting disc in drive {Drive?.Letter}"));
await EjectDisc();
}
// Reset the drive automatically if configured to
if (this.InternalProgram == InternalProgram.DiscImageCreator && Options.DICResetDriveAfterDump)
{
resultProgress?.Report(Result.Success($"Resetting drive {Drive?.Letter}"));
await ResetDrive();
}
// Get user-modifiable information if confugured to
if (Options.PromptForDiscInformation && processUserInfo != null)
{
resultProgress?.Report(Result.Success("Waiting for additional disc information..."));
bool? filledInfo;
(filledInfo, submissionInfo) = processUserInfo(submissionInfo);
if (filledInfo == true)
resultProgress?.Report(Result.Success("Additional disc information added!"));
else
resultProgress?.Report(Result.Success("Disc information skipped!"));
}
// Process special fields for site codes
resultProgress?.Report(Result.Success("Processing site codes..."));
InfoTool.ProcessSpecialFields(submissionInfo);
resultProgress?.Report(Result.Success("Processing complete!"));
// Format the information for the text output
resultProgress?.Report(Result.Success("Formatting information..."));
(var formattedValues, var formatResult) = InfoTool.FormatOutputData(submissionInfo, this.Options);
if (formattedValues == null)
resultProgress?.Report(Result.Success(formatResult));
else
resultProgress?.Report(Result.Failure(formatResult));
// Write the text output
resultProgress?.Report(Result.Success("Writing information to !submissionInfo.txt..."));
(bool txtSuccess, string txtResult) = InfoTool.WriteOutputData(outputDirectory, formattedValues);
if (txtSuccess)
resultProgress?.Report(Result.Success(txtResult));
else
resultProgress?.Report(Result.Failure(txtResult));
// Write the copy protection output
if (Options.ScanForProtection && Options.OutputSeparateProtectionFile)
{
resultProgress?.Report(Result.Success("Writing protection to !protectionInfo.txt..."));
bool scanSuccess = InfoTool.WriteProtectionData(outputDirectory, submissionInfo);
if (scanSuccess)
resultProgress?.Report(Result.Success("Writing complete!"));
else
resultProgress?.Report(Result.Failure("Writing could not complete!"));
}
// Write the JSON output, if required
if (Options.OutputSubmissionJSON)
{
resultProgress?.Report(Result.Success($"Writing information to !submissionInfo.json{(Options.IncludeArtifacts ? ".gz" : string.Empty)}..."));
bool jsonSuccess = InfoTool.WriteOutputData(outputDirectory, submissionInfo, Options.IncludeArtifacts);
if (jsonSuccess)
resultProgress?.Report(Result.Success("Writing complete!"));
else
resultProgress?.Report(Result.Failure("Writing could not complete!"));
}
// Compress the logs, if required
if (Options.CompressLogFiles)
{
resultProgress?.Report(Result.Success("Compressing log files..."));
(bool compressSuccess, string compressResult) = InfoTool.CompressLogFiles(outputDirectory, outputFilename, this.Parameters);
if (compressSuccess)
resultProgress?.Report(Result.Success(compressResult));
else
resultProgress?.Report(Result.Failure(compressResult));
}
resultProgress?.Report(Result.Success("Submission information process complete!"));
return Result.Success();
}
/// <summary>
/// Checks if the parameters are valid
/// </summary>
/// <returns>True if the configuration is valid, false otherwise</returns>
internal bool ParametersValid()
{
// Missing drive means it can never be valid
if (Drive == null)
return false;
bool parametersValid = Parameters?.IsValid() ?? false;
bool floppyValid = !(Drive.InternalDriveType == InternalDriveType.Floppy ^ Type == MediaType.FloppyDisk);
// TODO: HardDisk being in the Removable category is a hack, fix this later
bool removableDiskValid = !((Drive.InternalDriveType == InternalDriveType.Removable || Drive.InternalDriveType == InternalDriveType.HardDisk)
^ (Type == MediaType.CompactFlash || Type == MediaType.SDCard || Type == MediaType.FlashDrive || Type == MediaType.HardDisk));
return parametersValid && floppyValid && removableDiskValid;
}
/// <summary>
/// Run any additional tools given a DumpEnvironment
/// </summary>
/// <returns>Result instance with the outcome</returns>
private Result ExecuteAdditionalTools() => Result.Success("No external tools needed!");
/// <summary>
/// Run internal program async with an input set of parameters
/// </summary>
/// <param name="parameters"></param>
/// <returns>Standard output from commandline window</returns>
private async Task<string> ExecuteInternalProgram(BaseParameters parameters)
{
Process childProcess;
string output = await Task.Run(() =>
{
childProcess = new Process()
{
StartInfo = new ProcessStartInfo()
{
FileName = parameters.ExecutablePath,
Arguments = parameters.GenerateParameters(),
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
},
};
childProcess.Start();
childProcess.WaitForExit(1000);
// Just in case, we want to push a button 5 times to clear any errors
for (int i = 0; i < 5; i++)
childProcess.StandardInput.WriteLine("Y");
string stdout = childProcess.StandardOutput.ReadToEnd();
childProcess.Dispose();
return stdout;
});
return output;
}
/// <summary>
/// Inject information from a seed SubmissionInfo into the existing one
/// </summary>
/// <param name="info">Existing submission information</param>
/// <param name="seed">User-supplied submission information</param>
#if NET48
private void InjectSubmissionInformation(SubmissionInfo info, SubmissionInfo seed)
#else
private void InjectSubmissionInformation(SubmissionInfo? info, SubmissionInfo? seed)
#endif
{
// If we have any invalid info
if (info == null || seed == null)
return;
// Otherwise, inject information as necessary
if (seed.CommonDiscInfo != null)
{
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
// Info that only overwrites if supplied
if (!string.IsNullOrWhiteSpace(seed.CommonDiscInfo.Title)) info.CommonDiscInfo.Title = seed.CommonDiscInfo.Title;
if (!string.IsNullOrWhiteSpace(seed.CommonDiscInfo.ForeignTitleNonLatin)) info.CommonDiscInfo.ForeignTitleNonLatin = seed.CommonDiscInfo.ForeignTitleNonLatin;
if (!string.IsNullOrWhiteSpace(seed.CommonDiscInfo.DiscNumberLetter)) info.CommonDiscInfo.DiscNumberLetter = seed.CommonDiscInfo.DiscNumberLetter;
if (!string.IsNullOrWhiteSpace(seed.CommonDiscInfo.DiscTitle)) info.CommonDiscInfo.DiscTitle = seed.CommonDiscInfo.DiscTitle;
if (seed.CommonDiscInfo.Category != null) info.CommonDiscInfo.Category = seed.CommonDiscInfo.Category;
if (seed.CommonDiscInfo.Region != null) info.CommonDiscInfo.Region = seed.CommonDiscInfo.Region;
if (seed.CommonDiscInfo.Languages != null) info.CommonDiscInfo.Languages = seed.CommonDiscInfo.Languages;
if (seed.CommonDiscInfo.LanguageSelection != null) info.CommonDiscInfo.LanguageSelection = seed.CommonDiscInfo.LanguageSelection;
if (seed.CommonDiscInfo.Serial != null) info.CommonDiscInfo.Serial = seed.CommonDiscInfo.Serial;
if (!string.IsNullOrWhiteSpace(seed.CommonDiscInfo.Barcode)) info.CommonDiscInfo.Barcode = seed.CommonDiscInfo.Barcode;
if (!string.IsNullOrWhiteSpace(seed.CommonDiscInfo.Comments)) info.CommonDiscInfo.Comments = seed.CommonDiscInfo.Comments;
if (seed.CommonDiscInfo.CommentsSpecialFields != null) info.CommonDiscInfo.CommentsSpecialFields = seed.CommonDiscInfo.CommentsSpecialFields;
if (!string.IsNullOrWhiteSpace(seed.CommonDiscInfo.Contents)) info.CommonDiscInfo.Contents = seed.CommonDiscInfo.Contents;
if (seed.CommonDiscInfo.ContentsSpecialFields != null) info.CommonDiscInfo.ContentsSpecialFields = seed.CommonDiscInfo.ContentsSpecialFields;
// Info that always overwrites
info.CommonDiscInfo.Layer0MasteringRing = seed.CommonDiscInfo.Layer0MasteringRing;
info.CommonDiscInfo.Layer0MasteringSID = seed.CommonDiscInfo.Layer0MasteringSID;
info.CommonDiscInfo.Layer0ToolstampMasteringCode = seed.CommonDiscInfo.Layer0ToolstampMasteringCode;
info.CommonDiscInfo.Layer0MouldSID = seed.CommonDiscInfo.Layer0MouldSID;
info.CommonDiscInfo.Layer0AdditionalMould = seed.CommonDiscInfo.Layer0AdditionalMould;
info.CommonDiscInfo.Layer1MasteringRing = seed.CommonDiscInfo.Layer1MasteringRing;
info.CommonDiscInfo.Layer1MasteringSID = seed.CommonDiscInfo.Layer1MasteringSID;
info.CommonDiscInfo.Layer1ToolstampMasteringCode = seed.CommonDiscInfo.Layer1ToolstampMasteringCode;
info.CommonDiscInfo.Layer1MouldSID = seed.CommonDiscInfo.Layer1MouldSID;
info.CommonDiscInfo.Layer1AdditionalMould = seed.CommonDiscInfo.Layer1AdditionalMould;
info.CommonDiscInfo.Layer2MasteringRing = seed.CommonDiscInfo.Layer2MasteringRing;
info.CommonDiscInfo.Layer2MasteringSID = seed.CommonDiscInfo.Layer2MasteringSID;
info.CommonDiscInfo.Layer2ToolstampMasteringCode = seed.CommonDiscInfo.Layer2ToolstampMasteringCode;
info.CommonDiscInfo.Layer3MasteringRing = seed.CommonDiscInfo.Layer3MasteringRing;
info.CommonDiscInfo.Layer3MasteringSID = seed.CommonDiscInfo.Layer3MasteringSID;
info.CommonDiscInfo.Layer3ToolstampMasteringCode = seed.CommonDiscInfo.Layer3ToolstampMasteringCode;
}
if (seed.VersionAndEditions != null)
{
if (info.VersionAndEditions == null) info.VersionAndEditions = new VersionAndEditionsSection();
// Info that only overwrites if supplied
if (!string.IsNullOrWhiteSpace(seed.VersionAndEditions.Version)) info.VersionAndEditions.Version = seed.VersionAndEditions.Version;
if (!string.IsNullOrWhiteSpace(seed.VersionAndEditions.OtherEditions)) info.VersionAndEditions.OtherEditions = seed.VersionAndEditions.OtherEditions;
}
if (seed.CopyProtection != null)
{
if (info.CopyProtection == null) info.CopyProtection = new CopyProtectionSection();
// Info that only overwrites if supplied
if (!string.IsNullOrWhiteSpace(seed.CopyProtection.Protection)) info.CopyProtection.Protection = seed.CopyProtection.Protection;
}
}
/// <summary>
/// Validate the current environment is ready for a dump
/// </summary>
/// <returns>Result instance with the outcome</returns>
private Result IsValidForDump()
{
// Validate that everything is good
if (this.Parameters == null || !ParametersValid())
return Result.Failure("Error! Current configuration is not supported!");
// Fix the output paths, just in case
this.OutputPath = InfoTool.NormalizeOutputPaths(this.OutputPath, true);
// Validate that the output path isn't on the dumping drive
if (Drive != null && this.OutputPath[0] == Drive.Letter)
return Result.Failure("Error! Cannot output to same drive that is being dumped!");
// Validate that the required program exists
if (!File.Exists(Parameters.ExecutablePath))
return Result.Failure($"Error! {Parameters.ExecutablePath} does not exist!");
// Validate that the dumping drive doesn't contain the executable
string fullExecutablePath = Path.GetFullPath(Parameters.ExecutablePath);
if (Drive != null && fullExecutablePath[0] == Drive.Letter)
return Result.Failure("Error! Cannot dump same drive that executable resides on!");
// Validate that the current configuration is supported
return Tools.GetSupportStatus(System, Type);
}
/// <summary>
/// Validate that DIscImageCreator is able to be found
/// </summary>
/// <returns>True if DiscImageCreator is found properly, false otherwise</returns>
private bool RequiredProgramsExist()
{
// Validate that the path is configured
if (string.IsNullOrWhiteSpace(Options.DiscImageCreatorPath))
return false;
// Validate that the required program exists
if (!File.Exists(Options.DiscImageCreatorPath))
return false;
return true;
}
/// <summary>
/// Run a standalone DiscImageCreator command
/// </summary>
/// <param name="command">Command string to run</param>
/// <returns>The output of the command on success, null on error</returns>
#if NET48
private async Task<string> RunStandaloneDiscImageCreatorCommand(string command)
#else
private async Task<string?> RunStandaloneDiscImageCreatorCommand(string command)
#endif
{
// Validate that DiscImageCreator is all set
if (!RequiredProgramsExist())
return null;
// Validate we're not trying to eject a non-optical
if (Drive == null || Drive.InternalDriveType != InternalDriveType.Optical)
return null;
CancelDumping();
var parameters = new Modules.DiscImageCreator.Parameters(string.Empty)
{
BaseCommand = command,
DriveLetter = Drive.Letter.ToString(),
ExecutablePath = Options.DiscImageCreatorPath,
};
return await ExecuteInternalProgram(parameters);
}
#endregion
}
}

View File

@@ -1,198 +0,0 @@
using System;
using System.IO.Hashing;
using System.Linq;
using System.Security.Cryptography;
namespace MPF.Core.Hashing
{
/// <summary>
/// Available hashing types
/// </summary>
[Flags]
public enum Hash
{
CRC32 = 1 << 0,
MD5 = 1 << 1,
SHA1 = 1 << 2,
SHA256 = 1 << 3,
SHA384 = 1 << 4,
SHA512 = 1 << 5,
// Special combinations
Standard = CRC32 | MD5 | SHA1,
All = CRC32 | MD5 | SHA1 | SHA256 | SHA384 | SHA512,
}
/// <summary>
/// Async hashing class wraper
/// </summary>
public class Hasher
{
public Hash HashType { get; private set; }
#if NET48
private object _hasher;
#else
private object? _hasher;
#endif
public Hasher(Hash hashType)
{
this.HashType = hashType;
GetHasher();
}
/// <summary>
/// Generate the correct hashing class based on the hash type
/// </summary>
private void GetHasher()
{
switch (HashType)
{
case Hash.CRC32:
_hasher = new Crc32();
break;
case Hash.MD5:
_hasher = MD5.Create();
break;
case Hash.SHA1:
_hasher = SHA1.Create();
break;
case Hash.SHA256:
_hasher = SHA256.Create();
break;
case Hash.SHA384:
_hasher = SHA384.Create();
break;
case Hash.SHA512:
_hasher = SHA512.Create();
break;
}
}
public void Dispose()
{
if (_hasher is IDisposable disposable)
disposable.Dispose();
}
/// <summary>
/// Process a buffer of some length with the internal hash algorithm
/// </summary>
public void Process(byte[] buffer, int size)
{
switch (HashType)
{
case Hash.CRC32:
(_hasher as NonCryptographicHashAlgorithm)?.Append(buffer);
break;
case Hash.MD5:
case Hash.SHA1:
case Hash.SHA256:
case Hash.SHA384:
case Hash.SHA512:
(_hasher as HashAlgorithm)?.TransformBlock(buffer, 0, size, null, 0);
break;
}
}
/// <summary>
/// Finalize the internal hash algorigthm
/// </summary>
public void Terminate()
{
byte[] emptyBuffer = new byte[0];
switch (HashType)
{
case Hash.CRC32:
(_hasher as NonCryptographicHashAlgorithm)?.Append(emptyBuffer);
break;
case Hash.MD5:
case Hash.SHA1:
case Hash.SHA256:
case Hash.SHA384:
case Hash.SHA512:
(_hasher as HashAlgorithm)?.TransformFinalBlock(emptyBuffer, 0, 0);
break;
}
}
/// <summary>
/// Get internal hash as a byte array
/// </summary>
#if NET48
public byte[] GetHash()
#else
public byte[]? GetHash()
#endif
{
if (_hasher == null)
return null;
switch (HashType)
{
case Hash.CRC32:
return (_hasher as NonCryptographicHashAlgorithm)?.GetCurrentHash();
case Hash.MD5:
case Hash.SHA1:
case Hash.SHA256:
case Hash.SHA384:
case Hash.SHA512:
return (_hasher as HashAlgorithm)?.Hash;
}
return null;
}
/// <summary>
/// Get internal hash as a string
/// </summary>
#if NET48
public string GetHashString()
#else
public string? GetHashString()
#endif
{
var hash = GetHash();
if (hash == null)
return null;
return ByteArrayToString(hash);
}
/// <summary>
/// Convert a byte array to a hex string
/// </summary>
/// <param name="bytes">Byte array to convert</param>
/// <returns>Hex string representing the byte array</returns>
/// <link>http://stackoverflow.com/questions/311165/how-do-you-convert-byte-array-to-hexadecimal-string-and-vice-versa</link>
#if NET48
private static string ByteArrayToString(byte[] bytes)
#else
private static string? ByteArrayToString(byte[]? bytes)
#endif
{
// If we get null in, we send null out
if (bytes == null)
return null;
try
{
string hex = BitConverter.ToString(bytes);
return hex.Replace("-", string.Empty).ToLowerInvariant();
}
catch
{
return null;
}
}
}
}

View File

@@ -1,85 +0,0 @@
using System;
using System.IO;
using System.Threading;
//namespace Compress.ThreadReaders
namespace MPF.Core.Hashing
{
public class ThreadLoadBuffer : IDisposable
{
private readonly AutoResetEvent _waitEvent;
private readonly AutoResetEvent _outEvent;
private readonly Thread _tWorker;
#if NET48
private byte[] _buffer;
#else
private byte[]? _buffer;
#endif
private int _size;
private readonly Stream _ds;
private bool _finished;
public bool errorState;
public int SizeRead;
public ThreadLoadBuffer(Stream ds)
{
_waitEvent = new AutoResetEvent(false);
_outEvent = new AutoResetEvent(false);
_finished = false;
_ds = ds;
errorState = false;
_tWorker = new Thread(MainLoop);
_tWorker.Start();
}
public void Dispose()
{
_waitEvent.Close();
_outEvent.Close();
}
private void MainLoop()
{
while (true)
{
_waitEvent.WaitOne();
if (_finished)
{
break;
}
try
{
if (_buffer != null)
SizeRead = _ds.Read(_buffer, 0, _size);
}
catch (Exception)
{
errorState = true;
}
_outEvent.Set();
}
}
public void Trigger(byte[] buffer, int size)
{
_buffer = buffer;
_size = size;
_waitEvent.Set();
}
public void Wait()
{
_outEvent.WaitOne();
}
public void Finish()
{
_finished = true;
_waitEvent.Set();
_tWorker.Join();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,34 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;net6.0;net7.0</TargetFrameworks>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2023</Copyright>
<VersionPrefix>2.7.1</VersionPrefix>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)'!='net48'">
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<InternalsVisibleTo Include="MPF.Test" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="2.8.0" GeneratePathProperty="true">
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0-preview.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SabreTools.Models" Version="1.1.4" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.1.1" />
<PackageReference Include="SabreTools.Serialization" Version="1.1.6" />
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
<PackageReference Include="System.IO.Hashing" Version="7.0.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
</ItemGroup>
</Project>

View File

@@ -1,491 +0,0 @@
namespace MPF.Core.Modules.Aaru
{
/// <summary>
/// Top-level commands for Aaru
/// </summary>
public static class CommandStrings
{
public const string NONE = "";
// Archive Family
public const string ArchivePrefixShort = "arc";
public const string ArchivePrefixLong = "archive";
public const string ArchiveInfo = "info";
// Database Family
public const string DatabasePrefixShort = "db";
public const string DatabasePrefixLong = "database";
public const string DatabaseStats = "stats";
public const string DatabaseUpdate = "update";
// Device Family
public const string DevicePrefixShort = "dev";
public const string DevicePrefixLong = "device";
public const string DeviceInfo = "info";
public const string DeviceList = "list";
public const string DeviceReport = "report";
// Filesystem Family
public const string FilesystemPrefixShort = "fi";
public const string FilesystemPrefixShortAlt = "fs";
public const string FilesystemPrefixLong = "filesystem";
public const string FilesystemExtract = "extract";
public const string FilesystemInfo = "info";
public const string FilesystemListShort = "ls";
public const string FilesystemListLong = "list";
public const string FilesystemOptions = "options";
// Image Family
public const string ImagePrefixShort = "i";
public const string ImagePrefixLong = "image";
public const string ImageChecksumShort = "chk";
public const string ImageChecksumLong = "checksum";
public const string ImageCompareShort = "cmp";
public const string ImageCompareLong = "compare";
public const string ImageConvert = "convert";
public const string ImageCreateSidecar = "create-sidecar";
public const string ImageDecode = "decode";
public const string ImageEntropy = "entropy";
public const string ImageInfo = "info";
public const string ImageOptions = "options";
public const string ImagePrint = "print";
public const string ImageVerify = "verify";
// Media Family
public const string MediaPrefixShort = "m";
public const string MediaPrefixLong = "media";
public const string MediaDump = "dump";
public const string MediaInfo = "info";
public const string MediaScan = "scan";
// Standalone Commands
public const string Configure = "configure";
public const string Formats = "formats";
public const string ListEncodings = "list-encodings";
public const string ListNamespaces = "list-namespaces";
public const string Remote = "remote";
}
/// <summary>
/// Supported encodings for Aaru
/// </summary>
/// TODO: Use to verify encoding settings
public static class EncodingStrings
{
public const string ArabicMac = "x-mac-arabic";
public const string AtariASCII = "atascii";
public const string CentralEuropeanMac = "x-mac-ce";
public const string CommodorePETSCII = "petscii";
public const string CroatianMac = "x-mac-croatian";
public const string CyrillicMac = "x-mac-cryillic";
public const string FarsiMac = "x-mac-farsi";
public const string GreekMac = "x-mac-greek";
public const string HebrewMac = "x-mac-hebrew";
public const string RomanianMac = "x-mac-romanian";
public const string SinclairZXSpectrum = "spectrum";
public const string SinclairZX80 = "zx80";
public const string SinclairZX81 = "zx81";
public const string TurkishMac = "x-mac-turkish";
public const string UkrainianMac = "x-mac-ukrainian";
public const string Unicode = "utf-16";
public const string UnicodeBigEndian = "utf-16BE";
public const string UnicodeUTF32BigEndian = "utf-32BE";
public const string UnicodeUTF32 = "utf-32";
public const string UnicodeUTF7 = "utf-7";
public const string UnicodeUTF8 = "utf-8";
public const string USASCII = "us-ascii";
public const string WesternEuropeanAppleII = "apple2";
public const string WesternEuropeanAppleIIc = "apple2c";
public const string WesternEuropeanAppleIIe = "apple2e";
public const string WesternEuropeanAppleIIgs = "apple2gs";
public const string WesternEuropeanAppleLisa = "lisa";
public const string WesternEuropeanAtariST = "atarist";
public const string WesternEuropeanGEM = "gem";
public const string WesternEuropeanGEOS = "geos";
public const string WesternEuropeanISO = "iso-8859-1";
public const string WesternEuropeanMac = "macintosh";
public const string WesternEuropeanRadix50 = "radix50";
}
/// <summary>
/// Dumping flags for Aaru
/// </summary>
public static class FlagStrings
{
// Boolean flags
public const string Adler32Short = "-a";
public const string Adler32Long = "--adler32";
public const string ClearLong = "--clear";
public const string ClearAllLong = "--clear-all";
public const string CRC16Long = "--crc16";
public const string CRC32Short = "-c";
public const string CRC32Long = "--crc32";
public const string CRC64Long = "--crc64";
public const string DebugShort = "-d";
public const string DebugLong = "--debug";
public const string DiskTagsShort = "-f";
public const string DiskTagsLong = "--disk-tags";
public const string DuplicatedSectorsShort = "-p";
public const string DuplicatedSectorsLong = "--duplicated-sectors";
public const string EjectLong = "--eject";
public const string ExtendedAttributesShort = "-x";
public const string ExtendedAttributesLong = "--xattrs";
public const string FilesystemsShort = "-f";
public const string FilesystemsLong = "--filesystems";
public const string FirstPregapLong = "--first-pregap";
public const string FixOffsetLong = "--fix-offset";
public const string FixSubchannelLong = "--fix-subchannel";
public const string FixSubchannelCrcLong = "--fix-subchannel-crc";
public const string FixSubchannelPositionLong = "--fix-subchannel-position";
public const string Fletcher16Long = "--fletcher16";
public const string Fletcher32Long = "--fletcher32";
public const string ForceShort = "-f";
public const string ForceLong = "--force";
public const string GenerateSubchannelsLong = "--generate-subchannels";
public const string HelpShort = "-h";
public const string HelpShortAlt = "-?";
public const string HelpLong = "--help";
public const string LongFormatShort = "-l";
public const string LongFormatLong = "--long-format";
public const string LongSectorsShort = "-r";
public const string LongSectorsLong = "--long-sectors";
public const string MD5Short = "-m";
public const string MD5Long = "--md5";
public const string MetadataLong = "--metadata";
public const string PartitionsShort = "-p";
public const string PartitionsLong = "--partitions";
public const string PauseLong = "--pause";
public const string PersistentLong = "--persistent";
public const string PrivateLong = "--private";
public const string ResumeShort = "-r";
public const string ResumeLong = "--resume";
public const string RetrySubchannelLong = "--retry-subchannel";
public const string SectorTagsShort = "-p";
public const string SectorTagsLong = "--sector-tags";
public const string SeparatedTracksShort = "-t";
public const string SeparatedTracksLong = "--separated-tracks";
public const string SHA1Short = "-s";
public const string SHA1Long = "--sha1";
public const string SHA256Long = "--sha256";
public const string SHA384Long = "--sha384";
public const string SHA512Long = "--sha512";
public const string SkipCdiReadyHoleLong = "--skip-cdiready-hole";
public const string SpamSumShort = "-f";
public const string SpamSumLong = "--spamsum";
public const string StopOnErrorShort = "-s";
public const string StopOnErrorLong = "--stop-on-error";
public const string StoreEncryptedLong = "--store-encrypted";
public const string TapeShort = "-t";
public const string TapeLong = "--tape";
public const string TitleKeysLong = "--title-keys";
public const string TrapDiscShort = "-t";
public const string TrapDiscLong = "--trap-disc";
public const string TrimLong = "--trim";
public const string UseBufferedReadsLong = "--use-buffered-reads";
public const string VerboseShort = "-v";
public const string VerboseLong = "--verbose";
public const string VerifyDiscShort = "-w";
public const string VerifyDiscLong = "--verify-disc";
public const string VerifySectorsShort = "-s";
public const string VerifySectorsLong = "--verify-sectors";
public const string VersionLong = "--version";
public const string WholeDiscShort = "-w";
public const string WholeDiscLong = "--whole-disc";
// Int8 flags
public const string SpeedLong = "--speed";
// Int16 flags
public const string RetryPassesShort = "-p";
public const string RetryPassesLong = "--retry-passes";
public const string WidthShort = "-w";
public const string WidthLong = "--width";
// Int32 flags
public const string BlockSizeShort = "-b";
public const string BlockSizeLong = "--block-size";
public const string CountShort = "-c";
public const string CountLong = "--count";
public const string MaxBlocksLong = "--max-blocks";
public const string MediaLastSequenceLong = "--media-lastsequence";
public const string MediaSequenceLong = "--media-sequence";
public const string SkipShort = "-k";
public const string SkipLong = "--skip";
// Int64 flags
public const string LengthShort = "-l"; // or "all"
public const string LengthLong = "--length"; // or "all"
public const string StartShort = "-s";
public const string StartLong = "--start";
// String flags
public const string CommentsLong = "--comments";
public const string CreatorLong = "--creator";
public const string DriveManufacturerLong = "--drive-manufacturer";
public const string DriveModelLong = "--drive-model";
public const string DriveRevisionLong = "--drive-revision";
public const string DriveSerialLong = "--drive-serial";
public const string EncodingShort = "-e";
public const string EncodingLong = "--encoding";
public const string FormatConvertShort = "-p";
public const string FormatConvertLong = "--format";
public const string FormatDumpShort = "-t";
public const string FormatDumpLong = "--format";
public const string GeometryShort = "-g";
public const string GeometryLong = "--geometry";
public const string ImgBurnLogShort = "-b";
public const string ImgBurnLogLong = "--ibg-log";
public const string MediaBarcodeLong = "--media-barcode";
public const string MediaManufacturerLong = "--media-manufacturer";
public const string MediaModelLong = "--media-model";
public const string MediaPartNumberLong = "--media-partnumber";
public const string MediaSerialLong = "--media-serial";
public const string MediaTitleLong = "--media-title";
public const string MHDDLogShort = "-m";
public const string MHDDLogLong = "--mhdd-log";
public const string NamespaceShort = "-n";
public const string NamespaceLong = "--namespace";
public const string OptionsShort = "-O";
public const string OptionsLong = "--options";
public const string OutputPrefixShort = "-w";
public const string OutputPrefixLong = "--output-prefix";
public const string ResumeFileShort = "-r";
public const string ResumeFileLong = "--resume-file";
public const string SubchannelLong = "--subchannel";
public const string XMLSidecarShort = "-x";
public const string XMLSidecarLong = "--cicm-xml";
}
/// <summary>
/// Supported formats for Aaru
/// </summary>
/// TODO: Use to verify format settings
public static class FormatStrings
{
// Supported filters
public const string AppleDouble = "AppleDouble";
public const string AppleSingle = "AppleSingle";
public const string BZip2 = "BZip2";
public const string GZip = "GZip";
public const string LZip = "LZip";
public const string MacBinary = "MacBinary";
public const string NoFilter = "No filter";
public const string PCExchange = "PCExchange";
public const string XZ = "XZ";
// Read-only media image formats
public const string AppleDiskArchivalRetrievalTool = "Apple Disk Archival/Retrieval Tool";
public const string AppleNewDiskImageFormat = "Apple New Disk Image Format";
public const string AppleNIB = "Apple NIB";
public const string BlindWrite4 = "BlindWrite 4";
public const string BlindWrite5 = "BlindWrite 5";
public const string CPCEMUDiskFileAndExtendedCPCDiskFile = "CPCEMU Disk-File and Extended CPC Disk-File";
public const string D2FDiskImage = "d2f disk image";
public const string D88DiskImage = "D88 Disk Image";
public const string DIMDiskImage = "DIM Disk Image";
public const string DiscFerret = "DiscFerret";
public const string DiscJuggler = "DiscJuggler";
public const string DreamcastGDIImage = "Dreamcast GDI image";
public const string DunfieldsIMD = "Dunfield's IMD";
public const string HDCopyDiskImage = "HD-Copy disk image";
public const string KryoFluxSTREAM = "KryoFlux STREAM";
public const string MAMECompressedHunksOfData = "MAME Compressed Hunks of Data";
public const string MicrosoftVHDX = "Microsoft VHDX";
public const string NeroBurningROMImage = "Nero Burning ROM image";
public const string PartCloneDiskImage = "PartClone disk image";
public const string PartimageDiskImage = "Partimage disk image";
public const string SpectrumFloppyDiskImage = "Spectrum Floppy Disk Image";
public const string SuperCardPro = "SuperCardPro";
public const string SydexCopyQM = "Sydex CopyQM";
public const string SydexTeleDisk = "Sydex TeleDisk";
// Read/write media image formats
public const string AaruFormat = "Aaru Format";
public const string ACTApricotDiskImage = "ACT Apricot Disk Image";
public const string Alcohol120MediaDescriptorStructure = "Alcohol 120% Media Descriptor Structure";
public const string Anex86DiskImage = "Anex86 Disk Image";
public const string Apple2InterleavedDiskImage = "Apple ][Interleaved Disk Image";
public const string Apple2IMG = "Apple 2IMG";
public const string AppleDiskCopy42 = "Apple DiskCopy 4.2";
public const string AppleUniversalDiskImageFormat = "Apple Universal Disk Image Format";
public const string BasicLisaUtility = "Basic Lisa Utility";
public const string CDRDAOTocfile = "CDRDAO tocfile";
public const string CDRWinCuesheet = "CDRWin cuesheet";
public const string CisCopyDiskImageDCFile = "CisCopy Disk Image(DC-File)";
public const string CloneCD = "CloneCD";
public const string CopyTape = "CopyTape";
public const string DigitalResearchDiskCopy = "Digital Research DiskCopy";
public const string IBMSaveDskF = "IBM SaveDskF";
public const string MAXIDiskImage = "MAXI Disk image";
public const string ParallelsDiskImage = "Parallels disk image";
public const string QEMUCopyOnWriteDiskImage = "QEMU Copy-On-Write disk image";
public const string QEMUCopyOnWriteDiskImageV2 = "QEMU Copy-On-Write disk image v2";
public const string QEMUEnhancedDiskImage = "QEMU Enhanced Disk image";
public const string RawDiskImage = "Raw Disk Image";
public const string RayAracheliansDiskIMage = "Ray Arachelian's Disk IMage";
public const string RSIDEHardDiskImage = "RS-IDE Hard Disk Image";
public const string T98HardDiskImage = "T98 Hard Disk Image";
public const string T98NextNHDr0DiskImage = "T98-Next NHD r0 Disk Image";
public const string Virtual98DiskImage = "Virtual98 Disk Image";
public const string VirtualBoxDiskImage = "VirtualBox Disk Image";
public const string VirtualPC = "VirtualPC";
public const string VMwareDiskImage = "VMware disk image";
// Supported filesystems for identification and information only
public const string AcornAdvancedDiscFilingSystem = "Acorn Advanced Disc Filing System";
public const string AlexanderOsipovDOSFileSystem = "Alexander Osipov DOS file system";
public const string AmigaDOSFilesystem = "Amiga DOS filesystem";
public const string AppleFileSystem = "Apple File System";
public const string AppleHFSPlusFilesystem = "Apple HFS+ filesystem";
public const string AppleHierarchicalFileSystem = "Apple Hierarchical File System";
public const string AppleProDOSFilesystem = "Apple ProDOS filesystem";
public const string AtheOSFilesystem = "AtheOS Filesystem";
public const string BeFilesystem = "Be Filesystem";
public const string BSDFastFileSystem = "BSD Fast File System(aka UNIX File System, UFS)";
public const string BTreeFileSystem = "B-tree file system";
public const string CommodoreFileSystem = "Commodore file system";
public const string CramFilesystem = "Cram filesystem";
public const string DumpEightPlugin = "dump(8) Plugin";
public const string ECMA67 = "ECMA-67";
public const string ExtentFileSystemPlugin = "Extent File System Plugin";
public const string F2FSPlugin = "F2FS Plugin";
public const string Files11OnDiskStructure = "Files-11 On-Disk Structure";
public const string FossilFilesystemPlugin = "Fossil Filesystem Plugin";
public const string HAMMERFilesystem = "HAMMER Filesystem";
public const string HighPerformanceOpticalFileSystem = "High Performance Optical File System";
public const string HPLogicalInterchangeFormatPlugin = "HP Logical Interchange Format Plugin";
public const string JFSPlugin = "JFS Plugin";
public const string LinuxExtendedFilesystem = "Linux extended Filesystem";
public const string LinuxExtendedFilesystem234 = "Linux extended Filesystem 2, 3 and 4";
public const string LocusFilesystemPlugin = "Locus Filesystem Plugin";
public const string MicroDOSFileSystem = "MicroDOS file system";
public const string MicrosoftExtendedFileAllocationTable = "Microsoft Extended File Allocation Table";
public const string MinixFilesystem = "Minix Filesystem";
public const string NewTechnologyFileSystem = "New Technology File System(NTFS)";
public const string NILFS2Plugin = "NILFS2 Plugin";
public const string NintendoOpticalFilesystems = "Nintendo optical filesystems";
public const string OS2HighPerformanceFileSystem = "OS/2 High Performance File System";
public const string OS9RandomBlockFilePlugin = "OS-9 Random Block File Plugin";
public const string PCEngineCDPlugin = "PC Engine CD Plugin";
public const string PCFXPlugin = "PC-FX Plugin";
public const string ProfessionalFileSystem = "Professional File System";
public const string QNX4Plugin = "QNX4 Plugin";
public const string QNX6Plugin = "QNX6 Plugin";
public const string ReiserFilesystemPlugin = "Reiser Filesystem Plugin";
public const string Reiser4FilesystemPlugin = "Reiser4 Filesystem Plugin";
public const string ResilientFileSystemPlugin = "Resilient File System plugin";
public const string RT11FileSystem = "RT-11 file system";
public const string SmartFileSystem = "SmartFileSystem";
public const string SolarOSFilesystem = "Solar_OS filesystem";
public const string SquashFilesystem = "Squash filesystem";
public const string UNICOSFilesystemPlugin = "UNICOS Filesystem Plugin";
public const string UniversalDiskFormat = "Universal Disk Format";
public const string UNIXBootFilesystem = "UNIX Boot filesystem";
public const string UNIXSystemVFilesystem = "UNIX System V filesystem";
public const string VeritasFilesystem = "Veritas filesystem";
public const string VMwareFilesystem = "VMware filesystem";
public const string XFSFilesystemPlugin = "XFS Filesystem Plugin";
public const string XiaFilesystem = "Xia filesystem";
public const string ZFSFilesystemPlugin = "ZFS Filesystem Plugin";
// Supported filesystems that can read their contents
public const string AppleDOSFileSystem = "Apple DOS File System";
public const string AppleLisaFileSystem = "Apple Lisa File System";
public const string AppleMacintoshFileSystem = "Apple Macintosh File System";
public const string CPMFileSystem = "CP/M File System";
public const string FATXFilesystemPlugin = "FATX Filesystem Plugin";
public const string ISO9660Filesystem = "ISO9660 Filesystem";
public const string MicrosoftFileAllocationTable = "Microsoft File Allocation Table";
public const string OperaFilesystemPlugin = "Opera Filesystem Plugin";
public const string UCSDPascalFilesystem = "U.C.S.D.Pascal filesystem";
// Supported partitioning schemes
public const string AcornFileCorePartitions = "Acorn FileCore partitions";
public const string ACTApricotPartitions = "ACT Apricot partitions";
public const string AmigaRigidDiskBlock = "Amiga Rigid Disk Block";
public const string ApplePartitionMap = "Apple Partition Map";
public const string AtariPartitions = "Atari partitions";
public const string BSDDisklabel = "BSD disklabel";
public const string DECDisklabel = "DEC disklabel";
public const string DragonFlyBSD64bitDisklabel = "DragonFly BSD 64-bit disklabel";
public const string GUIDPartitionTable = "GUID Partition Table";
public const string Human68kPartitions = "Human 68k partitions";
public const string MasterBootRecord = "Master Boot Record";
public const string NECPC9800PartitionTable = "NEC PC-9800 partition table";
public const string NeXTDisklabel = "NeXT Disklabel";
public const string Plan9PartitionTable = "Plan9 partition table";
public const string RioKarmaPartitioning = "Rio Karma partitioning";
public const string SGIDiskVolumeHeader = "SGI Disk Volume Header";
public const string SunDisklabel = "Sun Disklabel";
public const string UNIXHardwired = "UNIX hardwired";
public const string UNIXVTOC = "UNIX VTOC";
public const string XboxPartitioning = "Xbox partitioning";
public const string XENIX = "XENIX";
}
/// <summary>
/// Supported namespaces for Aaru
/// </summary>
/// TODO: Use to verify namespace settings
public static class NamespaceStrings
{
// Namespaces for Apple Lisa File System
public const string LisaOfficeSystem = "office";
public const string LisaPascalWorkshop = "workshop"; // Default
// Namespaces for ISO9660 Filesystem
public const string JolietVolumeDescriptor = "joliet"; // Default
public const string PrimaryVolumeDescriptor = "normal";
public const string PrimaryVolumeDescriptorwithEncoding = "romeo";
public const string RockRidge = "rrip";
public const string PrimaryVolumeDescriptorVersionSuffix = "vms";
// Namespaces for Microsoft File Allocation Table
public const string DOS83UpperCase = "dos";
public const string LFNWhenAvailableWithFallback = "ecs"; // Default
public const string LongFileNames = "lfn";
public const string WindowsNT83MixedCase = "nt";
public const string OS2Extended = "os2";
}
/// <summary>
/// Supported options for Aaru
/// </summary>
/// TODO: Use to verify option settings
public static class OptionStrings
{
// Aaru format
public const string AaruCompress = "compress"; // boolean, default true;
public const string AaruDeduplicate = "deduplicate"; // boolean, default true
public const string AaruDictionary = "dictionary"; // number, default 33554432
public const string AaruMaxDDTSize = "max_ddt_size"; // number, default 256
public const string AaruMD5 = "md5"; // boolean, default false
public const string AaruSectorsPerBlock = "sectors_per_block"; // number, default 4096 [power of 2]
public const string AaruSHA1 = "sha1"; // boolean, default false
public const string AaruSHA256 = "sha256"; // boolean, default false
public const string AaruSpamSum = "spamsum"; // boolean, default false
// ACT Apricot Disk Image
public const string ACTApricotDiskImageCompress = "compress"; // boolean, default false
// Apple DiskCopy 4.2
public const string AppleDiskCopyMacOSX = "macosx"; // boolean, default false
// CDRDAO tocfile
public const string CDRDAOTocfileSeparate = "separate"; // boolean, default false
// CDRWin cuesheet
public const string CDRWinCuesheetSeparate = "separate"; // boolean, default false
// ISO9660 Filesystem
public const string ISO9660FSUseEvd = "use_evd"; // boolean, default false
public const string ISO9660FSUsePathTable = "use_path_table"; // boolean, default false
public const string ISO9660FSUseTransTbl = "use_trans_tbl"; // boolean, default false
// VMware disk image
public const string VMwareDiskImageAdapterType = "adapter_type"; // string, default ide [ide, lsilogic, buslogic, legacyESX]
public const string VMwareDiskImageHWVersion = "hwversion"; // number, default 4
public const string VMwareDiskImageSparse = "sparse"; // boolean, default false
public const string VMwareDiskImageSplit = "split"; // boolean, default false
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,425 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using MPF.Core.Converters;
using MPF.Core.Data;
using SabreTools.RedumpLib.Data;
namespace MPF.Core.Modules.CleanRip
{
/// <summary>
/// Represents a generic set of CleanRip parameters
/// </summary>
public class Parameters : BaseParameters
{
#region Metadata
/// <inheritdoc/>
public override InternalProgram InternalProgram => InternalProgram.CleanRip;
#endregion
/// <inheritdoc/>
#if NET48
public Parameters(string parameters) : base(parameters) { }
#else
public Parameters(string? parameters) : base(parameters) { }
#endif
/// <inheritdoc/>
public Parameters(RedumpSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
: base(system, type, driveLetter, filename, driveSpeed, options)
{
}
#region BaseParameters Implementations
/// <inheritdoc/>
public override (bool, List<string>) CheckAllOutputFilesExist(string basePath, bool preCheck)
{
List<string> missingFiles = new List<string>();
switch (this.Type)
{
case MediaType.DVD: // Only added here to help users; not strictly correct
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
if (!File.Exists($"{basePath}_logs.zip") || !preCheck)
{
if (!File.Exists($"{basePath}-dumpinfo.txt"))
missingFiles.Add($"{basePath}-dumpinfo.txt");
if (!File.Exists($"{basePath}.bca"))
missingFiles.Add($"{basePath}.bca");
}
break;
default:
missingFiles.Add("Media and system combination not supported for CleanRip");
break;
}
return (!missingFiles.Any(), missingFiles);
}
/// <inheritdoc/>
#if NET48
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive drive, bool includeArtifacts)
#else
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive? drive, bool includeArtifacts)
#endif
{
// TODO: Determine if there's a CleanRip version anywhere
if (info.DumpingInfo == null) info.DumpingInfo = new DumpingInfoSection();
info.DumpingInfo.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
info.DumpingInfo.DumpingDate = GetFileModifiedDate(basePath + "-dumpinfo.txt")?.ToString("yyyy-MM-dd HH:mm:ss");
var datafile = GenerateCleanripDatafile(basePath + ".iso", basePath + "-dumpinfo.txt");
// Get the individual hash data, as per internal
if (GetISOHashValues(datafile, out long size, out var crc32, out var md5, out var sha1))
{
if (info.SizeAndChecksums == null) info.SizeAndChecksums = new SizeAndChecksumsSection();
info.SizeAndChecksums.Size = size;
info.SizeAndChecksums.CRC32 = crc32;
info.SizeAndChecksums.MD5 = md5;
info.SizeAndChecksums.SHA1 = sha1;
// Dual-layer discs have the same size and layerbreak
if (size == 8511160320)
info.SizeAndChecksums.Layerbreak = 2084960;
}
// Extract info based generically on MediaType
switch (this.Type)
{
case MediaType.DVD: // Only added here to help users; not strictly correct
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
if (File.Exists(basePath + ".bca"))
{
if (info.Extras == null) info.Extras = new ExtrasSection();
info.Extras.BCA = GetBCA(basePath + ".bca");
}
if (GetGameCubeWiiInformation(basePath + "-dumpinfo.txt", out Region? gcRegion, out var gcVersion, out var gcName))
{
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
info.CommonDiscInfo.Region = gcRegion ?? info.CommonDiscInfo.Region;
if (info.VersionAndEditions == null) info.VersionAndEditions = new VersionAndEditionsSection();
info.VersionAndEditions.Version = gcVersion ?? info.VersionAndEditions.Version;
#if NET48
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalName] = gcName ?? string.Empty;
}
break;
}
// Fill in any artifacts that exist, Base64-encoded, if we need to
if (includeArtifacts)
{
if (info.Artifacts == null) info.Artifacts = new Dictionary<string, string>();
if (File.Exists(basePath + ".bca"))
info.Artifacts["bca"] = GetBase64(GetFullFile(basePath + ".bca", binary: true)) ?? string.Empty;
if (File.Exists(basePath + "-dumpinfo.txt"))
info.Artifacts["dumpinfo"] = GetBase64(GetFullFile(basePath + "-dumpinfo.txt")) ?? string.Empty;
}
}
/// <inheritdoc/>
public override List<string> GetLogFilePaths(string basePath)
{
List<string> logFiles = new List<string>();
switch (this.Type)
{
case MediaType.DVD: // Only added here to help users; not strictly correct
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
if (File.Exists($"{basePath}-dumpinfo.txt"))
logFiles.Add($"{basePath}-dumpinfo.txt");
if (File.Exists($"{basePath}.bca"))
logFiles.Add($"{basePath}.bca");
break;
}
return logFiles;
}
#endregion
#region Information Extraction Methods
/// <summary>
/// Get a formatted datfile from the cleanrip output, if possible
/// </summary>
/// <param name="iso">Path to ISO file</param>
/// <param name="dumpinfo">Path to discinfo file</param>
/// <returns></returns>
#if NET48
private static Datafile GenerateCleanripDatafile(string iso, string dumpinfo)
#else
private static Datafile? GenerateCleanripDatafile(string iso, string dumpinfo)
#endif
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(dumpinfo))
return null;
using (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") != true)
return null;
// Read all lines and gather dat information
while (!sr.EndOfStream)
{
var line = sr.ReadLine()?.Trim();
if (string.IsNullOrWhiteSpace(line))
continue;
else if (line.StartsWith("CRC32"))
crc = line.Substring(7).ToLowerInvariant();
else if (line.StartsWith("MD5"))
md5 = line.Substring(5);
else if (line.StartsWith("SHA-1"))
sha1 = line.Substring(7);
}
return new Datafile
{
Games = new Game[]
{
new Game
{
Roms = new Rom[]
{
new Rom { Name = Path.GetFileName(iso), Size = size.ToString(), Crc = crc, Md5 = md5, Sha1 = sha1 },
}
}
}
};
}
catch
{
// We don't care what the exception is right now
return null;
}
}
}
/// <summary>
/// Get the hex contents of the BCA file
/// </summary>
/// <param name="bcaPath">Path to the BCA file associated with the dump</param>
/// <returns>BCA data as a hex string if possible, null on error</returns>
/// <remarks>https://stackoverflow.com/questions/9932096/add-separator-to-string-at-every-n-characters</remarks>
#if NET48
private static string GetBCA(string bcaPath)
#else
private static string? GetBCA(string bcaPath)
#endif
{
// If the file doesn't exist, we can't get the info
if (!File.Exists(bcaPath))
return null;
try
{
var hex = GetFullFile(bcaPath, true);
if (hex == null)
return null;
return Regex.Replace(hex, ".{32}", "$0\n");
}
catch
{
// We don't care what the error was right now
return null;
}
}
/// <summary>
/// Get a formatted datfile from the cleanrip output, if possible
/// </summary>
/// <param name="iso">Path to ISO file</param>
/// <param name="dumpinfo">Path to discinfo file</param>
/// <returns></returns>
#if NET48
private static string GetCleanripDatfile(string iso, string dumpinfo)
#else
private static string? GetCleanripDatfile(string iso, string dumpinfo)
#endif
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(dumpinfo))
return null;
using (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") != true)
return null;
// Read all lines and gather dat information
while (!sr.EndOfStream)
{
var line = sr.ReadLine()?.Trim();
if (string.IsNullOrWhiteSpace(line))
continue;
else if (line.StartsWith("CRC32"))
crc = line.Substring(7).ToLowerInvariant();
else if (line.StartsWith("MD5"))
md5 = line.Substring(5);
else if (line.StartsWith("SHA-1"))
sha1 = line.Substring(7);
}
return $"<rom name=\"{Path.GetFileName(iso)}\" size=\"{size}\" crc=\"{crc}\" md5=\"{md5}\" sha1=\"{sha1}\" />";
}
catch
{
// We don't care what the exception is right now
return null;
}
}
}
/// <summary>
/// Get the extracted GC and Wii version
/// </summary>
/// <param name="dumpinfo">Path to discinfo file</param>
/// <param name="region">Output region, if possible</param>
/// <param name="version">Output internal version of the game</param>
/// <param name="name">Output internal name of the game</param>
/// <returns></returns>
#if NET48
private static bool GetGameCubeWiiInformation(string dumpinfo, out Region? region, out string version, out string name)
#else
private static bool GetGameCubeWiiInformation(string dumpinfo, out Region? region, out string? version, out string? name)
#endif
{
region = null; version = null; name = null;
// If the file doesn't exist, we can't get info from it
if (!File.Exists(dumpinfo))
return false;
using (StreamReader sr = File.OpenText(dumpinfo))
{
try
{
// Make sure this file is a dumpinfo
if (sr.ReadLine()?.Contains("--File Generated by CleanRip") != true)
return false;
// Read all lines and gather dat information
while (!sr.EndOfStream)
{
var line = sr.ReadLine()?.Trim();
if (string.IsNullOrWhiteSpace(line))
{
continue;
}
else if (line.StartsWith("Version"))
{
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("Filename: ".Length);
// char gameType = serial[0];
// string gameid = serial[1] + serial[2];
// string version = serial[4] + serial[5]
switch (serial[3])
{
case 'A':
region = Region.World;
break;
case 'D':
region = Region.Germany;
break;
case 'E':
region = Region.UnitedStatesOfAmerica;
break;
case 'F':
region = Region.France;
break;
case 'I':
region = Region.Italy;
break;
case 'J':
region = Region.Japan;
break;
case 'K':
region = Region.SouthKorea;
break;
case 'L':
region = Region.Europe; // Japanese import to Europe
break;
case 'M':
region = Region.Europe; // American import to Europe
break;
case 'N':
region = Region.UnitedStatesOfAmerica; // Japanese import to USA
break;
case 'P':
region = Region.Europe;
break;
case 'R':
region = Region.RussianFederation;
break;
case 'S':
region = Region.Spain;
break;
case 'Q':
region = Region.SouthKorea; // Korea with Japanese language
break;
case 'T':
region = Region.SouthKorea; // Korea with English language
break;
case 'X':
region = null; // Not a real region code
break;
}
}
}
return true;
}
catch
{
// We don't care what the exception is right now
return false;
}
}
}
#endregion
}
}

View File

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

View File

@@ -1,132 +0,0 @@
using SabreTools.RedumpLib.Data;
namespace MPF.Core.Modules.DiscImageCreator
{
public static class Converters
{
#region Cross-enumeration conversions
/// <summary>
/// Get the most common known system for a given MediaType
/// </summary>
/// <param name="baseCommand">Command value to check</param>
/// <returns>RedumpSystem if possible, null on error</returns>
public static RedumpSystem? ToRedumpSystem(string baseCommand)
{
switch (baseCommand)
{
case CommandStrings.Audio:
return RedumpSystem.AudioCD;
case CommandStrings.CompactDisc:
case CommandStrings.Data:
case CommandStrings.DigitalVideoDisc:
case CommandStrings.Disk:
case CommandStrings.Floppy:
case CommandStrings.Tape:
return RedumpSystem.IBMPCcompatible;
case CommandStrings.GDROM:
case CommandStrings.Swap:
return RedumpSystem.SegaDreamcast;
case CommandStrings.BluRay:
return RedumpSystem.SonyPlayStation3;
case CommandStrings.SACD:
return RedumpSystem.SuperAudioCD;
case CommandStrings.XBOX:
case CommandStrings.XBOXSwap:
return RedumpSystem.MicrosoftXbox;
case CommandStrings.XGD2Swap:
case CommandStrings.XGD3Swap:
return RedumpSystem.MicrosoftXbox360;
default:
return null;
}
}
/// <summary>
/// Get the MediaType associated with a given base command
/// </summary>
/// <param name="baseCommand">Command value to check</param>
/// <returns>MediaType if possible, null on error</returns>
/// <remarks>This takes the "safe" route by assuming the larger of any given format</remarks>
#if NET48
public static MediaType? ToMediaType(string baseCommand)
#else
public static MediaType? ToMediaType(string? baseCommand)
#endif
{
switch (baseCommand)
{
case CommandStrings.Audio:
case CommandStrings.CompactDisc:
case CommandStrings.Data:
case CommandStrings.SACD:
return MediaType.CDROM;
case CommandStrings.GDROM:
case CommandStrings.Swap:
return MediaType.GDROM;
case CommandStrings.DigitalVideoDisc:
case CommandStrings.XBOX:
case CommandStrings.XBOXSwap:
case CommandStrings.XGD2Swap:
case CommandStrings.XGD3Swap:
return MediaType.DVD;
case CommandStrings.BluRay:
return MediaType.BluRay;
// Non-optical
case CommandStrings.Floppy:
return MediaType.FloppyDisk;
case CommandStrings.Disk:
return MediaType.HardDisk;
case CommandStrings.Tape:
return MediaType.DataCartridge;
default:
return null;
}
}
/// <summary>
/// Get the default extension for a given disc type
/// </summary>
/// <param name="type">MediaType value to check</param>
/// <returns>Valid extension (with leading '.'), null on error</returns>
#if NET48
public static string Extension(MediaType? type)
#else
public static string? Extension(MediaType? type)
#endif
{
switch (type)
{
case MediaType.CDROM:
case MediaType.GDROM:
case MediaType.Cartridge:
case MediaType.HardDisk:
case MediaType.CompactFlash:
case MediaType.MMC:
case MediaType.SDCard:
case MediaType.FlashDrive:
return ".bin";
case MediaType.DVD:
case MediaType.HDDVD:
case MediaType.BluRay:
case MediaType.NintendoWiiOpticalDisc:
return ".iso";
case MediaType.LaserDisc:
case MediaType.NintendoGameCubeGameDisc:
return ".raw";
case MediaType.NintendoWiiUOpticalDisc:
return ".wud";
case MediaType.FloppyDisk:
return ".img";
case MediaType.Cassette:
return ".wav";
case MediaType.NONE:
default:
return null;
}
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,74 +0,0 @@
namespace MPF.Core.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";
public const string DVDIsoKey = "dvdisokey";
}
/// <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";
public const string OverreadLeadout = "--overread-leadout";
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,254 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using MPF.Core.Converters;
using MPF.Core.Data;
using SabreTools.RedumpLib.Data;
namespace MPF.Core.Modules.UmdImageCreator
{
/// <summary>
/// Represents a generic set of UmdImageCreator parameters
/// </summary>
public class Parameters : BaseParameters
{
#region Metadata
/// <inheritdoc/>
public override InternalProgram InternalProgram => InternalProgram.UmdImageCreator;
#endregion
/// <inheritdoc/>
#if NET48
public Parameters(string parameters) : base(parameters) { }
#else
public Parameters(string? parameters) : base(parameters) { }
#endif
/// <inheritdoc/>
public Parameters(RedumpSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
: base(system, type, driveLetter, filename, driveSpeed, options)
{
}
#region BaseParameters Implementations
/// <inheritdoc/>
public override (bool, List<string>) CheckAllOutputFilesExist(string basePath, bool preCheck)
{
List<string> missingFiles = new List<string>();
switch (this.Type)
{
case MediaType.UMD:
if (!File.Exists($"{basePath}_logs.zip") || !preCheck)
{
if (!File.Exists($"{basePath}_disc.txt"))
missingFiles.Add($"{basePath}_disc.txt");
if (!File.Exists($"{basePath}_mainError.txt"))
missingFiles.Add($"{basePath}_mainError.txt");
if (!File.Exists($"{basePath}_mainInfo.txt"))
missingFiles.Add($"{basePath}_mainInfo.txt");
if (!File.Exists($"{basePath}_volDesc.txt"))
missingFiles.Add($"{basePath}_volDesc.txt");
}
break;
default:
missingFiles.Add("Media and system combination not supported for UmdImageCreator");
break;
}
return (!missingFiles.Any(), missingFiles);
}
/// <inheritdoc/>
#if NET48
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive drive, bool includeArtifacts)
#else
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive? drive, bool includeArtifacts)
#endif
{
// TODO: Determine if there's a UMDImageCreator version anywhere
if (info.DumpingInfo == null) info.DumpingInfo = new DumpingInfoSection();
info.DumpingInfo.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
info.DumpingInfo.DumpingDate = GetFileModifiedDate(basePath + "_disc.txt")?.ToString("yyyy-MM-dd HH:mm:ss");
// Extract info based generically on MediaType
switch (this.Type)
{
case MediaType.UMD:
if (info.Extras == null) info.Extras = new ExtrasSection();
info.Extras.PVD = GetPVD(basePath + "_mainInfo.txt") ?? string.Empty;
if (GetFileHashes(basePath + ".iso", out long filesize, out var crc32, out var md5, out var sha1))
{
if (info.SizeAndChecksums == null) info.SizeAndChecksums = new SizeAndChecksumsSection();
info.SizeAndChecksums.Size = filesize;
info.SizeAndChecksums.CRC32 = crc32;
info.SizeAndChecksums.MD5 = md5;
info.SizeAndChecksums.SHA1 = sha1;
}
if (GetUMDAuxInfo(basePath + "_disc.txt", out var title, out DiscCategory? umdcat, out var umdversion, out var umdlayer, out long umdsize))
{
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
info.CommonDiscInfo.Title = title ?? string.Empty;
info.CommonDiscInfo.Category = umdcat ?? DiscCategory.Games;
if (info.VersionAndEditions == null) info.VersionAndEditions = new VersionAndEditionsSection();
info.VersionAndEditions.Version = umdversion ?? string.Empty;
if (info.SizeAndChecksums == null) info.SizeAndChecksums = new SizeAndChecksumsSection();
info.SizeAndChecksums.Size = umdsize;
if (!string.IsNullOrWhiteSpace(umdlayer))
info.SizeAndChecksums.Layerbreak = Int64.Parse(umdlayer ?? "-1");
}
break;
}
// Fill in any artifacts that exist, Base64-encoded, if we need to
if (includeArtifacts)
{
if (info.Artifacts == null) info.Artifacts = new Dictionary<string, string>();
if (File.Exists(basePath + "_disc.txt"))
info.Artifacts["disc"] = GetBase64(GetFullFile(basePath + "_disc.txt")) ?? string.Empty;
if (File.Exists(basePath + "_drive.txt"))
info.Artifacts["drive"] = GetBase64(GetFullFile(basePath + "_drive.txt")) ?? string.Empty;
if (File.Exists(basePath + "_mainError.txt"))
info.Artifacts["mainError"] = GetBase64(GetFullFile(basePath + "_mainError.txt")) ?? string.Empty;
if (File.Exists(basePath + "_mainInfo.txt"))
info.Artifacts["mainInfo"] = GetBase64(GetFullFile(basePath + "_mainInfo.txt")) ?? string.Empty;
if (File.Exists(basePath + "_volDesc.txt"))
info.Artifacts["volDesc"] = GetBase64(GetFullFile(basePath + "_volDesc.txt")) ?? string.Empty;
}
}
/// <inheritdoc/>
public override List<string> GetLogFilePaths(string basePath)
{
List<string> logFiles = new List<string>();
switch (this.Type)
{
case MediaType.UMD:
if (File.Exists($"{basePath}_disc.txt"))
logFiles.Add($"{basePath}_disc.txt");
if (File.Exists($"{basePath}_drive.txt"))
logFiles.Add($"{basePath}_drive.txt");
if (File.Exists($"{basePath}_mainError.txt"))
logFiles.Add($"{basePath}_mainError.txt");
if (File.Exists($"{basePath}_mainInfo.txt"))
logFiles.Add($"{basePath}_mainInfo.txt");
if (File.Exists($"{basePath}_volDesc.txt"))
logFiles.Add($"{basePath}_volDesc.txt");
break;
}
return logFiles;
}
#endregion
#region Information Extraction Methods
/// <summary>
/// Get the PVD from the input file, if possible
/// </summary>
/// <param name="mainInfo">_mainInfo.txt file location</param>
/// <returns>Newline-deliminated PVD if possible, null on error</returns>
#if NET48
private static string GetPVD(string mainInfo)
#else
private static string? GetPVD(string mainInfo)
#endif
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(mainInfo))
return null;
using (StreamReader sr = File.OpenText(mainInfo))
{
try
{
// Make sure we're in the right sector
while (sr.ReadLine()?.StartsWith("========== LBA[000016, 0x0000010]: Main Channel ==========") == false) ;
// Fast forward to the PVD
while (sr.ReadLine()?.StartsWith("0310") == false) ;
// Now that we're at the PVD, read each line in and concatenate
string pvd = "";
for (int i = 0; i < 6; i++)
pvd += sr.ReadLine() + "\n"; // 320-370
return pvd;
}
catch
{
// We don't care what the exception is right now
return null;
}
}
}
/// <summary>
/// Get the UMD auxiliary info from the outputted files, if possible
/// </summary>
/// <param name="disc">_disc.txt file location</param>
/// <returns>True on successful extraction of info, false otherwise</returns>
#if NET48
private static bool GetUMDAuxInfo(string disc, out string title, out DiscCategory? umdcat, out string umdversion, out string umdlayer, out long umdsize)
#else
private static bool GetUMDAuxInfo(string disc, out string? title, out DiscCategory? umdcat, out string? umdversion, out string? umdlayer, out long umdsize)
#endif
{
title = null; umdcat = null; umdversion = null; umdlayer = null; umdsize = -1;
// If the file doesn't exist, we can't get info from it
if (!File.Exists(disc))
return false;
using (StreamReader sr = File.OpenText(disc))
{
try
{
// Loop through everything to get the first instance of each required field
var line = string.Empty;
while (!sr.EndOfStream)
{
line = sr.ReadLine()?.Trim();
if (line == null)
break;
if (line.StartsWith("TITLE") && title == null)
title = line.Substring("TITLE: ".Length);
else if (line.StartsWith("DISC_VERSION") && umdversion == null)
umdversion = line.Split(' ')[1];
else if (line.StartsWith("pspUmdTypes"))
umdcat = GetUMDCategory(line.Split(' ')[1]);
else if (line.StartsWith("L0 length"))
umdlayer = line.Split(' ')[2];
else if (line.StartsWith("FileSize:"))
umdsize = Int64.Parse(line.Split(' ')[1]);
}
// If the L0 length is the size of the full disc, there's no layerbreak
if (Int64.TryParse(umdlayer, out long umdlayerValue) && umdlayerValue * 2048 == umdsize)
umdlayer = null;
return true;
}
catch
{
// We don't care what the exception is right now
return false;
}
}
}
#endregion
}
}

View File

@@ -1,335 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BinaryObjectScanner.Protection;
using BurnOutSharp;
using psxt001z;
namespace MPF.Core
{
public static class Protection
{
/// <summary>
/// Run protection scan on a given path
/// </summary>
/// <param name="path">Path to scan for protection</param>
/// <param name="options">Options object that determines what to scan</param>
/// <param name="progress">Optional progress callback</param>
/// <returns>Set of all detected copy protections with an optional error string</returns>
#if NET48
public static async Task<(Dictionary<string, List<string>>, string)> RunProtectionScanOnPath(string path, Data.Options options, IProgress<ProtectionProgress> progress = null)
#else
public static async Task<(Dictionary<string, List<string>>?, string?)> RunProtectionScanOnPath(string path, Data.Options options, IProgress<ProtectionProgress>? progress = null)
#endif
{
try
{
var found = await Task.Run(() =>
{
var scanner = new Scanner(
options.ScanArchivesForProtection,
scanContents: true, // Hardcoded value to avoid issues
scanGameEngines: false, // Hardcoded value to avoid issues
options.ScanPackersForProtection,
scanPaths: true, // Hardcoded value to avoid issues
options.IncludeDebugProtectionInformation,
progress);
return scanner.GetProtections(path);
});
// If nothing was returned, return
if (found == null || !found.Any())
return (null, null);
// Filter out any empty protections
var filteredProtections = found
.Where(kvp => kvp.Value != null && kvp.Value.Any())
.ToDictionary(
kvp => kvp.Key,
kvp => kvp.Value.OrderBy(s => s).ToList());
// Return the filtered set of protections
return (filteredProtections, null);
}
catch (Exception ex)
{
return (null, ex.ToString());
}
}
/// <summary>
/// Format found protections to a deduplicated, ordered string
/// </summary>
/// <param name="protections">Dictionary of file to list of protection mappings</param>
/// <returns>Detected protections, if any</returns>
#if NET48
public static string FormatProtections(Dictionary<string, List<string>> protections)
#else
public static string? FormatProtections(Dictionary<string, List<string>>? protections)
#endif
{
// If the filtered list is empty in some way, return
if (protections == null || !protections.Any())
return "None found [OMIT FROM SUBMISSION]";
// Get an ordered list of distinct found protections
var orderedDistinctProtections = protections
.SelectMany(kvp => kvp.Value)
.Distinct()
.OrderBy(p => p);
// Sanitize and join protections for writing
string protectionString = SanitizeFoundProtections(orderedDistinctProtections);
if (string.IsNullOrWhiteSpace(protectionString))
return "None found [OMIT FROM SUBMISSION]";
return protectionString;
}
/// <summary>
/// Get the existence of an anti-modchip string from a PlayStation disc, if possible
/// </summary>
/// <param name="path">Path to scan for anti-modchip strings</param>
/// <returns>Anti-modchip existence if possible, false on error</returns>
public static async Task<bool> GetPlayStationAntiModchipDetected(string path)
{
return await Task.Run(() =>
{
try
{
var antiModchip = new PSXAntiModchip();
foreach (string file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories))
{
try
{
byte[] fileContent = File.ReadAllBytes(file);
string protection = antiModchip.CheckContents(file, fileContent, false);
if (!string.IsNullOrWhiteSpace(protection))
return true;
}
catch { }
}
}
catch { }
return false;
});
}
/// <summary>
/// Get if LibCrypt data is detected in the subchannel file, if possible
/// </summary>
/// <param name="sub">.sub file location</param>
/// <returns>Status of the LibCrypt data, if possible</returns>
public static bool? GetLibCryptDetected(string sub)
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(sub))
return null;
return LibCrypt.CheckSubfile(sub);
}
/// <summary>
/// Sanitize unnecessary protection duplication from output
/// </summary>
/// <param name="foundProtections">Enumerable of found protections</param>
public static string SanitizeFoundProtections(IEnumerable<string> foundProtections)
{
// EXCEPTIONS
if (foundProtections.Any(p => p.StartsWith("[Exception opening file")))
{
foundProtections = foundProtections.Where(p => !p.StartsWith("[Exception opening file"));
foundProtections = foundProtections
.Prepend("Exception occurred while scanning [RESCAN NEEDED]")
.OrderBy(p => p);
}
// ActiveMARK
if (foundProtections.Any(p => p == "ActiveMARK 5") && foundProtections.Any(p => p == "ActiveMARK"))
foundProtections = foundProtections.Where(p => p != "ActiveMARK");
// Cactus Data Shield
if (foundProtections.Any(p => Regex.IsMatch(p, @"Cactus Data Shield [0-9]{3} .+")) && foundProtections.Any(p => p == "Cactus Data Shield 200"))
foundProtections = foundProtections.Where(p => p != "Cactus Data Shield 200");
// CD-Check
foundProtections = foundProtections.Where(p => p != "Executable-Based CD Check");
// CD-Cops
if (foundProtections.Any(p => p == "CD-Cops") && foundProtections.Any(p => p.StartsWith("CD-Cops") && p.Length > "CD-Cops".Length))
foundProtections = foundProtections.Where(p => p != "CD-Cops");
// CD-Key / Serial
foundProtections = foundProtections.Where(p => p != "CD-Key / Serial");
// Electronic Arts
if (foundProtections.Any(p => p == "EA CdKey Registration Module") && foundProtections.Any(p => p.StartsWith("EA CdKey Registration Module") && p.Length > "EA CdKey Registration Module".Length))
foundProtections = foundProtections.Where(p => p != "EA CdKey Registration Module");
if (foundProtections.Any(p => p == "EA DRM Protection") && foundProtections.Any(p => p.StartsWith("EA DRM Protection") && p.Length > "EA DRM Protection".Length))
foundProtections = foundProtections.Where(p => p != "EA DRM Protection");
// Games for Windows LIVE
if (foundProtections.Any(p => p == "Games for Windows LIVE") && foundProtections.Any(p => p.StartsWith("Games for Windows LIVE") && !p.Contains("Zero Day Piracy Protection") && p.Length > "Games for Windows LIVE".Length))
foundProtections = foundProtections.Where(p => p != "Games for Windows LIVE");
// Impulse Reactor
if (foundProtections.Any(p => p.StartsWith("Impulse Reactor Core Module")) && foundProtections.Any(p => p == "Impulse Reactor"))
foundProtections = foundProtections.Where(p => p != "Impulse Reactor");
// JoWood X-Prot
if (foundProtections.Any(p => p.StartsWith("JoWood X-Prot")))
{
if (foundProtections.Any(p => Regex.IsMatch(p, @"JoWood X-Prot [0-9]\.[0-9]\.[0-9]\.[0-9]{2}")))
{
foundProtections = foundProtections.Where(p => p != "JoWood X-Prot")
.Where(p => p != "JoWood X-Prot v1.0-v1.3")
.Where(p => p != "JoWood X-Prot v1.4+")
.Where(p => p != "JoWood X-Prot v2");
}
else if (foundProtections.Any(p => p == "JoWood X-Prot v2"))
{
foundProtections = foundProtections.Where(p => p != "JoWood X-Prot")
.Where(p => p != "JoWood X-Prot v1.0-v1.3")
.Where(p => p != "JoWood X-Prot v1.4+");
}
else if (foundProtections.Any(p => p == "JoWood X-Prot v1.4+"))
{
foundProtections = foundProtections.Where(p => p != "JoWood X-Prot")
.Where(p => p != "JoWood X-Prot v1.0-v1.3");
}
else if (foundProtections.Any(p => p == "JoWood X-Prot v1.0-v1.3"))
{
foundProtections = foundProtections.Where(p => p != "JoWood X-Prot");
}
}
// LaserLok
// TODO: Figure this one out
// Online Registration
foundProtections = foundProtections.Where(p => !p.StartsWith("Executable-Based Online Registration"));
// ProtectDISC / VOB ProtectCD/DVD
// TODO: Figure this one out
// SafeCast
// TODO: Figure this one out
// Cactus Data Shield / SafeDisc
if (foundProtections.Any(p => p == "Cactus Data Shield 300 (Confirm presence of other CDS-300 files)"))
{
foundProtections = foundProtections
.Where(p => p != "Cactus Data Shield 300 (Confirm presence of other CDS-300 files)");
if (foundProtections.Any(p => !p.StartsWith("SafeDisc")))
foundProtections = foundProtections.Append("Cactus Data Shield 300");
}
// SafeDisc
if (foundProtections.Any(p => p.StartsWith("SafeDisc")))
{
if (foundProtections.Any(p => Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}")))
{
foundProtections = foundProtections.Where(p => !p.StartsWith("Macrovision Protected Application"))
.Where(p => !p.StartsWith("Macrovision Protection File"))
.Where(p => !p.StartsWith("Macrovision Security Driver"))
.Where(p => p != "SafeDisc")
.Where(p => !(Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}-[0-9]\.[0-9]{2}\.[0-9]{3}")))
.Where(p => !(Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}/+")))
.Where(p => p != "SafeDisc 1/Lite")
.Where(p => p != "SafeDisc 2+");
}
else if (foundProtections.Any(p => Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}-[0-9]\.[0-9]{2}\.[0-9]{3}")))
{
foundProtections = foundProtections.Where(p => !p.StartsWith("Macrovision Protected Application"))
.Where(p => !p.StartsWith("Macrovision Protection File"))
.Where(p => !p.StartsWith("Macrovision Security Driver"))
.Where(p => p != "SafeDisc")
.Where(p => !(Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}/+")))
.Where(p => p != "SafeDisc 1/Lite")
.Where(p => p != "SafeDisc 2+");
}
else if (foundProtections.Any(p => Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}/+")))
{
foundProtections = foundProtections.Where(p => !p.StartsWith("Macrovision Protected Application"))
.Where(p => !p.StartsWith("Macrovision Protection File"))
.Where(p => !p.StartsWith("Macrovision Security Driver"))
.Where(p => p != "SafeDisc")
.Where(p => p != "SafeDisc 1/Lite")
.Where(p => p != "SafeDisc 2+");
}
else if (foundProtections.Any(p => p.StartsWith("Macrovision Security Driver")))
{
foundProtections = foundProtections.Where(p => !p.StartsWith("Macrovision Protected Application"))
.Where(p => !p.StartsWith("Macrovision Protection File"))
.Where(p => p != "SafeDisc")
.Where(p => p != "SafeDisc 1/Lite")
.Where(p => p != "SafeDisc 2+");
}
else if (foundProtections.Any(p => p == "SafeDisc 2+"))
{
foundProtections = foundProtections.Where(p => !p.StartsWith("Macrovision Protected Application"))
.Where(p => !p.StartsWith("Macrovision Protection File"))
.Where(p => p != "SafeDisc");
}
else if (foundProtections.Any(p => p == "SafeDisc 1/Lite"))
{
foundProtections = foundProtections.Where(p => !p.StartsWith("Macrovision Protected Application"))
.Where(p => !p.StartsWith("Macrovision Protection File"))
.Where(p => p != "SafeDisc");
}
}
// SecuROM
// TODO: Figure this one out
// SolidShield
// TODO: Figure this one out
// StarForce
if (foundProtections.Any(p => p.StartsWith("StarForce")))
{
if (foundProtections.Any(p => Regex.IsMatch(p, @"StarForce [0-9]+\..+")))
{
foundProtections = foundProtections.Where(p => p != "StarForce")
.Where(p => p != "StarForce 3-5")
.Where(p => p != "StarForce 5")
.Where(p => p != "StarForce 5 [Protected Module]");
}
else if (foundProtections.Any(p => p == "StarForce 5 [Protected Module]"))
{
foundProtections = foundProtections.Where(p => p != "StarForce")
.Where(p => p != "StarForce 3-5")
.Where(p => p != "StarForce 5");
}
else if (foundProtections.Any(p => p == "StarForce 5"))
{
foundProtections = foundProtections.Where(p => p != "StarForce")
.Where(p => p != "StarForce 3-5");
}
else if (foundProtections.Any(p => p == "StarForce 3-5"))
{
foundProtections = foundProtections.Where(p => p != "StarForce");
}
}
// Sysiphus
if (foundProtections.Any(p => p == "Sysiphus") && foundProtections.Any(p => p.StartsWith("Sysiphus") && p.Length > "Sysiphus".Length))
foundProtections = foundProtections.Where(p => p != "Sysiphus");
// TAGES
// TODO: Figure this one out
// XCP
if (foundProtections.Any(p => p == "XCP") && foundProtections.Any(p => p.StartsWith("XCP") && p.Length > "XCP".Length))
foundProtections = foundProtections.Where(p => p != "XCP");
return string.Join(", ", foundProtections);
}
}
}

View File

@@ -1,64 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MPF.Core.Converters;
namespace MPF.Core.UI.ComboBoxItems
{
/// <summary>
/// A generic combo box element
/// </summary>
/// <typeparam name="T">Enum type representing the possible values</typeparam>
public class Element<T> : IEquatable<Element<T>>, IElement where T : struct, Enum
{
private readonly T Data;
public Element(T data) => Data = data;
/// <summary>
/// Allow elements to be used as their internal enum type
/// </summary>
/// <param name="item"></param>
public static implicit operator T? (Element<T> item) => item?.Data;
/// <inheritdoc/>
public string Name => EnumConverter.GetLongName(Data);
public override string ToString() => Name;
/// <summary>
/// Internal enum value
/// </summary>
public T Value => Data;
/// <summary>
/// Determine if the item is selected or not
/// </summary>
/// <remarks>Only applies to CheckBox type</remarks>
public bool IsChecked { get; set; }
/// <summary>
/// Generate all elements associated with the data enum type
/// </summary>
/// <returns></returns>
public static IEnumerable<Element<T>> GenerateElements()
{
return Enum.GetValues(typeof(T))
.OfType<T>()
.Select(e => new Element<T>(e));
}
/// <inheritdoc/>
#if NET48
public bool Equals(Element<T> other)
#else
public bool Equals(Element<T>? other)
#endif
{
if (other == null)
return false;
return Name == other.Name;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,81 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MPF.Core.Data;
using MPF.Core.UI.ComboBoxItems;
using SabreTools.RedumpLib.Web;
namespace MPF.Core.UI.ViewModels
{
public class OptionsViewModel
{
#region Fields
/// <summary>
/// Current set of options
/// </summary>
public Options Options { get; }
/// <summary>
/// Flag for if settings were saved or not
/// </summary>
public bool SavedSettings { get; set; }
#endregion
#region Lists
/// <summary>
/// List of available internal programs
/// </summary>
public List<Element<InternalProgram>> InternalPrograms => PopulateInternalPrograms();
/// <summary>
/// Current list of supported system profiles
/// </summary>
public List<RedumpSystemComboBoxItem> Systems => RedumpSystemComboBoxItem.GenerateElements().ToList();
#endregion
/// <summary>
/// Constructor
/// </summary>
public OptionsViewModel(Options baseOptions)
{
Options = new Options(baseOptions);
}
#region Population
/// <summary>
/// Get a complete list of supported internal programs
/// </summary>
private static List<Element<InternalProgram>> PopulateInternalPrograms()
{
var internalPrograms = new List<InternalProgram> { InternalProgram.DiscImageCreator, InternalProgram.Aaru, InternalProgram.Redumper };
return internalPrograms.Select(ip => new Element<InternalProgram>(ip)).ToList();
}
#endregion
#region UI Commands
/// <summary>
/// Test Redump login credentials
/// </summary>
#if NET48
public (bool?, string) TestRedumpLogin(string username, string password)
#else
public async Task<(bool?, string?)> TestRedumpLogin(string username, string password)
#endif
{
#if NET48
return RedumpWebClient.ValidateCredentials(username, password);
#else
return await RedumpHttpClient.ValidateCredentials(username, password);
#endif
}
#endregion
}
}

View File

@@ -1,174 +0,0 @@
using System;
using System.IO;
namespace MPF.Core.Utilities
{
/// <summary>
/// Big endian reading overloads for BinaryReader
/// </summary>
public static class BinaryReaderExtensions
{
/// <summary>
/// Reads the specified number of bytes from the stream, starting from a specified point in the byte array.
/// </summary>
/// <param name="buffer">The buffer to read data into.</param>
/// <param name="index">The starting point in the buffer at which to begin reading into the buffer.</param>
/// <param name="count">The number of bytes to read.</param>
/// <returns>The number of bytes read into buffer. This might be less than the number of bytes requested if that many bytes are not available, or it might be zero if the end of the stream is reached.</returns>
public static int ReadBigEndian(this BinaryReader reader, byte[] buffer, int index, int count)
{
int retval = reader.Read(buffer, index, count);
Array.Reverse(buffer);
return retval;
}
/// <summary>
/// Reads the specified number of characters from the stream, starting from a specified point in the character array.
/// </summary>
/// <param name="buffer">The buffer to read data into.</param>
/// <param name="index">The starting point in the buffer at which to begin reading into the buffer.</param>
/// <param name="count">The number of characters to read.</param>
/// <returns>The total number of characters read into the buffer. This might be less than the number of characters requested if that many characters are not currently available, or it might be zero if the end of the stream is reached.</returns>
public static int ReadBigEndian(this BinaryReader reader, char[] buffer, int index, int count)
{
int retval = reader.Read(buffer, index, count);
Array.Reverse(buffer);
return retval;
}
/// <summary>
/// Reads the specified number of bytes from the current stream into a byte array and advances the current position by that number of bytes.
/// </summary>
/// <param name="count">The number of bytes to read. This value must be 0 or a non-negative number or an exception will occur.</param>
/// <returns>A byte array containing data read from the underlying stream. This might be less than the number of bytes requested if the end of the stream is reached.</returns>
public static byte[] ReadBytesBigEndian(this BinaryReader reader, int count)
{
byte[] retval = reader.ReadBytes(count);
Array.Reverse(retval);
return retval;
}
/// <summary>
/// Reads the specified number of characters from the current stream, returns the data in a character array, and advances the current position in accordance with the Encoding used and the specific character being read from the stream.
/// </summary>
/// <param name="count">The number of characters to read. This value must be 0 or a non-negative number or an exception will occur.</param>
/// <returns>A character array containing data read from the underlying stream. This might be less than the number of bytes requested if the end of the stream is reached.</returns>
public static char[] ReadCharsBigEndian(this BinaryReader reader, int count)
{
char[] retval = reader.ReadChars(count);
Array.Reverse(retval);
return retval;
}
/// <summary>
/// Reads a decimal value from the current stream and advances the current position of the stream by sixteen bytes.
/// </summary>
/// <returns>A decimal value read from the current stream.</returns>
public static decimal ReadDecimalBigEndian(this BinaryReader reader)
{
byte[] retval = reader.ReadBytes(16);
Array.Reverse(retval);
int i1 = BitConverter.ToInt32(retval, 0);
int i2 = BitConverter.ToInt32(retval, 4);
int i3 = BitConverter.ToInt32(retval, 8);
int i4 = BitConverter.ToInt32(retval, 12);
return new decimal(new int[] { i1, i2, i3, i4 });
}
/// <summary>
/// eads an 8-byte floating point value from the current stream and advances the current position of the stream by eight bytes.
/// </summary>
/// <returns>An 8-byte floating point value read from the current stream.</returns>
public static double ReadDoubleBigEndian(this BinaryReader reader)
{
byte[] retval = reader.ReadBytes(8);
Array.Reverse(retval);
return BitConverter.ToDouble(retval, 0);
}
/// <summary>
/// Reads a 2-byte signed integer from the current stream and advances the current position of the stream by two bytes.
/// </summary>
/// <returns>A 2-byte signed integer read from the current stream.</returns>
public static short ReadInt16BigEndian(this BinaryReader reader)
{
byte[] retval = reader.ReadBytes(2);
Array.Reverse(retval);
return BitConverter.ToInt16(retval, 0);
}
/// <summary>
/// Reads a 4-byte signed integer from the current stream and advances the current position of the stream by four bytes.
/// </summary>
/// <returns>A 4-byte signed integer read from the current stream.</returns>
public static int ReadInt32BigEndian(this BinaryReader reader)
{
byte[] retval = reader.ReadBytes(4);
Array.Reverse(retval);
return BitConverter.ToInt32(retval, 0);
}
/// <summary>
/// Reads an 8-byte signed integer from the current stream and advances the current position of the stream by eight bytes.
/// </summary>
/// <returns>An 8-byte signed integer read from the current stream.</returns>
public static long ReadInt64BigEndian(this BinaryReader reader)
{
byte[] retval = reader.ReadBytes(8);
Array.Reverse(retval);
return BitConverter.ToInt64(retval, 0);
}
/// <summary>
/// Reads a 4-byte floating point value from the current stream and advances the current position of the stream by four bytes.
/// </summary>
/// <returns>A 4-byte floating point value read from the current stream.</returns>
public static float ReadSingleBigEndian(this BinaryReader reader)
{
byte[] retval = reader.ReadBytes(4);
Array.Reverse(retval);
return BitConverter.ToSingle(retval, 0);
}
/// <summary>
/// Reads a 2-byte unsigned integer from the current stream using little-endian encoding and advances the position of the stream by two bytes.
///
/// This API is not CLS-compliant.
/// </summary>
/// <returns>A 2-byte unsigned integer read from this stream.</returns>
public static ushort ReadUInt16BigEndian(this BinaryReader reader)
{
byte[] retval = reader.ReadBytes(2);
Array.Reverse(retval);
return BitConverter.ToUInt16(retval, 0);
}
/// <summary>
/// Reads a 4-byte unsigned integer from the current stream and advances the position of the stream by four bytes.
///
/// This API is not CLS-compliant.
/// </summary>
/// <returns>A 4-byte unsigned integer read from this stream.</returns>
public static uint ReadUInt32BigEndian(this BinaryReader reader)
{
byte[] retval = reader.ReadBytes(4);
Array.Reverse(retval);
return BitConverter.ToUInt32(retval, 0);
}
/// <summary>
/// Reads an 8-byte unsigned integer from the current stream and advances the position of the stream by eight bytes.
///
/// This API is not CLS-compliant.
/// </summary>
/// <returns>An 8-byte unsigned integer read from this stream.</returns>
public static ulong ReadUInt64BigEndian(this BinaryReader reader)
{
byte[] retval = reader.ReadBytes(8);
Array.Reverse(retval);
return BitConverter.ToUInt64(retval, 0);
}
}
}

View File

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

View File

@@ -1,149 +0,0 @@
using System;
using System.Collections.Generic;
using MPF.Core.Converters;
using MPF.Core.Data;
using SabreTools.RedumpLib.Data;
namespace MPF.Core.Utilities
{
public static class EnumExtensions
{
/// <summary>
/// Determine if a system is okay if it's not detected by Windows
/// </summary>
/// <param name="system">RedumpSystem value to check</param>
/// <returns>True if Windows show see a disc when dumping, false otherwise</returns>
public static bool DetectedByWindows(this RedumpSystem? system)
{
switch (system)
{
case RedumpSystem.AmericanLaserGames3DO:
case RedumpSystem.AppleMacintosh:
case RedumpSystem.Atari3DO:
case RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem:
case RedumpSystem.NewJatreCDi:
case RedumpSystem.NintendoGameCube:
case RedumpSystem.NintendoWii:
case RedumpSystem.NintendoWiiU:
case RedumpSystem.PhilipsCDi:
case RedumpSystem.PhilipsCDiDigitalVideo:
case RedumpSystem.Panasonic3DOInteractiveMultiplayer:
case RedumpSystem.PanasonicM2:
case RedumpSystem.PioneerLaserActive:
case RedumpSystem.SuperAudioCD:
return false;
default:
return true;
}
}
/// <summary>
/// Determine if the media supports drive speeds
/// </summary>
/// <param name="type">MediaType value to check</param>
/// <returns>True if the media has variable dumping speeds, false otherwise</returns>
public static bool DoesSupportDriveSpeed(this MediaType? type)
{
switch (type)
{
case MediaType.CDROM:
case MediaType.DVD:
case MediaType.GDROM:
case MediaType.HDDVD:
case MediaType.BluRay:
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
return true;
default:
return false;
}
}
/// <summary>
/// Determine if a system has reversed ringcodes
/// </summary>
/// <param name="system">RedumpSystem value to check</param>
/// <returns>True if the system has reversed ringcodes, false otherwise</returns>
public static bool HasReversedRingcodes(this RedumpSystem? system)
{
switch (system)
{
case RedumpSystem.SonyPlayStation2:
case RedumpSystem.SonyPlayStation3:
case RedumpSystem.SonyPlayStation4:
//case RedumpSystem.SonyPlayStation5:
case RedumpSystem.SonyPlayStationPortable:
return true;
default:
return false;
}
}
/// <summary>
/// Determine if a system is considered audio-only
/// </summary>
/// <param name="system">RedumpSystem value to check</param>
/// <returns>True if the system is audio-only, false otherwise</returns>
/// <remarks>
/// Philips CD-i should NOT be in this list. It's being included until there's a
/// reasonable distinction between CD-i and CD-i ready on the database side.
/// </remarks>
public static bool IsAudio(this RedumpSystem? system)
{
switch (system)
{
case RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem:
case RedumpSystem.AudioCD:
case RedumpSystem.DVDAudio:
case RedumpSystem.HasbroiONEducationalGamingSystem:
case RedumpSystem.HasbroVideoNow:
case RedumpSystem.HasbroVideoNowColor:
case RedumpSystem.HasbroVideoNowJr:
case RedumpSystem.HasbroVideoNowXP:
case RedumpSystem.PhilipsCDi:
case RedumpSystem.PlayStationGameSharkUpdates:
case RedumpSystem.SuperAudioCD:
return true;
default:
return false;
}
}
/// <summary>
/// Determine if a system is considered XGD
/// </summary>
/// <param name="system">RedumpSystem value to check</param>
/// <returns>True if the system is XGD, false otherwise</returns>
public static bool IsXGD(this RedumpSystem? system)
{
switch (system)
{
case RedumpSystem.MicrosoftXbox:
case RedumpSystem.MicrosoftXbox360:
case RedumpSystem.MicrosoftXboxOne:
case RedumpSystem.MicrosoftXboxSeriesXS:
return true;
default:
return false;
}
}
/// <summary>
/// List all programs with their short usable names
/// </summary>
public static List<string> ListPrograms()
{
var programs = new List<string>();
foreach (var val in Enum.GetValues(typeof(InternalProgram)))
{
if (((InternalProgram)val) == InternalProgram.NONE)
continue;
programs.Add($"{((InternalProgram?)val).LongName()}");
}
return programs;
}
}
}

View File

@@ -1,133 +0,0 @@
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MPF.Core.Utilities
{
public static class Logging
{
/// <summary>
/// Process a chunk of text and send it to a handler
/// </summary>
/// <param name="reader">TextReader representing the input</param>
/// <param name="baseClass">Invoking class, passed on to the event handler</param>
/// <param name="handler">Event handler to be invoked to write to log</param>
#if NET48
public static async Task OutputToLog(TextReader reader, object baseClass, EventHandler<string> handler)
#else
public static async Task OutputToLog(TextReader reader, object baseClass, EventHandler<string>? handler)
#endif
{
// Initialize the required variables
char[] buffer = new char[256];
int read = 0;
var sb = new StringBuilder();
try
{
while (true)
{
// Try to read the next chunk of characters
read = await reader.ReadAsync(buffer, 0, buffer.Length);
if (read == 0)
{
Thread.Sleep(10);
continue;
}
// Convert the characters into a string
string line = new string(buffer, 0, read);
// If we have no newline characters, store in the string builder
if (!line.Contains("\r") && !line.Contains("\n"))
sb.Append(line);
// If we have a newline, append and log
else if (line.Contains("\n") || line.Contains("\r\n"))
ProcessNewLines(sb, line, baseClass, handler);
// If we have a carriage return only, append and log first and last instances
else if (line.Contains("\r"))
ProcessCarriageReturns(sb, line, baseClass, handler);
}
}
catch { }
finally
{
handler?.Invoke(baseClass, sb.ToString());
}
}
/// <summary>
/// Process a chunk that contains newlines
/// </summary>
/// <param name="sb">StringBuilder to write from and append to</param>
/// <param name="line">Current line to process</param>
/// <param name="baseClass">Invoking class, passed on to the event handler</param>
/// <param name="handler">Event handler to be invoked to write to log</param>
#if NET48
private static void ProcessNewLines(StringBuilder sb, string line, object baseClass, EventHandler<string> handler)
#else
private static void ProcessNewLines(StringBuilder sb, string line, object baseClass, EventHandler<string>? handler)
#endif
{
line = line.Replace("\r\n", "\n");
var split = line.Split('\n');
for (int i = 0; i < split.Length; i++)
{
// If the chunk contains a carriage return, handle it like a separate line
if (split[i].Contains("\r"))
{
ProcessCarriageReturns(sb, split[i], baseClass, handler);
continue;
}
// For the first item, append to anything existing and then write out
if (i == 0)
{
sb.Append(split[i]);
handler?.Invoke(baseClass, sb.ToString());
sb.Clear();
}
// For the last item, just append so it's dealt with the next time
else if (i == split.Length - 1)
{
sb.Append(split[i]);
}
// For everything else, directly write out
else
{
handler?.Invoke(baseClass, split[i]);
}
}
}
/// <summary>
/// Process a chunk that contains carriage returns
/// </summary>
/// <param name="sb">StringBuilder to write from and append to</param>
/// <param name="line">Current line to process</param>
/// <param name="baseClass">Invoking class, passed on to the event handler</param>
/// <param name="handler">Event handler to be invoked to write to log</param>
#if NET48
private static void ProcessCarriageReturns(StringBuilder sb, string line, object baseClass, EventHandler<string> handler)
#else
private static void ProcessCarriageReturns(StringBuilder sb, string line, object baseClass, EventHandler<string>? handler)
#endif
{
var split = line.Split('\r');
// Append and log the first
sb.Append(split[0]);
handler?.Invoke(baseClass, sb.ToString());
// Append the last
sb.Clear();
sb.Append($"\r{split[split.Length - 1]}");
}
}
}

View File

@@ -1,285 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using MPF.Core.Converters;
using MPF.Core.Data;
using Newtonsoft.Json;
using SabreTools.RedumpLib.Data;
namespace MPF.Core.Utilities
{
public static class OptionsLoader
{
private const string ConfigurationPath = "config.json";
#region Arguments
/// <summary>
/// Process any standalone arguments for the program
/// </summary>
/// <returns>True if one of the arguments was processed, false otherwise</returns>
public static bool? ProcessStandaloneArguments(string[] args)
{
// Help options
if (args.Length == 0 || args[0] == "-h" || args[0] == "-?")
return false;
// List options
if (args[0] == "-lm" || args[0] == "--listmedia")
{
Console.WriteLine("Supported Media Types:");
foreach (string mediaType in Extensions.ListMediaTypes())
{
Console.WriteLine(mediaType);
}
Console.ReadLine();
return true;
}
else if (args[0] == "-lp" || args[0] == "--listprograms")
{
Console.WriteLine("Supported Programs:");
foreach (string program in EnumExtensions.ListPrograms())
{
Console.WriteLine(program);
}
Console.ReadLine();
return true;
}
else if (args[0] == "-ls" || args[0] == "--listsystems")
{
Console.WriteLine("Supported Systems:");
foreach (string system in Extensions.ListSystems())
{
Console.WriteLine(system);
}
Console.ReadLine();
return true;
}
return false;
}
/// <summary>
/// Process common arguments for all functionality
/// </summary>
/// <returns>True if all arguments pass, false otherwise</returns>
#if NET48
public static (bool, MediaType, RedumpSystem?, string) ProcessCommonArguments(string[] args)
#else
public static (bool, MediaType, RedumpSystem?, string?) ProcessCommonArguments(string[] args)
#endif
{
// All other use requires at least 3 arguments
if (args.Length < 3)
return (false, MediaType.NONE, null, "Invalid number of arguments");
// Check the MediaType
var mediaType = EnumConverter.ToMediaType(args[0].Trim('"'));
if (mediaType == MediaType.NONE)
return (false, MediaType.NONE, null, $"{args[0]} is not a recognized media type");
// Check the RedumpSystem
var knownSystem = Extensions.ToRedumpSystem(args[1].Trim('"'));
if (knownSystem == null)
return (false, MediaType.NONE, null, $"{args[1]} is not a recognized system");
return (true, mediaType, knownSystem, null);
}
/// <summary>
/// Load the current set of options from application arguments
/// </summary>
#if NET48
public static (Options, SubmissionInfo, string, int) LoadFromArguments(string[] args, int startIndex = 0)
#else
public static (Options, SubmissionInfo?, string?, int) LoadFromArguments(string[] args, int startIndex = 0)
#endif
{
// Create the output values with defaults
var options = new Options()
{
RedumpUsername = null,
RedumpPassword = null,
InternalProgram = InternalProgram.NONE,
OutputSubmissionJSON = false,
CompressLogFiles = false,
};
// Create the submission info to return, if necessary
#if NET48
SubmissionInfo info = null;
string parsedPath = null;
#else
SubmissionInfo? info = null;
string? parsedPath = null;
#endif
// These values require multiple parts to be active
bool scan = false, protectFile = false;
// If we have no arguments, just return
if (args == null || args.Length == 0)
return (options, null, null, 0);
// If we have an invalid start index, just return
if (startIndex < 0 || startIndex >= args.Length)
return (options, null, null, startIndex);
// Loop through the arguments and parse out values
for (; startIndex < args.Length; startIndex++)
{
// Use specific program
if (args[startIndex].StartsWith("-u=") || args[startIndex].StartsWith("--use="))
{
string internalProgram = args[startIndex].Split('=')[1];
options.InternalProgram = EnumConverter.ToInternalProgram(internalProgram);
}
else if (args[startIndex] == "-u" || args[startIndex] == "--use")
{
string internalProgram = args[startIndex + 1];
options.InternalProgram = EnumConverter.ToInternalProgram(internalProgram);
startIndex++;
}
// Redump login
else if (args[startIndex].StartsWith("-c=") || args[startIndex].StartsWith("--credentials="))
{
string[] credentials = args[startIndex].Split('=')[1].Split(';');
options.RedumpUsername = credentials[0];
options.RedumpPassword = credentials[1];
}
else if (args[startIndex] == "-c" || args[startIndex] == "--credentials")
{
options.RedumpUsername = args[startIndex + 1];
options.RedumpPassword = args[startIndex + 2];
startIndex += 2;
}
// Pull all information (requires Redump login)
else if (args[startIndex].Equals("-a") || args[startIndex].Equals("--pull-all"))
{
options.PullAllInformation = true;
}
// Use a device path for physical checks
else if (args[startIndex].StartsWith("-p=") || args[startIndex].StartsWith("--path="))
{
parsedPath = args[startIndex].Split('=')[1];
}
else if (args[startIndex] == "-p" || args[startIndex] == "--path")
{
parsedPath = args[startIndex + 1];
startIndex++;
}
// Scan for protection (requires device path)
else if (args[startIndex].Equals("-s") || args[startIndex].Equals("--scan"))
{
scan = true;
}
// Output protection to separate file (requires scan for protection)
else if (args[startIndex].Equals("-f") || args[startIndex].Equals("--protect-file"))
{
protectFile = true;
}
// Include seed info file
if (args[startIndex].StartsWith("-l=") || args[startIndex].StartsWith("--load-seed="))
{
string seedInfo = args[startIndex].Split('=')[1];
info = InfoTool.CreateFromFile(seedInfo);
}
else if (args[startIndex] == "-l" || args[startIndex] == "--load-seed")
{
string seedInfo = args[startIndex + 1];
info = InfoTool.CreateFromFile(seedInfo);
startIndex++;
}
// 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;
}
}
// Now deal with the complex options
options.ScanForProtection = scan && !string.IsNullOrWhiteSpace(parsedPath);
options.OutputSeparateProtectionFile = scan && protectFile && !string.IsNullOrWhiteSpace(parsedPath);
return (options, info, parsedPath, startIndex);
}
/// <summary>
/// Return a list of supported arguments and descriptions
/// </summary>
public static List<string> PrintSupportedArguments()
{
var supportedArguments = new List<string>
{
"-u, --use <program> Dumping program output type [REQUIRED]",
"-c, --credentials <user> <pw> Redump username and password",
"-a, --pull-all Pull all information from Redump (requires --credentials)",
"-p, --path <drivepath> Physical drive path for additional checks",
"-s, --scan Enable copy protection scan (requires --path)",
"-f, --protect-file Output protection to separate file (requires --scan)",
"-l, --load-seed <path> Load a seed submission JSON for user information",
"-j, --json Enable submission JSON output",
"-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()
{
if (!File.Exists(ConfigurationPath))
{
_ = File.Create(ConfigurationPath);
return new Options();
}
var serializer = JsonSerializer.Create();
var reader = new StreamReader(ConfigurationPath);
#if NET48
var settings = serializer.Deserialize(reader, typeof(Dictionary<string, string>)) as Dictionary<string, string>;
#else
var settings = serializer.Deserialize(reader, typeof(Dictionary<string, string?>)) as Dictionary<string, string?>;
#endif
return new Options(settings);
}
/// <summary>
/// Save the current set of options to the application configuration
/// </summary>
public static void SaveToConfig(Options options)
{
var serializer = JsonSerializer.Create();
var sw = new StreamWriter(ConfigurationPath) { AutoFlush = true };
var writer = new JsonTextWriter(sw) { Formatting = Formatting.Indented };
serializer.Serialize(writer, options.Settings, typeof(Dictionary<string, string>));
}
#endregion
}
}

View File

@@ -1,238 +0,0 @@
using System;
using System.Reflection;
using MPF.Core.Data;
using Newtonsoft.Json.Linq;
using SabreTools.RedumpLib.Data;
namespace MPF.Core.Utilities
{
public static class Tools
{
#region Byte Arrays
/// <summary>
/// Search for a byte array in another array
/// </summary>
public static bool Contains(this byte[] stack, byte[] needle, out int position, int start = 0, int end = -1)
{
// Initialize the found position to -1
position = -1;
// If either array is null or empty, we can't do anything
if (stack == null || stack.Length == 0 || needle == null || needle.Length == 0)
return false;
// If the needle array is larger than the stack array, it can't be contained within
if (needle.Length > stack.Length)
return false;
// If start or end are not set properly, set them to defaults
if (start < 0)
start = 0;
if (end < 0)
end = stack.Length - needle.Length;
for (int i = start; i < end; i++)
{
if (stack.EqualAt(needle, i))
{
position = i;
return true;
}
}
return false;
}
/// <summary>
/// See if a byte array starts with another
/// </summary>
public static bool StartsWith(this byte[] stack, byte[] needle)
{
return stack.Contains(needle, out int _, start: 0, end: 1);
}
/// <summary>
/// Get if a stack at a certain index is equal to a needle
/// </summary>
private static bool EqualAt(this byte[] stack, byte[] needle, int index)
{
// If we're too close to the end of the stack, return false
if (needle.Length >= stack.Length - index)
return false;
for (int i = 0; i < needle.Length; i++)
{
if (stack[i + index] != needle[i])
return false;
}
return true;
}
#endregion
#region Support
/// <summary>
/// Verify that, given a system and a media type, they are correct
/// </summary>
public static Result GetSupportStatus(RedumpSystem? system, MediaType? type)
{
// No system chosen, update status
if (system == null)
return Result.Failure("Please select a valid system");
// If we're on an unsupported type, update the status accordingly
switch (type)
{
// Fully supported types
case MediaType.BluRay:
case MediaType.CDROM:
case MediaType.DVD:
case MediaType.FloppyDisk:
case MediaType.HardDisk:
case MediaType.CompactFlash:
case MediaType.SDCard:
case MediaType.FlashDrive:
case MediaType.HDDVD:
return Result.Success($"{type.LongName()} ready to dump");
// Partially supported types
case MediaType.GDROM:
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
return Result.Success($"{type.LongName()} partially supported for dumping");
// Special case for other supported tools
case MediaType.UMD:
return Result.Failure($"{type.LongName()} supported for submission info parsing");
// Specifically unknown type
case MediaType.NONE:
return Result.Failure($"Please select a valid media type");
// Undumpable but recognized types
default:
return Result.Failure($"{type.LongName()} media are not supported for dumping");
}
}
#endregion
#region Versioning
/// <summary>
/// Check for a new MPF version
/// </summary>
/// <returns>
/// Bool representing if the values are different.
/// String representing the message to display the the user.
/// String representing the new release URL.
/// </returns>
#if NET48
public static (bool different, string message, string url) CheckForNewVersion()
#else
public static (bool different, string message, string? url) CheckForNewVersion()
#endif
{
try
{
// Get current assembly version
var assemblyVersion = Assembly.GetEntryAssembly()?.GetName()?.Version;
if (assemblyVersion == null)
return (false, "Assembly version could not be determined", null);
string version = $"{assemblyVersion.Major}.{assemblyVersion.Minor}.{assemblyVersion.Build}";
// Get the latest tag from GitHub
var (tag, url) = GetRemoteVersionAndUrl();
bool different = version != tag;
string message = $"Local version: {version}"
+ $"{Environment.NewLine}Remote version: {tag}"
+ (different
? $"{Environment.NewLine}The update URL has been added copied to your clipboard"
: $"{Environment.NewLine}You have the newest version!");
return (different, message, url);
}
catch (Exception ex)
{
return (false, ex.ToString(), null);
}
}
/// <summary>
/// Get the current informational version formatted as a string
/// </summary>
#if NET48
public static string GetCurrentVersion()
#else
public static string? GetCurrentVersion()
#endif
{
try
{
var assembly = Assembly.GetEntryAssembly();
if (assembly == null)
return null;
var assemblyVersion = Attribute.GetCustomAttribute(assembly, typeof(AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute;
return assemblyVersion?.InformationalVersion;
}
catch (Exception ex)
{
return ex.ToString();
}
}
/// <summary>
/// Get the latest version of MPF from GitHub and the release URL
/// </summary>
#if NET48
private static (string tag, string url) GetRemoteVersionAndUrl()
#else
private static (string? tag, string? url) GetRemoteVersionAndUrl()
#endif
{
#if NET48
using (System.Net.WebClient wc = new System.Net.WebClient())
{
wc.Headers["User-Agent"] = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0";
// TODO: Figure out a better way than having this hardcoded...
string url = "https://api.github.com/repos/SabreTools/MPF/releases/latest";
string latestReleaseJsonString = wc.DownloadString(url);
var latestReleaseJson = JObject.Parse(latestReleaseJsonString);
string latestTag = latestReleaseJson["tag_name"].ToString();
string releaseUrl = latestReleaseJson["html_url"].ToString();
return (latestTag, releaseUrl);
}
#else
using (System.Net.Http.HttpClient hc = new System.Net.Http.HttpClient())
{
// TODO: Figure out a better way than having this hardcoded...
string url = "https://api.github.com/repos/SabreTools/MPF/releases/latest";
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, url);
message.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0");
var latestReleaseJsonString = hc.Send(message)?.Content?.ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult();
if (latestReleaseJsonString == null)
return (null, null);
var latestReleaseJson = JObject.Parse(latestReleaseJsonString);
if (latestReleaseJson == null)
return (null, null);
var latestTag = latestReleaseJson["tag_name"]?.ToString();
var releaseUrl = latestReleaseJson["html_url"]?.ToString();
return (latestTag, releaseUrl);
}
#endif
}
#endregion
}
}

View File

@@ -0,0 +1,517 @@
using System.Collections.Generic;
using MPF.ExecutionContexts.Aaru;
using SabreTools.RedumpLib.Data;
using Xunit;
namespace MPF.ExecutionContexts.Test
{
public class AaruTests
{
#region Converters.Extension
[Theory]
[InlineData(null, ".aaruf")]
[InlineData(MediaType.CDROM, ".aaruf")]
[InlineData(MediaType.GDROM, ".aaruf")]
[InlineData(MediaType.DVD, ".aaruf")]
[InlineData(MediaType.HDDVD, ".aaruf")]
[InlineData(MediaType.BluRay, ".aaruf")]
[InlineData(MediaType.FloppyDisk, ".aaruf")]
[InlineData(MediaType.HardDisk, ".aaruf")]
[InlineData(MediaType.ApertureCard, ".aaruf")]
public void ExtensionTest(MediaType? type, string expected)
{
string actual = Converters.Extension(type);
Assert.Equal(expected, actual);
}
#endregion
#region Default Values
private static readonly Dictionary<string, string?> AllOptions = new()
{
[SettingConstants.EnableDebug] = "true",
[SettingConstants.EnableVerbose] = "true",
[SettingConstants.ForceDumping] = "true",
[SettingConstants.RereadCount] = "1000",
[SettingConstants.StripPersonalData] = "true",
};
[Theory]
[InlineData(null, null, null, "filename.bin", null, null)]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.SegaDreamcast, MediaType.GDROM, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.BDVideo, MediaType.BluRay, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.NintendoWii, MediaType.NintendoWiiOpticalDisc, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.NintendoWiiU, MediaType.NintendoWiiUOpticalDisc, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.FloppyDisk, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
public void DefaultValueTest(RedumpSystem? system,
MediaType? type,
string? drivePath,
string filename,
int? driveSpeed,
string? expected)
{
var context = new ExecutionContext(system, type, drivePath, filename, driveSpeed, AllOptions);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
}
#endregion
#region Archive Family
[Theory]
[InlineData("arc info filename.bin")]
[InlineData("arc info \"filename.bin\"")]
[InlineData("archive info filename.bin")]
[InlineData("archive info \"filename.bin\"")]
public void ArchiveInfoTest(string parameters)
{
string? expected = "archive info \"filename.bin\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Database Family
[Theory]
[InlineData("db stats")]
[InlineData("database stats")]
public void DatabaseStatsTest(string parameters)
{
string? expected = "database stats";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
[Theory]
[InlineData("db update --clear --clear-all")]
[InlineData("db update --clear true --clear-all true")]
[InlineData("database update --clear --clear-all")]
[InlineData("database update --clear true --clear-all true")]
public void DatabaseUpdateTest(string parameters)
{
string? expected = "database update --clear True --clear-all True";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Device Family
[Theory]
[InlineData("dev info -w prefix filename.bin")]
[InlineData("dev info --output-prefix prefix filename.bin")]
[InlineData("device info -w prefix filename.bin")]
[InlineData("device info --output-prefix prefix filename.bin")]
public void DeviceInfoTest(string parameters)
{
string? expected = "device info --output-prefix \"prefix\" filename.bin";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
[Theory]
[InlineData("dev list localhost")]
[InlineData("device list localhost")]
public void DeviceListTest(string parameters)
{
string? expected = "device list \"localhost\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
[Theory]
[InlineData("dev report -t filename.bin")]
[InlineData("dev report -t true filename.bin")]
[InlineData("dev report --trap-disc filename.bin")]
[InlineData("dev report --trap-disc true filename.bin")]
[InlineData("device report -t filename.bin")]
[InlineData("device report -t true filename.bin")]
[InlineData("device report --trap-disc filename.bin")]
[InlineData("device report --trap-disc true filename.bin")]
public void DeviceReportTest(string parameters)
{
string? expected = "device report --trap-disc True filename.bin";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Filesystem Family
[Theory]
[InlineData("fi extract -e enc -x -n ns -O opts input output")]
[InlineData("fi extract -e enc -x true -n ns -O opts input output")]
[InlineData("fi extract --encoding enc --xattrs --namespace ns --options opts input output")]
[InlineData("fi extract --encoding enc --xattrs true --namespace ns --options opts input output")]
[InlineData("fs extract -e enc -x -n ns -O opts input output")]
[InlineData("fs extract -e enc -x true -n ns -O opts input output")]
[InlineData("fs extract --encoding enc --xattrs --namespace ns --options opts input output")]
[InlineData("fs extract --encoding enc --xattrs true --namespace ns --options opts input output")]
[InlineData("filesystem extract -e enc -x -n ns -O opts input output")]
[InlineData("filesystem extract -e enc -x true -n ns -O opts input output")]
[InlineData("filesystem extract --encoding enc --xattrs --namespace ns --options opts input output")]
[InlineData("filesystem extract --encoding enc --xattrs true --namespace ns --options opts input output")]
public void FilesystemExtractTest(string parameters)
{
string? expected = "filesystem extract --xattrs True --encoding \"enc\" --namespace \"ns\" --options \"opts\" \"input\" \"output\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
[Theory]
[InlineData("fi info -e enc -x -n ns -O opts input")]
[InlineData("fi info -e enc -x true -n ns -O opts input")]
[InlineData("fi info --encoding enc --xattrs --namespace ns --options opts input")]
[InlineData("fi info --encoding enc --xattrs true --namespace ns --options opts input")]
[InlineData("fs info -e enc -x -n ns -O opts input")]
[InlineData("fs info -e enc -x true -n ns -O opts input")]
[InlineData("fs info --encoding enc --xattrs --namespace ns --options opts input")]
[InlineData("fs info --encoding enc --xattrs true --namespace ns --options opts input")]
[InlineData("filesystem info -e enc -x -n ns -O opts input")]
[InlineData("filesystem info -e enc -x true -n ns -O opts input")]
[InlineData("filesystem info --encoding enc --xattrs --namespace ns --options opts input")]
[InlineData("filesystem info --encoding enc --xattrs true --namespace ns --options opts input")]
public void FilesystemInfoTest(string parameters)
{
string? expected = "filesystem info --xattrs True --encoding \"enc\" --namespace \"ns\" --options \"opts\" \"input\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
[Theory]
[InlineData("fi ls -e enc -f -l -p input")]
[InlineData("fi list -e enc -f -l -p input")]
[InlineData("fi ls -e enc -f true -l true -p true input")]
[InlineData("fi list -e enc -f true -l true -p true input")]
[InlineData("fi ls --encoding enc --filesystems --long-format --partitions input")]
[InlineData("fi list --encoding enc --filesystems --long-format --partitions input")]
[InlineData("fi ls --encoding enc --filesystems true --long-format true --partitions true input")]
[InlineData("fi list --encoding enc --filesystems true --long-format true --partitions true input")]
[InlineData("fs ls -e enc -f -l -p input")]
[InlineData("fs list -e enc -f -l -p input")]
[InlineData("fs ls -e enc -f true -l true -p true input")]
[InlineData("fs list -e enc -f true -l true -p true input")]
[InlineData("fs ls --encoding enc --filesystems --long-format --partitions input")]
[InlineData("fs list --encoding enc --filesystems --long-format --partitions input")]
[InlineData("fs ls --encoding enc --filesystems true --long-format true --partitions true input")]
[InlineData("fs list --encoding enc --filesystems true --long-format true --partitions true input")]
[InlineData("filesystem ls -e enc -f -l -p input")]
[InlineData("filesystem list -e enc -f -l -p input")]
[InlineData("filesystem ls -e enc -f true -l true -p true input")]
[InlineData("filesystem list -e enc -f true -l true -p true input")]
[InlineData("filesystem ls --encoding enc --filesystems --long-format --partitions input")]
[InlineData("filesystem list --encoding enc --filesystems --long-format --partitions input")]
[InlineData("filesystem ls --encoding enc --filesystems true --long-format true --partitions true input")]
[InlineData("filesystem list --encoding enc --filesystems true --long-format true --partitions true input")]
public void FilesystemListTest(string parameters)
{
string? expected = "filesystem list --filesystems True --long-format True --partitions True --encoding \"enc\" \"input\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
[Theory]
[InlineData("fi options")]
[InlineData("fs options")]
[InlineData("filesystem options")]
public void FilesystemOptionsTest(string parameters)
{
string? expected = "filesystem options";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Image Family
[Theory]
[InlineData("i chk -a --crc16 -c --crc64 --fletcher16 --fletcher32 -m -t -s --sha256 --sha384 --sha512 -f -w filename.bin")]
[InlineData("i chk -a true --crc16 true -c true --crc64 true --fletcher16 true --fletcher32 true -m true -t true -s true --sha256 true --sha384 true --sha512 true -f true -w true filename.bin")]
[InlineData("i chk --adler32 --crc16 --crc32 --crc64 --fletcher16 --fletcher32 --md5 --separated-tracks --sha1 --sha256 --sha384 --sha512 --spamsum --whole-disc filename.bin")]
[InlineData("i chk --adler32 true --crc16 true --crc32 true --crc64 true --fletcher16 true --fletcher32 true --md5 true --separated-tracks true --sha1 true --sha256 true --sha384 true --sha512 true --spamsum true --whole-disc true filename.bin")]
[InlineData("i checksum -a --crc16 -c --crc64 --fletcher16 --fletcher32 -m -t -s --sha256 --sha384 --sha512 -f -w filename.bin")]
[InlineData("i checksum -a true --crc16 true -c true --crc64 true --fletcher16 true --fletcher32 true -m true -t true -s true --sha256 true --sha384 true --sha512 true -f true -w true filename.bin")]
[InlineData("i checksum --adler32 --crc16 --crc32 --crc64 --fletcher16 --fletcher32 --md5 --separated-tracks --sha1 --sha256 --sha384 --sha512 --spamsum --whole-disc filename.bin")]
[InlineData("i checksum --adler32 true --crc16 true --crc32 true --crc64 true --fletcher16 true --fletcher32 true --md5 true --separated-tracks true --sha1 true --sha256 true --sha384 true --sha512 true --spamsum true --whole-disc true filename.bin")]
[InlineData("image chk -a --crc16 -c --crc64 --fletcher16 --fletcher32 -m -t -s --sha256 --sha384 --sha512 -f -w filename.bin")]
[InlineData("image chk -a true --crc16 true -c true --crc64 true --fletcher16 true --fletcher32 true -m true -t true -s true --sha256 true --sha384 true --sha512 true -f true -w true filename.bin")]
[InlineData("image chk --adler32 --crc16 --crc32 --crc64 --fletcher16 --fletcher32 --md5 --separated-tracks --sha1 --sha256 --sha384 --sha512 --spamsum --whole-disc filename.bin")]
[InlineData("image chk --adler32 true --crc16 true --crc32 true --crc64 true --fletcher16 true --fletcher32 true --md5 true --separated-tracks true --sha1 true --sha256 true --sha384 true --sha512 true --spamsum true --whole-disc true filename.bin")]
[InlineData("image checksum -a --crc16 -c --crc64 --fletcher16 --fletcher32 -m -t -s --sha256 --sha384 --sha512 -f -w filename.bin")]
[InlineData("image checksum -a true --crc16 true -c true --crc64 true --fletcher16 true --fletcher32 true -m true -t true -s true --sha256 true --sha384 true --sha512 true -f true -w true filename.bin")]
[InlineData("image checksum --adler32 --crc16 --crc32 --crc64 --fletcher16 --fletcher32 --md5 --separated-tracks --sha1 --sha256 --sha384 --sha512 --spamsum --whole-disc filename.bin")]
[InlineData("image checksum --adler32 true --crc16 true --crc32 true --crc64 true --fletcher16 true --fletcher32 true --md5 true --separated-tracks true --sha1 true --sha256 true --sha384 true --sha512 true --spamsum true --whole-disc true filename.bin")]
public void ImageChecksumTest(string parameters)
{
string? expected = "image checksum --adler32 True --crc16 True --crc32 True --crc64 True --fletcher16 True --fletcher32 True --md5 True --separated-tracks True --sha1 True --sha256 True --sha384 True --sha512 True --spamsum True --whole-disc True \"filename.bin\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
[Theory]
[InlineData("i cmp input1.bin input2.bin")]
[InlineData("i compare input1.bin input2.bin")]
[InlineData("image cmp input1.bin input2.bin")]
[InlineData("image compare input1.bin input2.bin")]
public void ImageCompareTest(string parameters)
{
string? expected = "image compare \"input1.bin\" \"input2.bin\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
[Theory]
[InlineData("i convert --comments co -c 0 --creator cr --drive-manufacturer dm --drive-model dm --drive-revision dr --drive-serial ds --fix-subchannel --fix-subchannel-crc --fix-subchannel-position -f -p fmt --generate-subchannels -g geo --media-barcode mb --media-lastsequence 0 --media-manufacturer mm --media-model mm --media-partnumber mpn --media-sequence 0 --media-serial ms --media-title mt -O opt -r resume -x cicm input1.bin input2.bin")]
[InlineData("i convert --comments co -c 0 --creator cr --drive-manufacturer dm --drive-model dm --drive-revision dr --drive-serial ds --fix-subchannel true --fix-subchannel-crc true --fix-subchannel-position true -f true -p fmt --generate-subchannels true -g geo --media-barcode mb --media-lastsequence 0 --media-manufacturer mm --media-model mm --media-partnumber mpn --media-sequence 0 --media-serial ms --media-title mt -O opt -r resume -x cicm input1.bin input2.bin")]
[InlineData("i convert --comments co --count 0 --creator cr --drive-manufacturer dm --drive-model dm --drive-revision dr --drive-serial ds --fix-subchannel --fix-subchannel-crc --fix-subchannel-position --force --format fmt --generate-subchannels --geometry geo --media-barcode mb --media-lastsequence 0 --media-manufacturer mm --media-model mm --media-partnumber mpn --media-sequence 0 --media-serial ms --media-title mt --options opt --resume-file resume --cicm-xml cicm input1.bin input2.bin")]
[InlineData("i convert --comments co --count 0 --creator cr --drive-manufacturer dm --drive-model dm --drive-revision dr --drive-serial ds --fix-subchannel true --fix-subchannel-crc true --fix-subchannel-position true --force true --format fmt --generate-subchannels true --geometry geo --media-barcode mb --media-lastsequence 0 --media-manufacturer mm --media-model mm --media-partnumber mpn --media-sequence 0 --media-serial ms --media-title mt --options opt --resume-file resume --cicm-xml cicm input1.bin input2.bin")]
[InlineData("image convert --comments co -c 0 --creator cr --drive-manufacturer dm --drive-model dm --drive-revision dr --drive-serial ds --fix-subchannel --fix-subchannel-crc --fix-subchannel-position -f -p fmt --generate-subchannels -g geo --media-barcode mb --media-lastsequence 0 --media-manufacturer mm --media-model mm --media-partnumber mpn --media-sequence 0 --media-serial ms --media-title mt -O opt -r resume -x cicm input1.bin input2.bin")]
[InlineData("image convert --comments co -c 0 --creator cr --drive-manufacturer dm --drive-model dm --drive-revision dr --drive-serial ds --fix-subchannel true --fix-subchannel-crc true --fix-subchannel-position true -f true -p fmt --generate-subchannels true -g geo --media-barcode mb --media-lastsequence 0 --media-manufacturer mm --media-model mm --media-partnumber mpn --media-sequence 0 --media-serial ms --media-title mt -O opt -r resume -x cicm input1.bin input2.bin")]
[InlineData("image convert --comments co --count 0 --creator cr --drive-manufacturer dm --drive-model dm --drive-revision dr --drive-serial ds --fix-subchannel --fix-subchannel-crc --fix-subchannel-position --force --format fmt --generate-subchannels --geometry geo --media-barcode mb --media-lastsequence 0 --media-manufacturer mm --media-model mm --media-partnumber mpn --media-sequence 0 --media-serial ms --media-title mt --options opt --resume-file resume --cicm-xml cicm input1.bin input2.bin")]
[InlineData("image convert --comments co --count 0 --creator cr --drive-manufacturer dm --drive-model dm --drive-revision dr --drive-serial ds --fix-subchannel true --fix-subchannel-crc true --fix-subchannel-position true --force true --format fmt --generate-subchannels true --geometry geo --media-barcode mb --media-lastsequence 0 --media-manufacturer mm --media-model mm --media-partnumber mpn --media-sequence 0 --media-serial ms --media-title mt --options opt --resume-file resume --cicm-xml cicm input1.bin input2.bin")]
public void ImageConvertTest(string parameters)
{
string? expected = "image convert --fix-subchannel True --fix-subchannel-crc True --fix-subchannel-position True --force True --generate-subchannels True --count 0 --media-lastsequence 0 --media-sequence 0 --comments \"co\" --creator \"cr\" --drive-manufacturer \"dm\" --drive-model \"dm\" --drive-revision \"dr\" --drive-serial \"ds\" --format \"fmt\" --geometry \"geo\" --media-barcode \"mb\" --media-manufacturer \"mm\" --media-model \"mm\" --media-partnumber \"mpn\" --media-serial \"ms\" --media-title \"mt\" --options \"opt\" --resume-file \"resume\" --cicm-xml \"cicm\" \"input1.bin\" \"input2.bin\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
[Theory]
[InlineData("i create-sidecar -b 0 -e enc -t filename.bin")]
[InlineData("i create-sidecar -b 0 -e enc -t true filename.bin")]
[InlineData("i create-sidecar --block-size 0 --encoding enc --tape filename.bin")]
[InlineData("i create-sidecar --block-size 0 --encoding enc --tape true filename.bin")]
[InlineData("image create-sidecar -b 0 -e enc -t filename.bin")]
[InlineData("image create-sidecar -b 0 -e enc -t true filename.bin")]
[InlineData("image create-sidecar --block-size 0 --encoding enc --tape filename.bin")]
[InlineData("image create-sidecar --block-size 0 --encoding enc --tape true filename.bin")]
public void ImageCreateSidecarTest(string parameters)
{
string? expected = "image create-sidecar --tape True --block-size 0 --encoding \"enc\" \"filename.bin\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
[Theory]
[InlineData("i decode -f -l all -p -s 0 filename.bin")]
[InlineData("i decode -f true -l all -p true -s 0 filename.bin")]
[InlineData("i decode --disk-tags --length all --sector-tags --start 0 filename.bin")]
[InlineData("i decode --disk-tags true --length all --sector-tags true --start 0 filename.bin")]
[InlineData("image decode -f -l all -p -s 0 filename.bin")]
[InlineData("image decode -f true -l all -p true -s 0 filename.bin")]
[InlineData("image decode --disk-tags --length all --sector-tags --start 0 filename.bin")]
[InlineData("image decode --disk-tags true --length all --sector-tags true --start 0 filename.bin")]
public void ImageDecodeTest(string parameters)
{
string? expected = "image decode --disk-tags True --sector-tags True --length all --start 0 \"filename.bin\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
[Theory]
[InlineData("i entropy -p -t -w filename.bin")]
[InlineData("i entropy -p true -t true -w true filename.bin")]
[InlineData("i entropy --duplicated-sectors --separated-tracks --whole-disc filename.bin")]
[InlineData("i entropy --duplicated-sectors true --separated-tracks true --whole-disc true filename.bin")]
[InlineData("image entropy -p -t -w filename.bin")]
[InlineData("image entropy -p true -t true -w true filename.bin")]
[InlineData("image entropy --duplicated-sectors --separated-tracks --whole-disc filename.bin")]
[InlineData("image entropy --duplicated-sectors true --separated-tracks true --whole-disc true filename.bin")]
public void ImageEntropyTest(string parameters)
{
string? expected = "image entropy --duplicated-sectors True --separated-tracks True --whole-disc True \"filename.bin\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
[Theory]
[InlineData("i info filename.bin")]
[InlineData("image info filename.bin")]
public void ImageInfoTest(string parameters)
{
string? expected = "image info \"filename.bin\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
[Theory]
[InlineData("i options")]
[InlineData("image options")]
public void ImageOptionsTest(string parameters)
{
string? expected = "image options";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
[Theory]
[InlineData("i print -l 0 -r -s 0 -w 0 filename.bin")]
[InlineData("i print -l 0 -r true -s 0 -w 0 filename.bin")]
[InlineData("i print --length 0 --long-sectors --start 0 --width 0 filename.bin")]
[InlineData("i print --length 0 --long-sectors true --start 0 --width 0 filename.bin")]
[InlineData("image print -l 0 -r -s 0 -w 0 filename.bin")]
[InlineData("image print -l 0 -r true -s 0 -w 0 filename.bin")]
[InlineData("image print --length 0 --long-sectors --start 0 --width 0 filename.bin")]
[InlineData("image print --length 0 --long-sectors true --start 0 --width 0 filename.bin")]
public void ImagePrintTest(string parameters)
{
string? expected = "image print --long-sectors True --width 0 --length 0 --start 0 \"filename.bin\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
[Theory]
[InlineData("i verify -w -s filename.bin")]
[InlineData("i verify -w true -s true filename.bin")]
[InlineData("i verify --verify-disc --verify-sectors filename.bin")]
[InlineData("i verify --verify-disc true --verify-sectors true filename.bin")]
[InlineData("image verify -w -s filename.bin")]
[InlineData("image verify -w true -s true filename.bin")]
[InlineData("image verify --verify-disc --verify-sectors filename.bin")]
[InlineData("image verify --verify-disc true --verify-sectors true filename.bin")]
public void ImageVerifyTest(string parameters)
{
string? expected = "image verify --verify-disc True --verify-sectors True \"filename.bin\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Media Family
[Theory]
[InlineData("m dump --eject -e enc --first-pregap --fix-offset --fix-subchannel --fix-subchannel-crc --fix-subchannel-position -f --generate-subchannels --max-blocks 0 --metadata -O opt --persistent --private -r -p 0 --retry-subchannel -k 0 --skip-cdiready-hole --speed 0 -s --store-encrypted --subchannel any --title-keys --trim --use-buffered-reads -x cicm input output.bin")]
[InlineData("m dump --eject true -e enc --first-pregap true --fix-offset true --fix-subchannel true --fix-subchannel-crc true --fix-subchannel-position true -f true --generate-subchannels true --max-blocks 0 --metadata true -O opt --persistent true --private true -r true -p 0 --retry-subchannel true -k 0 --skip-cdiready-hole true --speed 0 -s true --store-encrypted true --subchannel any --title-keys true --trim true --use-buffered-reads true -x cicm input output.bin")]
[InlineData("m dump --eject --encoding enc --first-pregap --fix-offset --fix-subchannel --fix-subchannel-crc --fix-subchannel-position --force --generate-subchannels --max-blocks 0 --metadata --options opt --persistent --private --resume --retry-passes 0 --retry-subchannel --skip 0 --skip-cdiready-hole --speed 0 --stop-on-error --store-encrypted --subchannel any --title-keys --trim --use-buffered-reads --cicm-xml cicm input output.bin")]
[InlineData("m dump --eject true --encoding enc --first-pregap true --fix-offset true --fix-subchannel true --fix-subchannel-crc true --fix-subchannel-position true --force true --generate-subchannels true --max-blocks 0 --metadata true --options opt --persistent true --private true --resume true --retry-passes 0 --retry-subchannel true --skip 0 --skip-cdiready-hole true --speed 0 --stop-on-error true --store-encrypted true --subchannel any --title-keys true --trim true --use-buffered-reads true --cicm-xml cicm input output.bin")]
[InlineData("media dump --eject -e enc --first-pregap --fix-offset --fix-subchannel --fix-subchannel-crc --fix-subchannel-position -f --generate-subchannels --max-blocks 0 --metadata -O opt --persistent --private -r -p 0 --retry-subchannel -k 0 --skip-cdiready-hole --speed 0 -s --store-encrypted --subchannel any --title-keys --trim --use-buffered-reads -x cicm input output.bin")]
[InlineData("media dump --eject true -e enc --first-pregap true --fix-offset true --fix-subchannel true --fix-subchannel-crc true --fix-subchannel-position true -f true --generate-subchannels true --max-blocks 0 --metadata true -O opt --persistent true --private true -r true -p 0 --retry-subchannel true -k 0 --skip-cdiready-hole true --speed 0 -s true --store-encrypted true --subchannel any --title-keys true --trim true --use-buffered-reads true -x cicm input output.bin")]
[InlineData("media dump --eject --encoding enc --first-pregap --fix-offset --fix-subchannel --fix-subchannel-crc --fix-subchannel-position --force --generate-subchannels --max-blocks 0 --metadata --options opt --persistent --private --resume --retry-passes 0 --retry-subchannel --skip 0 --skip-cdiready-hole --speed 0 --stop-on-error --store-encrypted --subchannel any --title-keys --trim --use-buffered-reads --cicm-xml cicm input output.bin")]
[InlineData("media dump --eject true --encoding enc --first-pregap true --fix-offset true --fix-subchannel true --fix-subchannel-crc true --fix-subchannel-position true --force true --generate-subchannels true --max-blocks 0 --metadata true --options opt --persistent true --private true --resume true --retry-passes 0 --retry-subchannel true --skip 0 --skip-cdiready-hole true --speed 0 --stop-on-error true --store-encrypted true --subchannel any --title-keys true --trim true --use-buffered-reads true --cicm-xml cicm input output.bin")]
public void MediaDumpTest(string parameters)
{
string? expected = "media dump --eject True --first-pregap True --fix-offset True --fix-subchannel True --fix-subchannel-crc True --fix-subchannel-position True --force True --generate-subchannels True --metadata True --persistent True --private True --resume True --retry-subchannel True --skip-cdiready-hole True --stop-on-error True --store-encrypted True --title-keys True --trim True --use-buffered-reads True --speed 0 --retry-passes 0 --max-blocks 0 --skip 0 --encoding \"enc\" --options \"opt\" --subchannel \"any\" --cicm-xml \"cicm\" input \"output.bin\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
[Theory]
[InlineData("m info -w prefix input")]
[InlineData("m info --output-prefix prefix input")]
[InlineData("media info -w prefix input")]
[InlineData("media info --output-prefix prefix input")]
public void MediaInfoTest(string parameters)
{
string? expected = "media info --output-prefix \"prefix\" input";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
[Theory]
[InlineData("m scan -b ibg -m mhdd --use-buffered-reads input")]
[InlineData("m scan -b ibg -m mhdd --use-buffered-reads true input")]
[InlineData("m scan --ibg-log ibg --mhdd-log mhdd --use-buffered-reads input")]
[InlineData("m scan --ibg-log ibg --mhdd-log mhdd --use-buffered-reads true input")]
[InlineData("media scan -b ibg -m mhdd --use-buffered-reads input")]
[InlineData("media scan -b ibg -m mhdd --use-buffered-reads true input")]
[InlineData("media scan --ibg-log ibg --mhdd-log mhdd --use-buffered-reads input")]
[InlineData("media scan --ibg-log ibg --mhdd-log mhdd --use-buffered-reads true input")]
public void MediaScanTest(string parameters)
{
string? expected = "media scan --use-buffered-reads True --ibg-log \"ibg\" --mhdd-log \"mhdd\" input";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Standalone Commands
[Theory]
[InlineData("--debug --help --verbose --version formats")]
[InlineData("--debug true --help true --verbose true --version true formats")]
public void PreCommandFlagsTest(string parameters)
{
string? expected = "--debug True --help True --verbose True --version True formats";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
[Theory]
[InlineData("configure", "configure")]
[InlineData("formats", "formats")]
[InlineData("list-encodings", "list-encodings")]
[InlineData("list-namespaces", "list-namespaces")]
[InlineData("remote localhost", "remote \"localhost\"")]
public void StandaloneCommandsTest(string parameters, string? expected)
{
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
}
}

View File

@@ -0,0 +1,464 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Xunit;
namespace MPF.ExecutionContexts.Test
{
public class BaseExecutionContextTests
{
#region GetBooleanSetting
[Fact]
public void GetBooleanSetting_InvalidDict_Default()
{
Dictionary<string, string?> settings = [];
string key = "key";
bool defaultValue = false;
bool actual = BaseExecutionContext.GetBooleanSetting(settings, key, defaultValue);
Assert.False(actual);
}
[Fact]
public void GetBooleanSetting_InvalidKey_Default()
{
Dictionary<string, string?> settings = new()
{
["key2"] = "true",
};
string key = "key";
bool defaultValue = false;
bool actual = BaseExecutionContext.GetBooleanSetting(settings, key, defaultValue);
Assert.False(actual);
}
[Fact]
public void GetBooleanSetting_NullValue_Default()
{
Dictionary<string, string?> settings = new()
{
["key"] = null,
};
string key = "key";
bool defaultValue = false;
bool actual = BaseExecutionContext.GetBooleanSetting(settings, key, defaultValue);
Assert.False(actual);
}
[Fact]
public void GetBooleanSetting_InvalidValue_Default()
{
Dictionary<string, string?> settings = new()
{
["key"] = "invalid",
};
string key = "key";
bool defaultValue = false;
bool actual = BaseExecutionContext.GetBooleanSetting(settings, key, defaultValue);
Assert.False(actual);
}
[Fact]
public void GetBooleanSetting_ValidValue_Parsed()
{
Dictionary<string, string?> settings = new()
{
["key"] = "true",
};
string key = "key";
bool defaultValue = false;
bool actual = BaseExecutionContext.GetBooleanSetting(settings, key, defaultValue);
Assert.True(actual);
}
#endregion
#region GetInt32Setting
[Fact]
public void GetInt32Setting_InvalidDict_Default()
{
Dictionary<string, string?> settings = [];
string key = "key";
int defaultValue = -1;
int actual = BaseExecutionContext.GetInt32Setting(settings, key, defaultValue);
Assert.Equal(-1, actual);
}
[Fact]
public void GetInt32Setting_InvalidKey_Default()
{
Dictionary<string, string?> settings = new()
{
["key2"] = "12345",
};
string key = "key";
int defaultValue = -1;
int actual = BaseExecutionContext.GetInt32Setting(settings, key, defaultValue);
Assert.Equal(-1, actual);
}
[Fact]
public void GetInt32Setting_NullValue_Default()
{
Dictionary<string, string?> settings = new()
{
["key"] = null,
};
string key = "key";
int defaultValue = -1;
int actual = BaseExecutionContext.GetInt32Setting(settings, key, defaultValue);
Assert.Equal(-1, actual);
}
[Fact]
public void GetInt32Setting_InvalidValue_Default()
{
Dictionary<string, string?> settings = new()
{
["key"] = "invalid",
};
string key = "key";
int defaultValue = -1;
int actual = BaseExecutionContext.GetInt32Setting(settings, key, defaultValue);
Assert.Equal(-1, actual);
}
[Fact]
public void GetInt32Setting_ValidValue_Parsed()
{
int expected = 12345;
Dictionary<string, string?> settings = new()
{
["key"] = "12345",
};
string key = "key";
int defaultValue = -1;
int actual = BaseExecutionContext.GetInt32Setting(settings, key, defaultValue);
Assert.Equal(expected, actual);
}
#endregion
#region GetStringSetting
[Fact]
public void GetStringSetting_InvalidDict_Default()
{
Dictionary<string, string?> settings = [];
string key = "key";
string? defaultValue = null;
string? actual = BaseExecutionContext.GetStringSetting(settings, key, defaultValue);
Assert.Null(actual);
}
[Fact]
public void GetStringSetting_InvalidKey_Default()
{
Dictionary<string, string?> settings = new()
{
["key2"] = "12345",
};
string key = "key";
string? defaultValue = null;
string? actual = BaseExecutionContext.GetStringSetting(settings, key, defaultValue);
Assert.Null(actual);
}
[Fact]
public void GetStringSetting_ValidValue_Rturned()
{
string expected = "expected";
Dictionary<string, string?> settings = new()
{
["key"] = "expected",
};
string key = "key";
string? defaultValue = null;
string? actual = BaseExecutionContext.GetStringSetting(settings, key, defaultValue);
Assert.Equal(expected, actual);
}
#endregion
#region SplitParameterString
[Fact]
public void SplitParameterString_Empty_Empty()
{
string parameters = string.Empty;
string[] actual = BaseExecutionContext.SplitParameterString(parameters);
Assert.Empty(actual);
}
[Fact]
public void SplitParameterString_NoSplit_Single()
{
string expected = "single";
string parameters = "single";
string[] actual = BaseExecutionContext.SplitParameterString(parameters);
var p0 = Assert.Single(actual);
Assert.Equal(expected, p0);
}
[Fact]
public void SplitParameterString_SplitNoEquals_Multiple()
{
string[] expected = ["-flag1", "value1", "-flag2"];
string parameters = "-flag1 value1 -flag2";
string[] actual = BaseExecutionContext.SplitParameterString(parameters);
Assert.True(expected.SequenceEqual(actual));
}
[Fact]
public void SplitParameterString_SplitEquals_Multiple()
{
string[] expected = ["-flag1=value1", "-flag2"];
string parameters = "-flag1=value1 -flag2";
string[] actual = BaseExecutionContext.SplitParameterString(parameters);
Assert.True(expected.SequenceEqual(actual));
}
[Fact]
public void SplitParameterString_SplitNoEqualsQuotes_Multiple()
{
string[] expected = ["-flag1", "\"value1 value2\"", "-flag2"];
string parameters = "-flag1 \"value1 value2\" -flag2";
string[] actual = BaseExecutionContext.SplitParameterString(parameters);
Assert.True(expected.SequenceEqual(actual));
}
[Fact]
public void SplitParameterString_SplitEqualsQuotes_Multiple()
{
string[] expected = ["-flag1=\"value1 value2\"", "-flag2"];
string parameters = "-flag1=\"value1 value2\" -flag2";
string[] actual = BaseExecutionContext.SplitParameterString(parameters);
Assert.True(expected.SequenceEqual(actual));
}
#endregion
#region DoesExist
[Fact]
public void DoesExist_Empty_False()
{
string[] parts = [];
int index = 0;
bool actual = BaseExecutionContext.DoesExist(parts, index);
Assert.False(actual);
}
[Fact]
public void DoesExist_Negative_False()
{
string[] parts = ["item"];
int index = -1;
bool actual = BaseExecutionContext.DoesExist(parts, index);
Assert.False(actual);
}
[Fact]
public void DoesExist_Greater_False()
{
string[] parts = ["item"];
int index = 1;
bool actual = BaseExecutionContext.DoesExist(parts, index);
Assert.False(actual);
}
[Fact]
public void DoesExist_Valid_True()
{
string[] parts = ["item"];
int index = 0;
bool actual = BaseExecutionContext.DoesExist(parts, index);
Assert.True(actual);
}
#endregion
#region IsValidBool
[Theory]
[InlineData("", false)]
[InlineData("true", true)]
[InlineData("True", true)]
[InlineData("TRUE", true)]
[InlineData("Yes", false)]
[InlineData("false", true)]
[InlineData("False", true)]
[InlineData("FALSE", true)]
[InlineData("No", false)]
[InlineData("Invalid", false)]
public void IsValidBoolTest(string parameter, bool expected)
{
bool actual = BaseExecutionContext.IsValidBool(parameter);
Assert.Equal(expected, actual);
}
#endregion
#region IsValidInt8
[Theory]
[InlineData("", null, null, false)]
[InlineData("", (sbyte)0, (sbyte)1, false)]
[InlineData("", (sbyte)0, sbyte.MaxValue, false)]
[InlineData("-2", null, null, true)]
[InlineData("-2", (sbyte)0, (sbyte)1, false)]
[InlineData("-2", (sbyte)0, sbyte.MaxValue, false)]
[InlineData("0", null, null, true)]
[InlineData("0", (sbyte)0, (sbyte)1, true)]
[InlineData("0", (sbyte)0, sbyte.MaxValue, true)]
[InlineData("2", null, null, true)]
[InlineData("2", (sbyte)0, (sbyte)1, false)]
[InlineData("2", (sbyte)0, sbyte.MaxValue, true)]
[InlineData("Invalid", null, null, false)]
[InlineData("Invalid", (sbyte)0, (sbyte)1, false)]
[InlineData("Invalid", (sbyte)0, sbyte.MaxValue, false)]
public void IsValidInt8Test(string parameter, sbyte? lowerBound, sbyte? upperBound, bool expected)
{
bool actual = BaseExecutionContext.IsValidInt8(parameter, lowerBound, upperBound);
Assert.Equal(expected, actual);
}
#endregion
#region IsValidInt16
[Theory]
[InlineData("", null, null, false)]
[InlineData("", (short)0, (short)1, false)]
[InlineData("", (short)0, short.MaxValue, false)]
[InlineData("-2", null, null, true)]
[InlineData("-2", (short)0, (short)1, false)]
[InlineData("-2", (short)0, short.MaxValue, false)]
[InlineData("0", null, null, true)]
[InlineData("0", (short)0, (short)1, true)]
[InlineData("0", (short)0, short.MaxValue, true)]
[InlineData("2", null, null, true)]
[InlineData("2", (short)0, (short)1, false)]
[InlineData("2", (short)0, short.MaxValue, true)]
[InlineData("Invalid", null, null, false)]
[InlineData("Invalid", (short)0, (short)1, false)]
[InlineData("Invalid", (short)0, short.MaxValue, false)]
public void IsValidInt16Test(string parameter, short? lowerBound, short? upperBound, bool expected)
{
bool actual = BaseExecutionContext.IsValidInt16(parameter, lowerBound, upperBound);
Assert.Equal(expected, actual);
}
#endregion
#region IsValidInt32
[Theory]
[InlineData("", null, null, false)]
[InlineData("", (int)0, (int)1, false)]
[InlineData("", (int)0, int.MaxValue, false)]
[InlineData("-2", null, null, true)]
[InlineData("-2", (int)0, (int)1, false)]
[InlineData("-2", (int)0, int.MaxValue, false)]
[InlineData("0", null, null, true)]
[InlineData("0", (int)0, (int)1, true)]
[InlineData("0", (int)0, int.MaxValue, true)]
[InlineData("2", null, null, true)]
[InlineData("2", (int)0, (int)1, false)]
[InlineData("2", (int)0, int.MaxValue, true)]
[InlineData("Invalid", null, null, false)]
[InlineData("Invalid", (int)0, (int)1, false)]
[InlineData("Invalid", (int)0, int.MaxValue, false)]
public void IsValidInt32Test(string parameter, int? lowerBound, int? upperBound, bool expected)
{
bool actual = BaseExecutionContext.IsValidInt32(parameter, lowerBound, upperBound);
Assert.Equal(expected, actual);
}
#endregion
#region IsValidInt64
[Theory]
[InlineData("", null, null, false)]
[InlineData("", (long)0, (long)1, false)]
[InlineData("", (long)0, long.MaxValue, false)]
[InlineData("-2", null, null, true)]
[InlineData("-2", (long)0, (long)1, false)]
[InlineData("-2", (long)0, long.MaxValue, false)]
[InlineData("0", null, null, true)]
[InlineData("0", (long)0, (long)1, true)]
[InlineData("0", (long)0, long.MaxValue, true)]
[InlineData("2", null, null, true)]
[InlineData("2", (long)0, (long)1, false)]
[InlineData("2", (long)0, long.MaxValue, true)]
[InlineData("Invalid", null, null, false)]
[InlineData("Invalid", (long)0, (long)1, false)]
[InlineData("Invalid", (long)0, long.MaxValue, false)]
public void IsValidInt64Test(string parameter, long? lowerBound, long? upperBound, bool expected)
{
bool actual = BaseExecutionContext.IsValidInt64(parameter, lowerBound, upperBound);
Assert.Equal(expected, actual);
}
#endregion
#region ExtractFactorFromValue
[Theory]
[InlineData("1", "1", 1)]
[InlineData("1c", "1", 1)]
[InlineData("1w", "1", 2)]
[InlineData("1d", "1", 4)]
[InlineData("1q", "1", 8)]
[InlineData("1k", "1", 1024)]
[InlineData("1M", "1", 1024 * 1024)]
[InlineData("1G", "1", 1024 * 1024 * 1024)]
public void ExtractFactorFromValueTest(string value, string expected, long expectedFactor)
{
string actual = BaseExecutionContext.ExtractFactorFromValue(value, out long factor);
Assert.Equal(expected, actual);
Assert.Equal(expectedFactor, factor);
}
#endregion
#region RemoveHexIdentifier
[Theory]
[InlineData("", "")]
[InlineData("0", "0")]
[InlineData("00", "00")]
[InlineData("0x", "0x")]
[InlineData("0X", "0X")]
[InlineData("A", "A")]
[InlineData("A0", "A0")]
[InlineData("Ax", "Ax")]
[InlineData("AX", "AX")]
[InlineData("012345", "012345")]
[InlineData("0x12345", "12345")]
[InlineData("0X12345", "12345")]
public void RemoveHexIdentifierTest(string value, string expected)
{
string actual = BaseExecutionContext.RemoveHexIdentifier(value);
Assert.Equal(expected, actual);
}
#endregion
}
}

View File

@@ -0,0 +1,480 @@
using System.Collections.Generic;
using MPF.ExecutionContexts.DiscImageCreator;
using SabreTools.RedumpLib.Data;
using Xunit;
namespace MPF.ExecutionContexts.Test
{
public class DiscImageCreatorTests
{
// TODO: Add Converters.ToRedumpSystem test
// TODO: Add Converters.ToMediaType test
#region Converters.Extension
[Theory]
[InlineData(null, null)]
[InlineData(MediaType.CDROM, ".bin")]
[InlineData(MediaType.GDROM, ".bin")]
[InlineData(MediaType.Cartridge, ".bin")]
[InlineData(MediaType.HardDisk, ".bin")]
[InlineData(MediaType.CompactFlash, ".bin")]
[InlineData(MediaType.MMC, ".bin")]
[InlineData(MediaType.SDCard, ".bin")]
[InlineData(MediaType.FlashDrive, ".bin")]
[InlineData(MediaType.DVD, ".iso")]
[InlineData(MediaType.HDDVD, ".iso")]
[InlineData(MediaType.BluRay, ".iso")]
[InlineData(MediaType.NintendoWiiOpticalDisc, ".iso")]
[InlineData(MediaType.LaserDisc, ".raw")]
[InlineData(MediaType.NintendoGameCubeGameDisc, ".raw")]
[InlineData(MediaType.NintendoWiiUOpticalDisc, ".wud")]
[InlineData(MediaType.FloppyDisk, ".img")]
[InlineData(MediaType.Cassette, ".wav")]
[InlineData(MediaType.ApertureCard, null)]
public void ExtensionTest(MediaType? type, string? expected)
{
string? actual = Converters.Extension(type);
Assert.Equal(expected, actual);
}
#endregion
#region Default Values
private static readonly Dictionary<string, string?> AllOptions = new()
{
[SettingConstants.DVDRereadCount] = "1000",
[SettingConstants.MultiSectorRead] = "true",
[SettingConstants.MultiSectorReadValue] = "1000",
[SettingConstants.ParanoidMode] = "true",
[SettingConstants.QuietMode] = "true",
[SettingConstants.RereadCount] = "1000",
[SettingConstants.UseCMIFlag] = "true",
};
[Theory]
[InlineData(null, null, null, "filename.bin", null, null)]
[InlineData(RedumpSystem.AppleMacintosh, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "cd /dev/sr0 \"filename.bin\" 2 /c2 1000 /q /mr 1000 /ns /sf /ss /s 2")]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "cd /dev/sr0 \"filename.bin\" 2 /c2 1000 /q /mr 1000 /ns /sf /ss /s 2")]
[InlineData(RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "cd /dev/sr0 \"filename.bin\" 2 /aj /c2 1000 /q /mr 1000")]
[InlineData(RedumpSystem.HasbroVideoNow, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "cd /dev/sr0 \"filename.bin\" 2 /a 0 /c2 1000 /q /mr 1000")]
[InlineData(RedumpSystem.HasbroVideoNowColor, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "cd /dev/sr0 \"filename.bin\" 2 /a 0 /c2 1000 /q /mr 1000")]
[InlineData(RedumpSystem.HasbroVideoNowJr, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "cd /dev/sr0 \"filename.bin\" 2 /a 0 /c2 1000 /q /mr 1000")]
[InlineData(RedumpSystem.HasbroVideoNowXP, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "cd /dev/sr0 \"filename.bin\" 2 /a 0 /c2 1000 /q /mr 1000")]
[InlineData(RedumpSystem.SonyPlayStation, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "cd /dev/sr0 \"filename.bin\" 2 /c2 1000 /q /mr 1000 /nl /am")]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, "/dev/sr0", "filename.bin", 2, "dvd /dev/sr0 \"filename.bin\" 2 /c /q /rr 1000 /sf")]
[InlineData(RedumpSystem.MicrosoftXbox, MediaType.DVD, "/dev/sr0", "filename.bin", 2, "xbox /dev/sr0 \"filename.bin\" 2 /q /rr 1000")]
[InlineData(RedumpSystem.MicrosoftXbox360, MediaType.DVD, "/dev/sr0", "filename.bin", 2, "xbox /dev/sr0 \"filename.bin\" 2 /q /rr 1000")]
[InlineData(RedumpSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc, "/dev/sr0", "filename.bin", 2, "dvd /dev/sr0 \"filename.bin\" 2 /q /raw")]
[InlineData(RedumpSystem.NintendoWii, MediaType.NintendoWiiOpticalDisc, "/dev/sr0", "filename.bin", 2, "dvd /dev/sr0 \"filename.bin\" 2 /q /raw")]
[InlineData(RedumpSystem.SegaDreamcast, MediaType.GDROM, "/dev/sr0", "filename.bin", 2, "gd /dev/sr0 \"filename.bin\" 2 /c2 1000 /q")]
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, "/dev/sr0", "filename.bin", 2, "dvd /dev/sr0 \"filename.bin\" 2 /c /q /rr 1000")]
[InlineData(RedumpSystem.BDVideo, MediaType.BluRay, "/dev/sr0", "filename.bin", 2, "bd /dev/sr0 \"filename.bin\" 2 /q /rr 1000")]
[InlineData(RedumpSystem.NintendoWiiU, MediaType.NintendoWiiUOpticalDisc, "/dev/sr0", "filename.bin", 2, "bd /dev/sr0 \"filename.bin\" 2 /q")]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.FloppyDisk, "/dev/sr0", "filename.bin", 2, "fd /dev/sr0 \"filename.bin\"")]
public void DefaultValueTest(RedumpSystem? system,
MediaType? type,
string? drivePath,
string filename,
int? driveSpeed,
string? expected)
{
var context = new ExecutionContext(system, type, drivePath, filename, driveSpeed, AllOptions);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
}
#endregion
#region Audio
[Theory]
[InlineData("audio F filename.bin 0 1 2 /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /f 0 /np /nq /nr /r /am /sf 1 /ss /sk 1 0 /s 0 /t")]
public void AudioTest(string parameters)
{
string? expected = "audio F \"filename.bin\" 0 1 2 /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /f 0 /np /nq /nr /r /am /sf 1 /ss /sk 1 0 /s 0 /t";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region AuthPS3
[Theory]
[InlineData("authps3 f")]
public void AuthPS3Test(string parameters)
{
string? expected = "authps3 f";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region BluRay
[Theory]
[InlineData("bd F filename.bin 0 /d /q /rr 0 /f 0 /ra /avdp")]
public void BluRayTest(string parameters)
{
string? expected = "bd F \"filename.bin\" 0 /d /q /rr 0 /f 0 /ra /avdp";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region Close
[Theory]
[InlineData("close f")]
public void CloseTest(string parameters)
{
string? expected = "close f";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region CompactDisc
[Theory]
[InlineData("cd f filename.bin 0 /a 0 /p /aj /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /mscf /fdesc sync edc /f 0 /fulltoc /mr 0 /np /nq /nl /ns /nr /am /sf 1 /ss /74 /s 0 /toc /trp /vn 0 /vnc /vnx")]
public void CompactDiscTest(string parameters)
{
string? expected = "cd f \"filename.bin\" 0 /a 0 /p /aj /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /mscf /fdesc sync edc /f 0 /fulltoc /mr 0 /np /nq /nl /ns /nr /am /sf 1 /ss /74 /s 0 /toc /trp /vn 0 /vnc /vnx";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region Data
[Theory]
[InlineData("data F filename.bin 0 1 2 /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /f 0 /np /nq /nr /r /am /sf 1 /ss /sk 1 0 /s 0 /t")]
public void DataTest(string parameters)
{
string? expected = "data F \"filename.bin\" 0 1 2 /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /f 0 /np /nq /nr /r /am /sf 1 /ss /sk 1 0 /s 0 /t";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region DigitalVideoDisc
[Theory]
[InlineData("dvd F filename.bin 0 /c /d /q /rr 0 /fix 0 /ps 0 /ra 0 1 /raw /re /r 0 1 /sf 1 /sk 1 0 /avdp")]
public void DigitalVideoDiscTest(string parameters)
{
string? expected = "dvd F \"filename.bin\" 0 /c /d /q /rr 0 /fix 0 /ps 0 /ra 0 1 /raw /re /r 0 1 /sf 1 /sk 1 0 /avdp";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region Disk
[Theory]
[InlineData("disk F filename.bin /d")]
public void DiskTest(string parameters)
{
string? expected = "disk F \"filename.bin\" /d";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region DriveSpeed
[Theory]
[InlineData("ls f")]
public void DriveSpeedTest(string parameters)
{
string? expected = "ls f";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Eject
[Theory]
[InlineData("eject f")]
public void EjectTest(string parameters)
{
string? expected = "eject f";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Floppy
[Theory]
[InlineData("fd F filename.bin /d")]
public void FloppyTest(string parameters)
{
string? expected = "fd F \"filename.bin\" /d";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region GDROM
[Theory]
[InlineData("gd f filename.bin 0 /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /f 0 /np /nq /nr /s 0")]
public void GDROMTest(string parameters)
{
string? expected = "gd f \"filename.bin\" 0 /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /f 0 /np /nq /nr /s 0";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region MDS
[Theory]
[InlineData("mds filename.bin")]
public void MDSTest(string parameters)
{
string? expected = "mds \"filename.bin\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Merge
[Theory]
[InlineData("merge input1.bin input2.bin")]
public void MergeTest(string parameters)
{
string? expected = "merge \"input1.bin\" \"input2.bin\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Reset
[Theory]
[InlineData("reset f")]
public void ResetTest(string parameters)
{
string? expected = "reset f";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region SACD
[Theory]
[InlineData("sacd f filename.bin 0 /d /q")]
public void SACDTest(string parameters)
{
string? expected = "sacd f \"filename.bin\" 0 /d /q";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region Start
[Theory]
[InlineData("start f")]
public void StartTest(string parameters)
{
string? expected = "start f";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Stop
[Theory]
[InlineData("stop f")]
public void StopTest(string parameters)
{
string? expected = "stop f";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Sub
[Theory]
[InlineData("sub filename.bin")]
public void SubTest(string parameters)
{
string? expected = "sub \"filename.bin\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Swap
[Theory]
[InlineData("swap f filename.bin 0 /a 0 /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /f 0 /np /nq /nl /ns /nr /am /sf 1 /ss /74 /s 0 /trp /vn 0 /vnc /vnx")]
public void SwapTest(string parameters)
{
string? expected = "swap f \"filename.bin\" 0 /a 0 /be raw /c2 1 2 3 1 5 6 /c2new 1 /d8 /d /q /f 0 /np /nq /nl /ns /nr /am /sf 1 /ss /74 /s 0 /trp /vn 0 /vnc /vnx";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region Tape
[Theory]
[InlineData("tape filename.bin")]
public void TapeTest(string parameters)
{
string? expected = "tape \"filename.bin\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region Version
[Theory]
[InlineData("/v")]
public void VersionTest(string parameters)
{
string? expected = "/v";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region XBOX
[Theory]
[InlineData("xbox f filename.bin 0 /d /q /rr 0 /f 0 /nss 0")]
public void XBOXTest(string parameters)
{
string? expected = "xbox f \"filename.bin\" 0 /d /q /rr 0 /f 0 /nss 0";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region XBOXSwap
[Theory]
[InlineData("xboxswap f filename.bin 0 /d /q /f 0 /nss 0")]
public void XBOXSwapTest(string parameters)
{
string? expected = "xboxswap f \"filename.bin\" 0 /d /q /f 0 /nss 0";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region XGD2Swap
[Theory]
[InlineData("xgd2swap f filename.bin 0 /d /q /f 0 /nss 0")]
public void XGD2SwapTest(string parameters)
{
string? expected = "xgd2swap f \"filename.bin\" 0 /d /q /f 0 /nss 0";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region XGD3Swap
[Theory]
[InlineData("xgd3swap f filename.bin 0 /d /q /f 0 /nss 0")]
public void XGD3SwapTest(string parameters)
{
string? expected = "xgd3swap f \"filename.bin\" 0 /d /q /f 0 /nss 0";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
}
}

View File

@@ -0,0 +1,68 @@
using System.Collections.Generic;
using MPF.ExecutionContexts.Dreamdump;
using SabreTools.RedumpLib.Data;
using Xunit;
namespace MPF.ExecutionContexts.Test
{
public class DreamdumpTests
{
#region Default Values
private static readonly Dictionary<string, string?> AllOptions = new()
{
[SettingConstants.RereadCount] = "1000",
[SettingConstants.SectorOrder] = "DATA_C2_SUB",
};
// None of these scenarios are actually supported as all are treated like GD-ROM
[Theory]
[InlineData(null, null, null, "filename.bin", null, "--retries=20 --image-name=\"filename\" --sector-order=DATA_C2_SUB")]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, "/dev/sr0", "path/filename.bin", 2, "--retries=20 --image-name=\"filename\" --image-path=\"path\" --speed=2 --sector-order=DATA_C2_SUB --drive=/dev/sr0")]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, "/dev/sr0", "path/filename.bin", 2, "--retries=20 --image-name=\"filename\" --image-path=\"path\" --speed=2 --sector-order=DATA_C2_SUB --drive=/dev/sr0")]
[InlineData(RedumpSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc, "/dev/sr0", "path/filename.bin", 2, "--retries=20 --image-name=\"filename\" --image-path=\"path\" --speed=2 --sector-order=DATA_C2_SUB --drive=/dev/sr0")]
[InlineData(RedumpSystem.NintendoWii, MediaType.NintendoWiiOpticalDisc, "/dev/sr0", "path/filename.bin", 2, "--retries=20 --image-name=\"filename\" --image-path=\"path\" --speed=2 --sector-order=DATA_C2_SUB --drive=/dev/sr0")]
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, "/dev/sr0", "path/filename.bin", 2, "--retries=20 --image-name=\"filename\" --image-path=\"path\" --speed=2 --sector-order=DATA_C2_SUB --drive=/dev/sr0")]
[InlineData(RedumpSystem.BDVideo, MediaType.BluRay, "/dev/sr0", "path/filename.bin", 2, "--retries=20 --image-name=\"filename\" --image-path=\"path\" --speed=2 --sector-order=DATA_C2_SUB --drive=/dev/sr0")]
[InlineData(RedumpSystem.NintendoWiiU, MediaType.NintendoWiiUOpticalDisc, "/dev/sr0", "path/filename.bin", 2, "--retries=20 --image-name=\"filename\" --image-path=\"path\" --speed=2 --sector-order=DATA_C2_SUB --drive=/dev/sr0")]
public void DefaultValueTest(RedumpSystem? system,
MediaType? type,
string? drivePath,
string filename,
int? driveSpeed,
string? expected)
{
var context = new ExecutionContext(system, type, drivePath, filename, driveSpeed, AllOptions);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
}
#endregion
#region Default
[Theory]
[InlineData("--force-qtoc --train --retries=20 --image-name=image --image-path=path --read-offset=0 --read-at-once=0 --speed=8 --sector-order=so --drive=/dev/sr0")]
public void DiscTest(string parameters)
{
string? expected = "--force-qtoc --train --retries=20 --image-name=\"image\" --image-path=\"path\" --read-offset=0 --read-at-once=0 --speed=8 --sector-order=so --drive=/dev/sr0";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
[Theory]
[InlineData("--image-name=\"image name.bin\" --image-path=\"directory name\"")]
public void SpacesTest(string parameters)
{
string? expected = "--image-name=\"image name.bin\" --image-path=\"directory name\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
}
}

View File

@@ -0,0 +1,410 @@
using MPF.ExecutionContexts.Data;
using Xunit;
namespace MPF.ExecutionContexts.Test
{
public class InputTests
{
#region FlagInput
[Theory]
// Invalid parts
[InlineData("flag", new string[0], 0, false, false)]
// Invalid index
[InlineData("flag", new string[] { "flag" }, -1, false, false)]
[InlineData("flag", new string[] { "flag" }, 1, false, false)]
// Invalid name
[InlineData("flag", new string[] { "" }, 0, false, false)]
[InlineData("flag", new string[] { "flag2" }, 0, false, false)]
// Valid
[InlineData("flag", new string[] { "flag" }, 0, true, true)]
public void FlagInputTest(string name, string[] parts, int index, bool success, bool expected)
{
var input = new FlagInput(name);
bool actual = input.Process(parts, ref index);
Assert.Equal(success, actual);
Assert.Equal(expected, input.Value);
}
#endregion
#region BooleanInput
[Theory]
// Invalid parts
[InlineData("flag", true, new string[0], 0, false, null)]
// Invalid index
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
// Invalid name
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
// Valid name, no following
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag" }, 0, true, true)]
// Valid name, invalid following
[InlineData("flag", true, new string[] { "flag", "invalid" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag", "invalid" }, 0, true, true)]
[InlineData("flag", true, new string[] { "flag=invalid" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag=invalid" }, 0, true, true)]
// Valid name, valid following
[InlineData("flag", true, new string[] { "flag", "true" }, 0, true, true)]
[InlineData("flag", true, new string[] { "flag", "false" }, 0, true, false)]
[InlineData("flag", true, new string[] { "flag=true" }, 0, true, true)]
[InlineData("flag", true, new string[] { "flag=false" }, 0, true, false)]
public void BooleanInputTest(string name, bool required, string[] parts, int index, bool success, bool? expected)
{
var input = new BooleanInput(name, required);
bool actual = input.Process(parts, ref index);
Assert.Equal(success, actual);
Assert.Equal(expected, input.Value);
}
#endregion
#region Int8Input
[Theory]
// Invalid parts
[InlineData("flag", true, new string[0], 0, false, null)]
// Invalid index
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
// Invalid name
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
// Valid name, no following
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag" }, 0, true, sbyte.MinValue)]
// Valid name, invalid following
[InlineData("flag", true, new string[] { "flag", "invalid" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag", "invalid" }, 0, true, sbyte.MinValue)]
[InlineData("flag", true, new string[] { "flag=invalid" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag=invalid" }, 0, true, sbyte.MinValue)]
// Valid name, valid following
[InlineData("flag", true, new string[] { "flag", "1" }, 0, true, (sbyte)1)]
[InlineData("flag", true, new string[] { "flag", "-1" }, 0, true, (sbyte)-1)]
[InlineData("flag", true, new string[] { "flag=1" }, 0, true, (sbyte)1)]
[InlineData("flag", true, new string[] { "flag=-1" }, 0, true, (sbyte)-1)]
public void Int8InputTest(string name, bool required, string[] parts, int index, bool success, sbyte? expected)
{
var input = new Int8Input(name, required);
bool actual = input.Process(parts, ref index);
Assert.Equal(success, actual);
Assert.Equal(expected, input.Value);
}
#endregion
#region UInt8Input
[Theory]
// Invalid parts
[InlineData("flag", true, new string[0], 0, false, null)]
// Invalid index
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
// Invalid name
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
// Valid name, no following
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag" }, 0, true, byte.MinValue)]
// Valid name, invalid following
[InlineData("flag", true, new string[] { "flag", "invalid" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag", "invalid" }, 0, true, byte.MinValue)]
[InlineData("flag", true, new string[] { "flag=invalid" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag=invalid" }, 0, true, byte.MinValue)]
// Valid name, valid following
[InlineData("flag", true, new string[] { "flag", "1" }, 0, true, (byte)1)]
[InlineData("flag", true, new string[] { "flag=1" }, 0, true, (byte)1)]
public void UInt8InputTest(string name, bool required, string[] parts, int index, bool success, byte? expected)
{
var input = new UInt8Input(name, required);
bool actual = input.Process(parts, ref index);
Assert.Equal(success, actual);
Assert.Equal(expected, input.Value);
}
#endregion
#region Int16Input
[Theory]
// Invalid parts
[InlineData("flag", true, new string[0], 0, false, null)]
// Invalid index
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
// Invalid name
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
// Valid name, no following
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag" }, 0, true, short.MinValue)]
// Valid name, invalid following
[InlineData("flag", true, new string[] { "flag", "invalid" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag", "invalid" }, 0, true, short.MinValue)]
[InlineData("flag", true, new string[] { "flag=invalid" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag=invalid" }, 0, true, short.MinValue)]
// Valid name, valid following
[InlineData("flag", true, new string[] { "flag", "1" }, 0, true, (short)1)]
[InlineData("flag", true, new string[] { "flag", "-1" }, 0, true, (short)-1)]
[InlineData("flag", true, new string[] { "flag=1" }, 0, true, (short)1)]
[InlineData("flag", true, new string[] { "flag=-1" }, 0, true, (short)-1)]
public void Int16InputTest(string name, bool required, string[] parts, int index, bool success, short? expected)
{
var input = new Int16Input(name, required);
bool actual = input.Process(parts, ref index);
Assert.Equal(success, actual);
Assert.Equal(expected, input.Value);
}
#endregion
#region UInt16Input
[Theory]
// Invalid parts
[InlineData("flag", true, new string[0], 0, false, null)]
// Invalid index
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
// Invalid name
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
// Valid name, no following
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag" }, 0, true, ushort.MinValue)]
// Valid name, invalid following
[InlineData("flag", true, new string[] { "flag", "invalid" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag", "invalid" }, 0, true, ushort.MinValue)]
[InlineData("flag", true, new string[] { "flag=invalid" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag=invalid" }, 0, true, ushort.MinValue)]
// Valid name, valid following
[InlineData("flag", true, new string[] { "flag", "1" }, 0, true, (ushort)1)]
[InlineData("flag", true, new string[] { "flag=1" }, 0, true, (ushort)1)]
public void UInt16InputTest(string name, bool required, string[] parts, int index, bool success, ushort? expected)
{
var input = new UInt16Input(name, required);
bool actual = input.Process(parts, ref index);
Assert.Equal(success, actual);
Assert.Equal(expected, input.Value);
}
#endregion
#region Int32Input
[Theory]
// Invalid parts
[InlineData("flag", true, new string[0], 0, false, null)]
// Invalid index
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
// Invalid name
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
// Valid name, no following
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag" }, 0, true, int.MinValue)]
// Valid name, invalid following
[InlineData("flag", true, new string[] { "flag", "invalid" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag", "invalid" }, 0, true, int.MinValue)]
[InlineData("flag", true, new string[] { "flag=invalid" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag=invalid" }, 0, true, int.MinValue)]
// Valid name, valid following
[InlineData("flag", true, new string[] { "flag", "1" }, 0, true, (int)1)]
[InlineData("flag", true, new string[] { "flag", "-1" }, 0, true, (int)-1)]
[InlineData("flag", true, new string[] { "flag=1" }, 0, true, (int)1)]
[InlineData("flag", true, new string[] { "flag=-1" }, 0, true, (int)-1)]
public void Int32InputTest(string name, bool required, string[] parts, int index, bool success, int? expected)
{
var input = new Int32Input(name, required);
bool actual = input.Process(parts, ref index);
Assert.Equal(success, actual);
Assert.Equal(expected, input.Value);
}
#endregion
#region UInt32Input
[Theory]
// Invalid parts
[InlineData("flag", true, new string[0], 0, false, null)]
// Invalid index
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
// Invalid name
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
// Valid name, no following
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag" }, 0, true, uint.MinValue)]
// Valid name, invalid following
[InlineData("flag", true, new string[] { "flag", "invalid" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag", "invalid" }, 0, true, uint.MinValue)]
[InlineData("flag", true, new string[] { "flag=invalid" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag=invalid" }, 0, true, uint.MinValue)]
// Valid name, valid following
[InlineData("flag", true, new string[] { "flag", "1" }, 0, true, (uint)1)]
[InlineData("flag", true, new string[] { "flag=1" }, 0, true, (uint)1)]
public void UInt32InputTest(string name, bool required, string[] parts, int index, bool success, uint? expected)
{
var input = new UInt32Input(name, required);
bool actual = input.Process(parts, ref index);
Assert.Equal(success, actual);
Assert.Equal(expected, input.Value);
}
#endregion
#region Int64Input
[Theory]
// Invalid parts
[InlineData("flag", true, new string[0], 0, false, null)]
// Invalid index
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
// Invalid name
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
// Valid name, no following
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag" }, 0, true, long.MinValue)]
// Valid name, invalid following
[InlineData("flag", true, new string[] { "flag", "invalid" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag", "invalid" }, 0, true, long.MinValue)]
[InlineData("flag", true, new string[] { "flag=invalid" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag=invalid" }, 0, true, long.MinValue)]
// Valid name, valid following
[InlineData("flag", true, new string[] { "flag", "1" }, 0, true, (long)1)]
[InlineData("flag", true, new string[] { "flag", "-1" }, 0, true, (long)-1)]
[InlineData("flag", true, new string[] { "flag=1" }, 0, true, (long)1)]
[InlineData("flag", true, new string[] { "flag=-1" }, 0, true, (long)-1)]
public void Int64InputTest(string name, bool required, string[] parts, int index, bool success, long? expected)
{
var input = new Int64Input(name, required);
bool actual = input.Process(parts, ref index);
Assert.Equal(success, actual);
Assert.Equal(expected, input.Value);
}
#endregion
#region UInt64Input
[Theory]
// Invalid parts
[InlineData("flag", true, new string[0], 0, false, null)]
// Invalid index
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
// Invalid name
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
// Valid name, no following
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag" }, 0, true, ulong.MinValue)]
// Valid name, invalid following
[InlineData("flag", true, new string[] { "flag", "invalid" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag", "invalid" }, 0, true, ulong.MinValue)]
[InlineData("flag", true, new string[] { "flag=invalid" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag=invalid" }, 0, true, ulong.MinValue)]
// Valid name, valid following
[InlineData("flag", true, new string[] { "flag", "1" }, 0, true, (ulong)1)]
[InlineData("flag", true, new string[] { "flag=1" }, 0, true, (ulong)1)]
public void UInt64InputTest(string name, bool required, string[] parts, int index, bool success, ulong? expected)
{
var input = new UInt64Input(name, required);
bool actual = input.Process(parts, ref index);
Assert.Equal(success, actual);
Assert.Equal(expected, input.Value);
}
#endregion
#region StringInput
[Theory]
// Invalid parts
[InlineData("flag", true, new string[0], 0, false, null)]
// Invalid index
[InlineData("flag", true, new string[] { "flag" }, -1, false, null)]
[InlineData("flag", true, new string[] { "flag" }, 1, false, null)]
// Invalid name
[InlineData("flag", true, new string[] { "" }, 0, false, null)]
[InlineData("flag", true, new string[] { "flag2" }, 0, false, null)]
// Valid name, no following
[InlineData("flag", true, new string[] { "flag" }, 0, false, null)]
[InlineData("flag", false, new string[] { "flag" }, 0, true, "")]
// Valid name, following
[InlineData("flag", true, new string[] { "flag", "value" }, 0, true, "value")]
[InlineData("flag", true, new string[] { "flag=value" }, 0, true, "value")]
public void StringInputTest(string name, bool required, string[] parts, int index, bool success, string? expected)
{
var input = new StringInput(name, required);
bool actual = input.Process(parts, ref index);
Assert.Equal(success, actual);
Assert.Equal(expected, input.Value);
}
#endregion
#region ExtractFactorFromValue
[Theory]
[InlineData("1", "1", 1)]
[InlineData("1c", "1", 1)]
[InlineData("1w", "1", 2)]
[InlineData("1d", "1", 4)]
[InlineData("1q", "1", 8)]
[InlineData("1k", "1", 1024)]
[InlineData("1M", "1", 1024 * 1024)]
[InlineData("1G", "1", 1024 * 1024 * 1024)]
public void ExtractFactorFromValueTest(string value, string expected, long expectedFactor)
{
string actual = Input.ExtractFactorFromValue(value, out long factor);
Assert.Equal(expected, actual);
Assert.Equal(expectedFactor, factor);
}
#endregion
#region RemoveHexIdentifier
[Theory]
[InlineData("", "")]
[InlineData("0", "0")]
[InlineData("00", "00")]
[InlineData("0x", "0x")]
[InlineData("0X", "0X")]
[InlineData("A", "A")]
[InlineData("A0", "A0")]
[InlineData("Ax", "Ax")]
[InlineData("AX", "AX")]
[InlineData("012345", "012345")]
[InlineData("0x12345", "12345")]
[InlineData("0X12345", "12345")]
public void RemoveHexIdentifierTest(string value, string expected)
{
string actual = Input.RemoveHexIdentifier(value);
Assert.Equal(expected, actual);
}
#endregion
}
}

View File

@@ -0,0 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MPF.ExecutionContexts\MPF.ExecutionContexts.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeCoverage" Version="18.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<PackageReference Include="SabreTools.RedumpLib" Version="[1.9.1]" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
<PackageReference Include="xunit.analyzers" Version="1.27.0" />
<PackageReference Include="xunit.assert" Version="2.9.3" />
<PackageReference Include="xunit.core" Version="2.9.3" />
<PackageReference Include="xunit.extensibility.core" Version="2.9.3" />
<PackageReference Include="xunit.extensibility.execution" Version="2.9.3" />
<PackageReference Include="xunit.runner.console" Version="2.9.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,378 @@
using System.Collections.Generic;
using MPF.ExecutionContexts.Redumper;
using SabreTools.RedumpLib.Data;
using Xunit;
namespace MPF.ExecutionContexts.Test
{
public class RedumperTests
{
#region Converters.Extension
[Theory]
[InlineData(null, null)]
[InlineData(MediaType.CDROM, ".bin")]
[InlineData(MediaType.GDROM, ".bin")]
[InlineData(MediaType.DVD, ".iso")]
[InlineData(MediaType.HDDVD, ".iso")]
[InlineData(MediaType.BluRay, ".iso")]
[InlineData(MediaType.NintendoWiiOpticalDisc, ".iso")]
[InlineData(MediaType.NintendoGameCubeGameDisc, ".raw")]
[InlineData(MediaType.NintendoWiiUOpticalDisc, ".wud")]
[InlineData(MediaType.ApertureCard, null)]
public void ExtensionTest(MediaType? type, string? expected)
{
string? actual = Converters.Extension(type);
Assert.Equal(expected, actual);
}
#endregion
#region Default Values
private static readonly Dictionary<string, string?> AllOptions = new()
{
[SettingConstants.EnableVerbose] = "true",
[SettingConstants.LeadinRetryCount] = "1000",
[SettingConstants.ReadMethod] = "BE",
[SettingConstants.RereadCount] = "1000",
[SettingConstants.SectorOrder] = "DATA_C2_SUB",
[SettingConstants.DriveType] = "GENERIC",
};
[Theory]
[InlineData(null, null, null, "filename.bin", null, "disc --verbose --skeleton --retries=1000 --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --skeleton --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --skeleton --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
[InlineData(RedumpSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
[InlineData(RedumpSystem.NintendoWii, MediaType.NintendoWiiOpticalDisc, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
[InlineData(RedumpSystem.BDVideo, MediaType.BluRay, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
[InlineData(RedumpSystem.NintendoWiiU, MediaType.NintendoWiiUOpticalDisc, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
public void DefaultValueTest(RedumpSystem? system,
MediaType? type,
string? drivePath,
string filename,
int? driveSpeed,
string? expected)
{
var context = new ExecutionContext(system, type, drivePath, filename, driveSpeed, AllOptions);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
}
#endregion
#region Disc
[Theory]
[InlineData("disc -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("disc --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void DiscTest(string parameters)
{
string? expected = "disc --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
[Theory]
[InlineData("disc --drive=dr --image-path=\"directory name\" --image-name=\"image name.bin\"")]
public void SpacesTest(string parameters)
{
string? expected = "disc --drive=dr --image-path=\"directory name\" --image-name=\"image name.bin\"";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region Rings
[Theory]
[InlineData("rings -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("rings --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void RingsTest(string parameters)
{
string? expected = "rings --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Dump
[Theory]
[InlineData("dump -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("dump --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void DumpTest(string parameters)
{
string? expected = "dump --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region DumpExtra
[Theory]
[InlineData("dump::extra -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("dump::extra --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void DumpExtraTest(string parameters)
{
string? expected = "dump::extra --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Refine
[Theory]
[InlineData("refine -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("refine --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void RefineTest(string parameters)
{
string? expected = "refine --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Verify
[Theory]
[InlineData("verify -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("verify --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void VerifyTest(string parameters)
{
string? expected = "verify --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region DVDKey
[Theory]
[InlineData("dvdkey -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("dvdkey --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void DVDKeyTest(string parameters)
{
string? expected = "dvdkey --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Eject
[Theory]
[InlineData("eject -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("eject --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void EjectTest(string parameters)
{
string? expected = "eject --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region DVDIsoKey
[Theory]
[InlineData("dvdisokey -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("dvdisokey --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void DVDIsoKeyTest(string parameters)
{
string? expected = "dvdisokey --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Protection
[Theory]
[InlineData("protection -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("protection --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void ProtectionTest(string parameters)
{
string? expected = "protection --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Split
[Theory]
[InlineData("split -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("split --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void SplitTest(string parameters)
{
string? expected = "split --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Hash
[Theory]
[InlineData("hash -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("hash --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void HashTest(string parameters)
{
string? expected = "hash --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Info
[Theory]
[InlineData("info -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("info --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void InfoTest(string parameters)
{
string? expected = "info --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Skeleton
[Theory]
[InlineData("skeleton -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("skeleton --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void SkeletonTest(string parameters)
{
string? expected = "skeleton --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Subchannel
[Theory]
[InlineData("subchannel -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("subchannel --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void SubchannelTest(string parameters)
{
string? expected = "subchannel --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region Debug
[Theory]
[InlineData("debug -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("debug --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void DebugTest(string parameters)
{
string? expected = "debug --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region FixMSF
[Theory]
[InlineData("fixmsf -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("fixmsf --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void FixMSFTest(string parameters)
{
string? expected = "fixmsf --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
}
#endregion
#region DebugFlip
[Theory]
[InlineData("debug::flip -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("debug::flip --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void DebugFlipTest(string parameters)
{
string? expected = "debug::flip --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
}
#endregion
#region DriveTest
[Theory]
[InlineData("drive::test -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("drive::test --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void DriveTestTest(string parameters)
{
string? expected = "drive::test --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --mediatek-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --filesystem-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
}
#endregion
}
}

View File

@@ -0,0 +1,89 @@
namespace MPF.ExecutionContexts.Aaru
{
/// <summary>
/// Top-level commands for Aaru
/// </summary>
public static class CommandStrings
{
public const string NONE = "";
#region Archive Family
public const string ArchivePrefixShort = "arc";
public const string ArchivePrefixLong = "archive";
public const string ArchiveInfo = "info";
#endregion
#region Database Family
public const string DatabasePrefixShort = "db";
public const string DatabasePrefixLong = "database";
public const string DatabaseStats = "stats";
public const string DatabaseUpdate = "update";
#endregion
#region Device Family
public const string DevicePrefixShort = "dev";
public const string DevicePrefixLong = "device";
public const string DeviceInfo = "info";
public const string DeviceList = "list";
public const string DeviceReport = "report";
#endregion
#region Filesystem Family
public const string FilesystemPrefixShort = "fi";
public const string FilesystemPrefixShortAlt = "fs";
public const string FilesystemPrefixLong = "filesystem";
public const string FilesystemExtract = "extract";
public const string FilesystemInfo = "info";
public const string FilesystemListShort = "ls";
public const string FilesystemListLong = "list";
public const string FilesystemOptions = "options";
#endregion
#region Image Family
public const string ImagePrefixShort = "i";
public const string ImagePrefixLong = "image";
public const string ImageChecksumShort = "chk";
public const string ImageChecksumLong = "checksum";
public const string ImageCompareShort = "cmp";
public const string ImageCompareLong = "compare";
public const string ImageConvert = "convert";
public const string ImageCreateSidecar = "create-sidecar";
public const string ImageDecode = "decode";
public const string ImageEntropy = "entropy";
public const string ImageInfo = "info";
public const string ImageOptions = "options";
public const string ImagePrint = "print";
public const string ImageVerify = "verify";
#endregion
#region Media Family
public const string MediaPrefixShort = "m";
public const string MediaPrefixLong = "media";
public const string MediaDump = "dump";
public const string MediaInfo = "info";
public const string MediaScan = "scan";
#endregion
#region Standalone Commands
public const string Configure = "configure";
public const string Formats = "formats";
public const string ListEncodings = "list-encodings";
public const string ListNamespaces = "list-namespaces";
public const string Remote = "remote";
#endregion
}
}

View File

@@ -1,6 +1,6 @@
using SabreTools.RedumpLib.Data;
namespace MPF.Core.Modules.Aaru
namespace MPF.ExecutionContexts.Aaru
{
public static class Converters
{

View File

@@ -0,0 +1,43 @@
namespace MPF.ExecutionContexts.Aaru
{
/// <summary>
/// Supported encodings for Aaru
/// </summary>
/// TODO: Use to verify encoding settings
public static class EncodingStrings
{
public const string ArabicMac = "x-mac-arabic";
public const string AtariASCII = "atascii";
public const string CentralEuropeanMac = "x-mac-ce";
public const string CommodorePETSCII = "petscii";
public const string CroatianMac = "x-mac-croatian";
public const string CyrillicMac = "x-mac-cryillic";
public const string FarsiMac = "x-mac-farsi";
public const string GreekMac = "x-mac-greek";
public const string HebrewMac = "x-mac-hebrew";
public const string RomanianMac = "x-mac-romanian";
public const string SinclairZXSpectrum = "spectrum";
public const string SinclairZX80 = "zx80";
public const string SinclairZX81 = "zx81";
public const string TurkishMac = "x-mac-turkish";
public const string UkrainianMac = "x-mac-ukrainian";
public const string Unicode = "utf-16";
public const string UnicodeBigEndian = "utf-16BE";
public const string UnicodeUTF32BigEndian = "utf-32BE";
public const string UnicodeUTF32 = "utf-32";
public const string UnicodeUTF7 = "utf-7";
public const string UnicodeUTF8 = "utf-8";
public const string USASCII = "us-ascii";
public const string WesternEuropeanAppleII = "apple2";
public const string WesternEuropeanAppleIIc = "apple2c";
public const string WesternEuropeanAppleIIe = "apple2e";
public const string WesternEuropeanAppleIIgs = "apple2gs";
public const string WesternEuropeanAppleLisa = "lisa";
public const string WesternEuropeanAtariST = "atarist";
public const string WesternEuropeanGEM = "gem";
public const string WesternEuropeanGEOS = "geos";
public const string WesternEuropeanISO = "iso-8859-1";
public const string WesternEuropeanMac = "macintosh";
public const string WesternEuropeanRadix50 = "radix50";
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,173 @@
namespace MPF.ExecutionContexts.Aaru
{
/// <summary>
/// Dumping flags for Aaru
/// </summary>
public static class FlagStrings
{
#region Precommand Flags
public const string DebugShort = "-d";
public const string DebugLong = "--debug";
public const string HelpShort = "-h";
public const string HelpShortAlt = "-?";
public const string HelpLong = "--help";
public const string VerboseShort = "-v";
public const string VerboseLong = "--verbose";
public const string VersionLong = "--version";
#endregion
#region Boolean flags
public const string Adler32Short = "-a";
public const string Adler32Long = "--adler32";
public const string ClearLong = "--clear";
public const string ClearAllLong = "--clear-all";
public const string CRC16Long = "--crc16";
public const string CRC32Short = "-c";
public const string CRC32Long = "--crc32";
public const string CRC64Long = "--crc64";
public const string DiskTagsShort = "-f";
public const string DiskTagsLong = "--disk-tags";
public const string DuplicatedSectorsShort = "-p";
public const string DuplicatedSectorsLong = "--duplicated-sectors";
public const string EjectLong = "--eject";
public const string ExtendedAttributesShort = "-x";
public const string ExtendedAttributesLong = "--xattrs";
public const string FilesystemsShort = "-f";
public const string FilesystemsLong = "--filesystems";
public const string FirstPregapLong = "--first-pregap";
public const string FixOffsetLong = "--fix-offset";
public const string FixSubchannelLong = "--fix-subchannel";
public const string FixSubchannelCrcLong = "--fix-subchannel-crc";
public const string FixSubchannelPositionLong = "--fix-subchannel-position";
public const string Fletcher16Long = "--fletcher16";
public const string Fletcher32Long = "--fletcher32";
public const string ForceShort = "-f";
public const string ForceLong = "--force";
public const string GenerateSubchannelsLong = "--generate-subchannels";
public const string LongFormatShort = "-l";
public const string LongFormatLong = "--long-format";
public const string LongSectorsShort = "-r";
public const string LongSectorsLong = "--long-sectors";
public const string MD5Short = "-m";
public const string MD5Long = "--md5";
public const string MetadataLong = "--metadata";
public const string PartitionsShort = "-p";
public const string PartitionsLong = "--partitions";
public const string PauseLong = "--pause";
public const string PersistentLong = "--persistent";
public const string PrivateLong = "--private";
public const string ResumeShort = "-r";
public const string ResumeLong = "--resume";
public const string RetrySubchannelLong = "--retry-subchannel";
public const string SectorTagsShort = "-p";
public const string SectorTagsLong = "--sector-tags";
public const string SeparatedTracksShort = "-t";
public const string SeparatedTracksLong = "--separated-tracks";
public const string SHA1Short = "-s";
public const string SHA1Long = "--sha1";
public const string SHA256Long = "--sha256";
public const string SHA384Long = "--sha384";
public const string SHA512Long = "--sha512";
public const string SkipCdiReadyHoleLong = "--skip-cdiready-hole";
public const string SpamSumShort = "-f";
public const string SpamSumLong = "--spamsum";
public const string StopOnErrorShort = "-s";
public const string StopOnErrorLong = "--stop-on-error";
public const string StoreEncryptedLong = "--store-encrypted";
public const string TapeShort = "-t";
public const string TapeLong = "--tape";
public const string TitleKeysLong = "--title-keys";
public const string TrapDiscShort = "-t";
public const string TrapDiscLong = "--trap-disc";
public const string TrimLong = "--trim";
public const string UseBufferedReadsLong = "--use-buffered-reads";
public const string VerifyDiscShort = "-w";
public const string VerifyDiscLong = "--verify-disc";
public const string VerifySectorsShort = "-s";
public const string VerifySectorsLong = "--verify-sectors";
public const string WholeDiscShort = "-w";
public const string WholeDiscLong = "--whole-disc";
#endregion
#region Int8 flags
public const string SpeedLong = "--speed";
#endregion
#region Int16 flags
public const string RetryPassesShort = "-p";
public const string RetryPassesLong = "--retry-passes";
public const string WidthShort = "-w";
public const string WidthLong = "--width";
#endregion
#region Int32 flags
public const string BlockSizeShort = "-b";
public const string BlockSizeLong = "--block-size";
public const string CountShort = "-c";
public const string CountLong = "--count";
public const string MaxBlocksLong = "--max-blocks";
public const string MediaLastSequenceLong = "--media-lastsequence";
public const string MediaSequenceLong = "--media-sequence";
public const string SkipShort = "-k";
public const string SkipLong = "--skip";
#endregion
#region Int64 flags
public const string LengthShort = "-l"; // or "all"
public const string LengthLong = "--length"; // or "all"
public const string StartShort = "-s";
public const string StartLong = "--start";
#endregion
#region String flags
public const string CommentsLong = "--comments";
public const string CreatorLong = "--creator";
public const string DriveManufacturerLong = "--drive-manufacturer";
public const string DriveModelLong = "--drive-model";
public const string DriveRevisionLong = "--drive-revision";
public const string DriveSerialLong = "--drive-serial";
public const string EncodingShort = "-e";
public const string EncodingLong = "--encoding";
public const string FormatConvertShort = "-p";
public const string FormatDumpShort = "-t";
public const string FormatLong = "--format";
public const string GeometryShort = "-g";
public const string GeometryLong = "--geometry";
public const string ImgBurnLogShort = "-b";
public const string ImgBurnLogLong = "--ibg-log";
public const string MediaBarcodeLong = "--media-barcode";
public const string MediaManufacturerLong = "--media-manufacturer";
public const string MediaModelLong = "--media-model";
public const string MediaPartNumberLong = "--media-partnumber";
public const string MediaSerialLong = "--media-serial";
public const string MediaTitleLong = "--media-title";
public const string MHDDLogShort = "-m";
public const string MHDDLogLong = "--mhdd-log";
public const string NamespaceShort = "-n";
public const string NamespaceLong = "--namespace";
public const string OptionsShort = "-O";
public const string OptionsLong = "--options";
public const string OutputPrefixShort = "-w";
public const string OutputPrefixLong = "--output-prefix";
public const string ResumeFileShort = "-r";
public const string ResumeFileLong = "--resume-file";
public const string SubchannelLong = "--subchannel";
public const string XMLSidecarShort = "-x";
public const string XMLSidecarLong = "--cicm-xml";
#endregion
}
}

View File

@@ -0,0 +1,169 @@
namespace MPF.ExecutionContexts.Aaru
{
/// <summary>
/// Supported formats for Aaru
/// </summary>
/// TODO: Use to verify format settings
public static class FormatStrings
{
// Supported filters
public const string AppleDouble = "AppleDouble";
public const string AppleSingle = "AppleSingle";
public const string BZip2 = "BZip2";
public const string GZip = "GZip";
public const string LZip = "LZip";
public const string MacBinary = "MacBinary";
public const string NoFilter = "No filter";
public const string PCExchange = "PCExchange";
public const string XZ = "XZ";
// Read-only media image formats
public const string AppleDiskArchivalRetrievalTool = "Apple Disk Archival/Retrieval Tool";
public const string AppleNewDiskImageFormat = "Apple New Disk Image Format";
public const string AppleNIB = "Apple NIB";
public const string BlindWrite4 = "BlindWrite 4";
public const string BlindWrite5 = "BlindWrite 5";
public const string CPCEMUDiskFileAndExtendedCPCDiskFile = "CPCEMU Disk-File and Extended CPC Disk-File";
public const string D2FDiskImage = "d2f disk image";
public const string D88DiskImage = "D88 Disk Image";
public const string DIMDiskImage = "DIM Disk Image";
public const string DiscFerret = "DiscFerret";
public const string DiscJuggler = "DiscJuggler";
public const string DreamcastGDIImage = "Dreamcast GDI image";
public const string DunfieldsIMD = "Dunfield's IMD";
public const string HDCopyDiskImage = "HD-Copy disk image";
public const string KryoFluxSTREAM = "KryoFlux STREAM";
public const string MAMECompressedHunksOfData = "MAME Compressed Hunks of Data";
public const string MicrosoftVHDX = "Microsoft VHDX";
public const string NeroBurningROMImage = "Nero Burning ROM image";
public const string PartCloneDiskImage = "PartClone disk image";
public const string PartimageDiskImage = "Partimage disk image";
public const string SpectrumFloppyDiskImage = "Spectrum Floppy Disk Image";
public const string SuperCardPro = "SuperCardPro";
public const string SydexCopyQM = "Sydex CopyQM";
public const string SydexTeleDisk = "Sydex TeleDisk";
// Read/write media image formats
public const string AaruFormat = "Aaru Format";
public const string ACTApricotDiskImage = "ACT Apricot Disk Image";
public const string Alcohol120MediaDescriptorStructure = "Alcohol 120% Media Descriptor Structure";
public const string Anex86DiskImage = "Anex86 Disk Image";
public const string Apple2InterleavedDiskImage = "Apple ][Interleaved Disk Image";
public const string Apple2IMG = "Apple 2IMG";
public const string AppleDiskCopy42 = "Apple DiskCopy 4.2";
public const string AppleUniversalDiskImageFormat = "Apple Universal Disk Image Format";
public const string BasicLisaUtility = "Basic Lisa Utility";
public const string CDRDAOTocfile = "CDRDAO tocfile";
public const string CDRWinCuesheet = "CDRWin cuesheet";
public const string CisCopyDiskImageDCFile = "CisCopy Disk Image(DC-File)";
public const string CloneCD = "CloneCD";
public const string CopyTape = "CopyTape";
public const string DigitalResearchDiskCopy = "Digital Research DiskCopy";
public const string IBMSaveDskF = "IBM SaveDskF";
public const string MAXIDiskImage = "MAXI Disk image";
public const string ParallelsDiskImage = "Parallels disk image";
public const string QEMUCopyOnWriteDiskImage = "QEMU Copy-On-Write disk image";
public const string QEMUCopyOnWriteDiskImageV2 = "QEMU Copy-On-Write disk image v2";
public const string QEMUEnhancedDiskImage = "QEMU Enhanced Disk image";
public const string RawDiskImage = "Raw Disk Image";
public const string RayAracheliansDiskIMage = "Ray Arachelian's Disk IMage";
public const string RSIDEHardDiskImage = "RS-IDE Hard Disk Image";
public const string T98HardDiskImage = "T98 Hard Disk Image";
public const string T98NextNHDr0DiskImage = "T98-Next NHD r0 Disk Image";
public const string Virtual98DiskImage = "Virtual98 Disk Image";
public const string VirtualBoxDiskImage = "VirtualBox Disk Image";
public const string VirtualPC = "VirtualPC";
public const string VMwareDiskImage = "VMware disk image";
// Supported filesystems for identification and information only
public const string AcornAdvancedDiscFilingSystem = "Acorn Advanced Disc Filing System";
public const string AlexanderOsipovDOSFileSystem = "Alexander Osipov DOS file system";
public const string AmigaDOSFilesystem = "Amiga DOS filesystem";
public const string AppleFileSystem = "Apple File System";
public const string AppleHFSPlusFilesystem = "Apple HFS+ filesystem";
public const string AppleHierarchicalFileSystem = "Apple Hierarchical File System";
public const string AppleProDOSFilesystem = "Apple ProDOS filesystem";
public const string AtheOSFilesystem = "AtheOS Filesystem";
public const string BeFilesystem = "Be Filesystem";
public const string BSDFastFileSystem = "BSD Fast File System(aka UNIX File System, UFS)";
public const string BTreeFileSystem = "B-tree file system";
public const string CommodoreFileSystem = "Commodore file system";
public const string CramFilesystem = "Cram filesystem";
public const string DumpEightPlugin = "dump(8) Plugin";
public const string ECMA67 = "ECMA-67";
public const string ExtentFileSystemPlugin = "Extent File System Plugin";
public const string F2FSPlugin = "F2FS Plugin";
public const string Files11OnDiskStructure = "Files-11 On-Disk Structure";
public const string FossilFilesystemPlugin = "Fossil Filesystem Plugin";
public const string HAMMERFilesystem = "HAMMER Filesystem";
public const string HighPerformanceOpticalFileSystem = "High Performance Optical File System";
public const string HPLogicalInterchangeFormatPlugin = "HP Logical Interchange Format Plugin";
public const string JFSPlugin = "JFS Plugin";
public const string LinuxExtendedFilesystem = "Linux extended Filesystem";
public const string LinuxExtendedFilesystem234 = "Linux extended Filesystem 2, 3 and 4";
public const string LocusFilesystemPlugin = "Locus Filesystem Plugin";
public const string MicroDOSFileSystem = "MicroDOS file system";
public const string MicrosoftExtendedFileAllocationTable = "Microsoft Extended File Allocation Table";
public const string MinixFilesystem = "Minix Filesystem";
public const string NewTechnologyFileSystem = "New Technology File System(NTFS)";
public const string NILFS2Plugin = "NILFS2 Plugin";
public const string NintendoOpticalFilesystems = "Nintendo optical filesystems";
public const string OS2HighPerformanceFileSystem = "OS/2 High Performance File System";
public const string OS9RandomBlockFilePlugin = "OS-9 Random Block File Plugin";
public const string PCEngineCDPlugin = "PC Engine CD Plugin";
public const string PCFXPlugin = "PC-FX Plugin";
public const string ProfessionalFileSystem = "Professional File System";
public const string QNX4Plugin = "QNX4 Plugin";
public const string QNX6Plugin = "QNX6 Plugin";
public const string ReiserFilesystemPlugin = "Reiser Filesystem Plugin";
public const string Reiser4FilesystemPlugin = "Reiser4 Filesystem Plugin";
public const string ResilientFileSystemPlugin = "Resilient File System plugin";
public const string RT11FileSystem = "RT-11 file system";
public const string SmartFileSystem = "SmartFileSystem";
public const string SolarOSFilesystem = "Solar_OS filesystem";
public const string SquashFilesystem = "Squash filesystem";
public const string UNICOSFilesystemPlugin = "UNICOS Filesystem Plugin";
public const string UniversalDiskFormat = "Universal Disk Format";
public const string UNIXBootFilesystem = "UNIX Boot filesystem";
public const string UNIXSystemVFilesystem = "UNIX System V filesystem";
public const string VeritasFilesystem = "Veritas filesystem";
public const string VMwareFilesystem = "VMware filesystem";
public const string XFSFilesystemPlugin = "XFS Filesystem Plugin";
public const string XiaFilesystem = "Xia filesystem";
public const string ZFSFilesystemPlugin = "ZFS Filesystem Plugin";
// Supported filesystems that can read their contents
public const string AppleDOSFileSystem = "Apple DOS File System";
public const string AppleLisaFileSystem = "Apple Lisa File System";
public const string AppleMacintoshFileSystem = "Apple Macintosh File System";
public const string CPMFileSystem = "CP/M File System";
public const string FATXFilesystemPlugin = "FATX Filesystem Plugin";
public const string ISO9660Filesystem = "ISO9660 Filesystem";
public const string MicrosoftFileAllocationTable = "Microsoft File Allocation Table";
public const string OperaFilesystemPlugin = "Opera Filesystem Plugin";
public const string UCSDPascalFilesystem = "U.C.S.D.Pascal filesystem";
// Supported partitioning schemes
public const string AcornFileCorePartitions = "Acorn FileCore partitions";
public const string ACTApricotPartitions = "ACT Apricot partitions";
public const string AmigaRigidDiskBlock = "Amiga Rigid Disk Block";
public const string ApplePartitionMap = "Apple Partition Map";
public const string AtariPartitions = "Atari partitions";
public const string BSDDisklabel = "BSD disklabel";
public const string DECDisklabel = "DEC disklabel";
public const string DragonFlyBSD64bitDisklabel = "DragonFly BSD 64-bit disklabel";
public const string GUIDPartitionTable = "GUID Partition Table";
public const string Human68kPartitions = "Human 68k partitions";
public const string MasterBootRecord = "Master Boot Record";
public const string NECPC9800PartitionTable = "NEC PC-9800 partition table";
public const string NeXTDisklabel = "NeXT Disklabel";
public const string Plan9PartitionTable = "Plan9 partition table";
public const string RioKarmaPartitioning = "Rio Karma partitioning";
public const string SGIDiskVolumeHeader = "SGI Disk Volume Header";
public const string SunDisklabel = "Sun Disklabel";
public const string UNIXHardwired = "UNIX hardwired";
public const string UNIXVTOC = "UNIX VTOC";
public const string XboxPartitioning = "Xbox partitioning";
public const string XENIX = "XENIX";
}
}

View File

@@ -0,0 +1,27 @@
namespace MPF.ExecutionContexts.Aaru
{
/// <summary>
/// Supported namespaces for Aaru
/// </summary>
/// TODO: Use to verify namespace settings
public static class NamespaceStrings
{
// Namespaces for Apple Lisa File System
public const string LisaOfficeSystem = "office";
public const string LisaPascalWorkshop = "workshop"; // Default
// Namespaces for ISO9660 Filesystem
public const string JolietVolumeDescriptor = "joliet"; // Default
public const string PrimaryVolumeDescriptor = "normal";
public const string PrimaryVolumeDescriptorwithEncoding = "romeo";
public const string RockRidge = "rrip";
public const string PrimaryVolumeDescriptorVersionSuffix = "vms";
// Namespaces for Microsoft File Allocation Table
public const string DOS83UpperCase = "dos";
public const string LFNWhenAvailableWithFallback = "ecs"; // Default
public const string LongFileNames = "lfn";
public const string WindowsNT83MixedCase = "nt";
public const string OS2Extended = "os2";
}
}

View File

@@ -0,0 +1,43 @@
namespace MPF.ExecutionContexts.Aaru
{
/// <summary>
/// Supported options for Aaru
/// </summary>
/// TODO: Use to verify option settings
public static class OptionStrings
{
// Aaru format
public const string AaruCompress = "compress"; // boolean, default true;
public const string AaruDeduplicate = "deduplicate"; // boolean, default true
public const string AaruDictionary = "dictionary"; // number, default 33554432
public const string AaruMaxDDTSize = "max_ddt_size"; // number, default 256
public const string AaruMD5 = "md5"; // boolean, default false
public const string AaruSectorsPerBlock = "sectors_per_block"; // number, default 4096 [power of 2]
public const string AaruSHA1 = "sha1"; // boolean, default false
public const string AaruSHA256 = "sha256"; // boolean, default false
public const string AaruSpamSum = "spamsum"; // boolean, default false
// ACT Apricot Disk Image
public const string ACTApricotDiskImageCompress = "compress"; // boolean, default false
// Apple DiskCopy 4.2
public const string AppleDiskCopyMacOSX = "macosx"; // boolean, default false
// CDRDAO tocfile
public const string CDRDAOTocfileSeparate = "separate"; // boolean, default false
// CDRWin cuesheet
public const string CDRWinCuesheetSeparate = "separate"; // boolean, default false
// ISO9660 Filesystem
public const string ISO9660FSUseEvd = "use_evd"; // boolean, default false
public const string ISO9660FSUsePathTable = "use_path_table"; // boolean, default false
public const string ISO9660FSUseTransTbl = "use_trans_tbl"; // boolean, default false
// VMware disk image
public const string VMwareDiskImageAdapterType = "adapter_type"; // string, default ide [ide, lsilogic, buslogic, legacyESX]
public const string VMwareDiskImageHWVersion = "hwversion"; // number, default 4
public const string VMwareDiskImageSparse = "sparse"; // boolean, default false
public const string VMwareDiskImageSplit = "split"; // boolean, default false
}
}

View File

@@ -0,0 +1,20 @@
namespace MPF.ExecutionContexts.Aaru
{
public static class SettingConstants
{
public const string EnableDebug = "AaruEnableDebug";
public const bool EnableDebugDefault = false;
public const string EnableVerbose = "AaruEnableVerbose";
public const bool EnableVerboseDefault = true;
public const string ForceDumping = "AaruForceDumping";
public const bool ForceDumpingDefault = true;
public const string RereadCount = "AaruRereadCount";
public const int RereadCountDefault = 5;
public const string StripPersonalData = "AaruStripPersonalData";
public const bool StripPersonalDataDefault = false;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,123 @@
using System;
using System.Text;
namespace MPF.ExecutionContexts.Data
{
/// <summary>
/// Represents a boolean flag with an optional trailing value
/// </summary>
public class BooleanInput : Input<bool?>
{
#region Constructors
/// <inheritdoc/>
public BooleanInput(string name)
: base(name) { }
/// <inheritdoc/>
public BooleanInput(string name, bool required)
: base(name, required) { }
/// <inheritdoc/>
public BooleanInput(string shortName, string longName)
: base(shortName, longName) { }
/// <inheritdoc/>
public BooleanInput(string shortName, string longName, bool required)
: base(shortName, longName, required) { }
/// <inheritdoc/>
public BooleanInput(string[] names)
: base(names) { }
/// <inheritdoc/>
public BooleanInput(string[] names, bool required)
: base(names, required) { }
#endregion
/// <inheritdoc/>
public override string Format(bool useEquals)
{
// Do not output if there is no value
if (Value is null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Separator
if (useEquals)
builder.Append('=');
else
builder.Append(' ');
// Value
builder.Append(Value.ToString());
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
// Ensure the value exists
if (index + 1 >= parts.Length)
{
Value = _required ? null : true;
return !_required;
}
// If the next value is valid
if (!bool.TryParse(parts[index + 1], out bool value))
{
Value = _required ? null : true;
return !_required;
}
index++;
Value = value;
return true;
}
// Check for equal separated
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
{
// Split the string, using the first equal sign as the separator
string[] tempSplit = part.Split('=');
string key = tempSplit[0];
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
// Ensure the value exists
if (string.IsNullOrEmpty(val))
{
Value = _required ? null : true;
return !_required;
}
// If the next value is valid
if (!bool.TryParse(val, out bool value))
{
Value = _required ? null : true;
return !_required;
}
Value = value;
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,73 @@
using System;
using System.Text;
namespace MPF.ExecutionContexts.Data
{
/// <summary>
/// Represents a boolean flag without a trailing value
/// </summary>
public class FlagInput : Input<bool>
{
#region Constructors
/// <inheritdoc/>
public FlagInput(string name)
: base(name) { }
/// <inheritdoc/>
public FlagInput(string name, bool required)
: base(name, required) { }
/// <inheritdoc/>
public FlagInput(string shortName, string longName)
: base(shortName, longName) { }
/// <inheritdoc/>
public FlagInput(string shortName, string longName, bool required)
: base(shortName, longName, required) { }
/// <inheritdoc/>
public FlagInput(string[] names)
: base(names) { }
/// <inheritdoc/>
public FlagInput(string[] names, bool required)
: base(names, required) { }
#endregion
/// <inheritdoc/>
public override string Format(bool useEquals)
{
// Do not output if there is no value
if (!Value)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check the name
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
Value = true;
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,291 @@
namespace MPF.ExecutionContexts.Data
{
/// <summary>
/// Represents a single input for an execution context
/// </summary>
public abstract class Input
{
#region Properties
/// <summary>
/// Primary name for the input
/// </summary>
public readonly string Name;
/// <summary>
/// Alternative name for the input
/// </summary>
protected readonly string[] _altNames;
/// <summary>
/// Indicates if the value following is required or not
/// </summary>
protected readonly bool _required;
/// <summary>
/// Indicates if a value has been set
/// </summary>
public abstract bool ValueSet { get; }
#endregion
#region Constructors
/// <param name="name">Flag name / value</param>
public Input(string name)
{
Name = name;
_altNames = [];
_required = true;
}
/// <param name="name">Flag name / value</param>
/// <param name="required">Indicates if a following value is required</param>
public Input(string name, bool required)
{
Name = name;
_altNames = [];
_required = required;
}
/// <param name="shortName">Flag name / value</param>
/// <param name="longName">Verbose flag name / value</param>
public Input(string shortName, string longName)
{
Name = longName;
_altNames = [shortName];
_required = true;
}
/// <param name="shortName">Flag name / value</param>
/// <param name="longName">Verbose flag name / value</param>
/// <param name="required">Indicates if a following value is required</param>
public Input(string shortName, string longName, bool required)
{
Name = longName;
_altNames = [shortName];
_required = required;
}
/// <param name="names">Set of names to use</param>
public Input(string[] names)
{
Name = names.Length > 0 ? names[0] : string.Empty;
_altNames = names;
_required = true;
}
/// <param name="names">Set of names to use</param>
/// <param name="required">Indicates if a following value is required</param>
public Input(string[] names, bool required)
{
Name = names.Length > 0 ? names[0] : string.Empty;
_altNames = names;
_required = required;
}
#endregion
#region Functionality
/// <summary>
/// Clear any accumulated value
/// </summary>
public abstract void ClearValue();
/// <summary>
/// Create a formatted representation of the input and possible value
/// </summary>
/// <param name="useEquals">Use an equal sign as a separator on output</param>
public abstract string Format(bool useEquals);
/// <summary>
/// Process the current index, if possible
/// </summary>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="index">Reference to the position in the parts</param>
/// <returns>True if a value could be determined, false otherwise</returns>
public abstract bool Process(string[] parts, ref int index);
#endregion
#region Helpers
/// <summary>
/// Get the trimmed value and multiplication factor from a value
/// </summary>
/// <param name="value">String value to treat as suffixed number</param>
/// <returns>Trimmed value and multiplication factor</returns>
internal static string ExtractFactorFromValue(string value, out long factor)
{
value = value.Trim('"');
factor = 1;
// Characters
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
if (value.EndsWith('c'))
#else
if (value.EndsWith("c", System.StringComparison.Ordinal))
#endif
{
factor = 1;
value = value.TrimEnd('c');
}
// Words
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
else if (value.EndsWith('w'))
#else
else if (value.EndsWith("w", System.StringComparison.Ordinal))
#endif
{
factor = 2;
value = value.TrimEnd('w');
}
// Double Words
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
else if (value.EndsWith('d'))
#else
else if (value.EndsWith("d", System.StringComparison.Ordinal))
#endif
{
factor = 4;
value = value.TrimEnd('d');
}
// Quad Words
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
else if (value.EndsWith('q'))
#else
else if (value.EndsWith("q", System.StringComparison.Ordinal))
#endif
{
factor = 8;
value = value.TrimEnd('q');
}
// Kilobytes
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
else if (value.EndsWith('k'))
#else
else if (value.EndsWith("k", System.StringComparison.Ordinal))
#endif
{
factor = 1024;
value = value.TrimEnd('k');
}
// Megabytes
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
else if (value.EndsWith('M'))
#else
else if (value.EndsWith("M", System.StringComparison.Ordinal))
#endif
{
factor = 1024 * 1024;
value = value.TrimEnd('M');
}
// Gigabytes
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
else if (value.EndsWith('G'))
#else
else if (value.EndsWith("G", System.StringComparison.Ordinal))
#endif
{
factor = 1024 * 1024 * 1024;
value = value.TrimEnd('G');
}
return value;
}
/// <summary>
/// Removes a leading 0x if it exists, case insensitive
/// </summary>
/// <param name="value">String with removed leading 0x</param>
/// <returns></returns>
internal static string RemoveHexIdentifier(string value)
{
if (value.Length <= 2)
return value;
if (value[0] != '0')
return value;
if (value[1] != 'x' && value[1] != 'X')
return value;
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
return value[2..];
#else
return value.Substring(2);
#endif
}
#endregion
}
/// <summary>
/// Represents a single input for an execution context
/// </summary>
public abstract class Input<T> : Input
{
#region Properties
/// <summary>
/// Represents the last value stored
/// </summary>
public T? Value { get; protected set; }
/// <inheritdoc/>
public override bool ValueSet => Value is not null;
#endregion
#region Constructors
/// <inheritdoc/>
public Input(string name)
: base(name) { }
/// <inheritdoc/>
public Input(string name, bool required)
: base(name, required) { }
/// <inheritdoc/>
public Input(string shortName, string longName)
: base(shortName, longName) { }
/// <inheritdoc/>
public Input(string shortName, string longName, bool required)
: base(shortName, longName, required) { }
/// <inheritdoc/>
public Input(string[] names)
: base(names) { }
/// <inheritdoc/>
public Input(string[] names, bool required)
: base(names, required) { }
#endregion
#region Functionality
/// <inheritdoc/>
public override void ClearValue()
{
Value = default;
}
/// <summary>
/// Set a new value
/// </summary>
public void SetValue(T value)
{
Value = value;
}
#endregion
}
}

View File

@@ -0,0 +1,189 @@
using System;
using System.Globalization;
using System.Text;
namespace MPF.ExecutionContexts.Data
{
/// <summary>
/// Represents an Int16 flag with an optional trailing value
/// </summary>
public class Int16Input : Input<short?>
{
#region Properties
/// <summary>
/// Indicates a minimum value (inclusive) for the flag
/// </summary>
public short? MinValue { get; set; } = null;
/// <summary>
/// Indicates a maximum value (inclusive) for the flag
/// </summary>
public short? MaxValue { get; set; } = null;
#endregion
#region Constructors
/// <inheritdoc/>
public Int16Input(string name)
: base(name) { }
/// <inheritdoc/>
public Int16Input(string name, bool required)
: base(name, required) { }
/// <inheritdoc/>
public Int16Input(string shortName, string longName)
: base(shortName, longName) { }
/// <inheritdoc/>
public Int16Input(string shortName, string longName, bool required)
: base(shortName, longName, required) { }
/// <inheritdoc/>
public Int16Input(string[] names)
: base(names) { }
/// <inheritdoc/>
public Int16Input(string[] names, bool required)
: base(names, required) { }
#endregion
/// <inheritdoc/>
public override string Format(bool useEquals)
{
// Do not output if there is no value
if (Value is null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Only output separator and value if needed
if (_required || (!_required && Value != short.MinValue))
{
// Separator
if (useEquals)
builder.Append('=');
else
builder.Append(' ');
// Value
builder.Append(Value.ToString());
}
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
// Ensure the value exists
if (index + 1 >= parts.Length)
{
Value = _required ? null : short.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(parts[index + 1], out short? value) && value is not null)
{
index++;
Value = value;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : short.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// Check for equal separated
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
{
// Split the string, using the first equal sign as the separator
string[] tempSplit = part.Split('=');
string key = tempSplit[0];
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
// Ensure the value exists
if (string.IsNullOrEmpty(val))
{
Value = _required ? null : short.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(val, out short? value) && value is not null)
{
Value = value;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : short.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
return false;
}
/// <summary>
/// Parse a value from a string
/// </summary>
private static bool ParseValue(string str, out short? output)
{
// If the next value is valid
if (short.TryParse(str, out short value))
{
output = value;
return true;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(str, out long factor);
if (short.TryParse(baseVal, out value))
{
output = (short)(value * factor);
return true;
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (short.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
output = (short)(value * factor);
return true;
}
// The value could not be parsed
output = null;
return false;
}
}
}

View File

@@ -0,0 +1,161 @@
using System;
using System.Globalization;
using System.Text;
namespace MPF.ExecutionContexts.Data
{
/// <summary>
/// Represents an Int32 flag with an optional trailing value
/// </summary>
public class Int32ArrInput : Input<int?[]>
{
#region Properties
/// <summary>
/// Internal array size
/// </summary>
public int Size { get; set; }
/// <summary>
/// Indicates a minimum value (inclusive) for the flag
/// </summary>
public int? MinValue { get; set; } = null;
/// <summary>
/// Indicates a maximum value (inclusive) for the flag
/// </summary>
public int? MaxValue { get; set; } = null;
#endregion
#region Constructors
/// <inheritdoc/>
public Int32ArrInput(string name)
: base(name) { }
/// <inheritdoc/>
public Int32ArrInput(string name, bool required)
: base(name, required) { }
/// <inheritdoc/>
public Int32ArrInput(string shortName, string longName)
: base(shortName, longName) { }
/// <inheritdoc/>
public Int32ArrInput(string shortName, string longName, bool required)
: base(shortName, longName, required) { }
/// <inheritdoc/>
public Int32ArrInput(string[] names)
: base(names) { }
/// <inheritdoc/>
public Int32ArrInput(string[] names, bool required)
: base(names, required) { }
#endregion
/// <inheritdoc/>
public override string Format(bool useEquals)
{
// Do not output if there is no value
if (Value is null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Only output separator and value if needed
if (_required || (!_required && Value is not null))
{
// Separator
if (useEquals)
builder.Append('=');
else
builder.Append(' ');
// Value
int?[] nonNull = Array.FindAll(Value, i => i is not null);
string[] stringValues = Array.ConvertAll(nonNull, i => i.ToString() ?? string.Empty);
builder.Append(string.Join(" ", stringValues));
}
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
Value = new int?[Size];
for (int i = 0; i < Size; i++)
{
// Ensure the value exists
if (index + 1 >= parts.Length)
return !_required;
// If the next value is valid
if (ParseValue(parts[index + 1], out int? value) && value is not null)
{
index++;
Value[i] = value;
Value[i] = (MinValue is not null && Value[i] < MinValue) ? MinValue : Value[i];
Value[i] = (MaxValue is not null && Value[i] > MaxValue) ? MaxValue : Value[i];
continue;
}
// Return value based on required flag
return !_required;
}
return true;
}
return false;
}
/// <summary>
/// Parse a value from a string
/// </summary>
private static bool ParseValue(string str, out int? output)
{
// If the next value is valid
if (int.TryParse(str, out int value))
{
output = value;
return true;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(str, out long factor);
if (int.TryParse(baseVal, out value))
{
output = (int)(value * factor);
return true;
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (int.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
output = (int)(value * factor);
return true;
}
// The value could not be parsed
output = null;
return false;
}
}
}

View File

@@ -0,0 +1,189 @@
using System;
using System.Globalization;
using System.Text;
namespace MPF.ExecutionContexts.Data
{
/// <summary>
/// Represents an Int32 flag with an optional trailing value
/// </summary>
public class Int32Input : Input<int?>
{
#region Properties
/// <summary>
/// Indicates a minimum value (inclusive) for the flag
/// </summary>
public int? MinValue { get; set; } = null;
/// <summary>
/// Indicates a maximum value (inclusive) for the flag
/// </summary>
public int? MaxValue { get; set; } = null;
#endregion
#region Constructors
/// <inheritdoc/>
public Int32Input(string name)
: base(name) { }
/// <inheritdoc/>
public Int32Input(string name, bool required)
: base(name, required) { }
/// <inheritdoc/>
public Int32Input(string shortName, string longName)
: base(shortName, longName) { }
/// <inheritdoc/>
public Int32Input(string shortName, string longName, bool required)
: base(shortName, longName, required) { }
/// <inheritdoc/>
public Int32Input(string[] names)
: base(names) { }
/// <inheritdoc/>
public Int32Input(string[] names, bool required)
: base(names, required) { }
#endregion
/// <inheritdoc/>
public override string Format(bool useEquals)
{
// Do not output if there is no value
if (Value is null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Only output separator and value if needed
if (_required || (!_required && Value != int.MinValue))
{
// Separator
if (useEquals)
builder.Append('=');
else
builder.Append(' ');
// Value
builder.Append(Value.ToString());
}
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
// Ensure the value exists
if (index + 1 >= parts.Length)
{
Value = _required ? null : int.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(parts[index + 1], out int? value) && value is not null)
{
index++;
Value = value;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : int.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// Check for equal separated
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
{
// Split the string, using the first equal sign as the separator
string[] tempSplit = part.Split('=');
string key = tempSplit[0];
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
// Ensure the value exists
if (string.IsNullOrEmpty(val))
{
Value = _required ? null : int.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(val, out int? value) && value is not null)
{
Value = value;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : int.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
return false;
}
/// <summary>
/// Parse a value from a string
/// </summary>
private static bool ParseValue(string str, out int? output)
{
// If the next value is valid
if (int.TryParse(str, out int value))
{
output = value;
return true;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(str, out long factor);
if (int.TryParse(baseVal, out value))
{
output = (int)(value * factor);
return true;
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (int.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
output = (int)(value * factor);
return true;
}
// The value could not be parsed
output = null;
return false;
}
}
}

View File

@@ -0,0 +1,189 @@
using System;
using System.Globalization;
using System.Text;
namespace MPF.ExecutionContexts.Data
{
/// <summary>
/// Represents an Int64 flag with an optional trailing value
/// </summary>
public class Int64Input : Input<long?>
{
#region Properties
/// <summary>
/// Indicates a minimum value (inclusive) for the flag
/// </summary>
public long? MinValue { get; set; } = null;
/// <summary>
/// Indicates a maximum value (inclusive) for the flag
/// </summary>
public long? MaxValue { get; set; } = null;
#endregion
#region Constructors
/// <inheritdoc/>
public Int64Input(string name)
: base(name) { }
/// <inheritdoc/>
public Int64Input(string name, bool required)
: base(name, required) { }
/// <inheritdoc/>
public Int64Input(string shortName, string longName)
: base(shortName, longName) { }
/// <inheritdoc/>
public Int64Input(string shortName, string longName, bool required)
: base(shortName, longName, required) { }
/// <inheritdoc/>
public Int64Input(string[] names)
: base(names) { }
/// <inheritdoc/>
public Int64Input(string[] names, bool required)
: base(names, required) { }
#endregion
/// <inheritdoc/>
public override string Format(bool useEquals)
{
// Do not output if there is no value
if (Value is null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Only output separator and value if needed
if (_required || (!_required && Value != long.MinValue))
{
// Separator
if (useEquals)
builder.Append('=');
else
builder.Append(' ');
// Value
builder.Append(Value.ToString());
}
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
// Ensure the value exists
if (index + 1 >= parts.Length)
{
Value = _required ? null : long.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(parts[index + 1], out long? value) && value is not null)
{
index++;
Value = value;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : long.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// Check for equal separated
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
{
// Split the string, using the first equal sign as the separator
string[] tempSplit = part.Split('=');
string key = tempSplit[0];
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
// Ensure the value exists
if (string.IsNullOrEmpty(val))
{
Value = _required ? null : long.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(val, out long? value) && value is not null)
{
Value = value;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : long.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
return false;
}
/// <summary>
/// Parse a value from a string
/// </summary>
private static bool ParseValue(string str, out long? output)
{
// If the next value is valid
if (long.TryParse(str, out long value))
{
output = value;
return true;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(str, out long factor);
if (long.TryParse(baseVal, out value))
{
output = value * factor;
return true;
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (long.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
output = value * factor;
return true;
}
// The value could not be parsed
output = null;
return false;
}
}
}

View File

@@ -0,0 +1,189 @@
using System;
using System.Globalization;
using System.Text;
namespace MPF.ExecutionContexts.Data
{
/// <summary>
/// Represents an Int8 flag with an optional trailing value
/// </summary>
public class Int8Input : Input<sbyte?>
{
#region Properties
/// <summary>
/// Indicates a minimum value (inclusive) for the flag
/// </summary>
public sbyte? MinValue { get; set; } = null;
/// <summary>
/// Indicates a maximum value (inclusive) for the flag
/// </summary>
public sbyte? MaxValue { get; set; } = null;
#endregion
#region Constructors
/// <inheritdoc/>
public Int8Input(string name)
: base(name) { }
/// <inheritdoc/>
public Int8Input(string name, bool required)
: base(name, required) { }
/// <inheritdoc/>
public Int8Input(string shortName, string longName)
: base(shortName, longName) { }
/// <inheritdoc/>
public Int8Input(string shortName, string longName, bool required)
: base(shortName, longName, required) { }
/// <inheritdoc/>
public Int8Input(string[] names)
: base(names) { }
/// <inheritdoc/>
public Int8Input(string[] names, bool required)
: base(names, required) { }
#endregion
/// <inheritdoc/>
public override string Format(bool useEquals)
{
// Do not output if there is no value
if (Value is null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Only output separator and value if needed
if (_required || (!_required && Value != sbyte.MinValue))
{
// Separator
if (useEquals)
builder.Append('=');
else
builder.Append(' ');
// Value
builder.Append(Value.ToString());
}
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
// Ensure the value exists
if (index + 1 >= parts.Length)
{
Value = _required ? null : sbyte.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(parts[index + 1], out sbyte? value) && value is not null)
{
index++;
Value = value;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : sbyte.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// Check for equal separated
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
{
// Split the string, using the first equal sign as the separator
string[] tempSplit = part.Split('=');
string key = tempSplit[0];
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
// Ensure the value exists
if (string.IsNullOrEmpty(val))
{
Value = _required ? null : sbyte.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(val, out sbyte? value) && value is not null)
{
Value = value;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : sbyte.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
return false;
}
/// <summary>
/// Parse a value from a string
/// </summary>
private static bool ParseValue(string str, out sbyte? output)
{
// If the next value is valid
if (sbyte.TryParse(str, out sbyte value))
{
output = value;
return true;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(str, out long factor);
if (sbyte.TryParse(baseVal, out value))
{
output = (sbyte)(value * factor);
return true;
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (sbyte.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
output = (sbyte)(value * factor);
return true;
}
// The value could not be parsed
output = null;
return false;
}
}
}

View File

@@ -0,0 +1,126 @@
using System;
using System.Text;
namespace MPF.ExecutionContexts.Data
{
/// <summary>
/// Represents a string flag with an optional trailing value
/// </summary>
public class StringInput : Input<string>
{
#region Properties
/// <summary>
/// Indicates whether quotes are used in output or not
/// </summary>
public bool Quotes { get; set; } = false;
#endregion
#region Constructors
/// <inheritdoc/>
public StringInput(string name)
: base(name) { }
/// <inheritdoc/>
public StringInput(string name, bool required)
: base(name, required) { }
/// <inheritdoc/>
public StringInput(string shortName, string longName)
: base(shortName, longName) { }
/// <inheritdoc/>
public StringInput(string shortName, string longName, bool required)
: base(shortName, longName, required) { }
/// <inheritdoc/>
public StringInput(string[] names)
: base(names) { }
/// <inheritdoc/>
public StringInput(string[] names, bool required)
: base(names, required) { }
#endregion
/// <inheritdoc/>
public override string Format(bool useEquals)
{
// Do not output if there is no value
if (Value is null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Only output separator and value if needed
if (_required || (!_required && Value != string.Empty))
{
// Separator
if (useEquals)
builder.Append('=');
else
builder.Append(' ');
// Value
if (Quotes)
builder.Append($"\"{Value}\"");
else
builder.Append(Value);
}
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
// Ensure the value exists
if (index + 1 >= parts.Length)
{
Value = _required ? null : string.Empty;
return !_required;
}
index++;
Value = parts[index].Trim('"');
return true;
}
// Check for equal separated
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
{
// Split the string, using the first equal sign as the separator
string[] tempSplit = part.Split('=');
string key = tempSplit[0];
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
// Ensure the value exists
if (string.IsNullOrEmpty(val))
{
Value = _required ? null : string.Empty;
return !_required;
}
Value = val.Trim('"');
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,189 @@
using System;
using System.Globalization;
using System.Text;
namespace MPF.ExecutionContexts.Data
{
/// <summary>
/// Represents an UInt16 flag with an optional trailing value
/// </summary>
public class UInt16Input : Input<ushort?>
{
#region Properties
/// <summary>
/// Indicates a minimum value (inclusive) for the flag
/// </summary>
public ushort? MinValue { get; set; } = null;
/// <summary>
/// Indicates a maximum value (inclusive) for the flag
/// </summary>
public ushort? MaxValue { get; set; } = null;
#endregion
#region Constructors
/// <inheritdoc/>
public UInt16Input(string name)
: base(name) { }
/// <inheritdoc/>
public UInt16Input(string name, bool required)
: base(name, required) { }
/// <inheritdoc/>
public UInt16Input(string shortName, string longName)
: base(shortName, longName) { }
/// <inheritdoc/>
public UInt16Input(string shortName, string longName, bool required)
: base(shortName, longName, required) { }
/// <inheritdoc/>
public UInt16Input(string[] names)
: base(names) { }
/// <inheritdoc/>
public UInt16Input(string[] names, bool required)
: base(names, required) { }
#endregion
/// <inheritdoc/>
public override string Format(bool useEquals)
{
// Do not output if there is no value
if (Value is null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Only output separator and value if needed
if (_required || (!_required && Value != ushort.MinValue))
{
// Separator
if (useEquals)
builder.Append('=');
else
builder.Append(' ');
// Value
builder.Append(Value.ToString());
}
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
// Ensure the value exists
if (index + 1 >= parts.Length)
{
Value = _required ? null : ushort.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(parts[index + 1], out ushort? value) && value is not null)
{
index++;
Value = value;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : ushort.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// Check for equal separated
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
{
// Split the string, using the first equal sign as the separator
string[] tempSplit = part.Split('=');
string key = tempSplit[0];
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
// Ensure the value exists
if (string.IsNullOrEmpty(val))
{
Value = _required ? null : ushort.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(val, out ushort? value) && value is not null)
{
Value = value;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : ushort.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
return false;
}
/// <summary>
/// Parse a value from a string
/// </summary>
private static bool ParseValue(string str, out ushort? output)
{
// If the next value is valid
if (ushort.TryParse(str, out ushort value))
{
output = value;
return true;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(str, out long factor);
if (ushort.TryParse(baseVal, out value))
{
output = (ushort)(value * factor);
return true;
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (ushort.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
output = (ushort)(value * factor);
return true;
}
// The value could not be parsed
output = null;
return false;
}
}
}

View File

@@ -0,0 +1,189 @@
using System;
using System.Globalization;
using System.Text;
namespace MPF.ExecutionContexts.Data
{
/// <summary>
/// Represents an UInt32 flag with an optional trailing value
/// </summary>
public class UInt32Input : Input<uint?>
{
#region Properties
/// <summary>
/// Indicates a minimum value (inclusive) for the flag
/// </summary>
public uint? MinValue { get; set; } = null;
/// <summary>
/// Indicates a maximum value (inclusive) for the flag
/// </summary>
public uint? MaxValue { get; set; } = null;
#endregion
#region Constructors
/// <inheritdoc/>
public UInt32Input(string name)
: base(name) { }
/// <inheritdoc/>
public UInt32Input(string name, bool required)
: base(name, required) { }
/// <inheritdoc/>
public UInt32Input(string shortName, string longName)
: base(shortName, longName) { }
/// <inheritdoc/>
public UInt32Input(string shortName, string longName, bool required)
: base(shortName, longName, required) { }
/// <inheritdoc/>
public UInt32Input(string[] names)
: base(names) { }
/// <inheritdoc/>
public UInt32Input(string[] names, bool required)
: base(names, required) { }
#endregion
/// <inheritdoc/>
public override string Format(bool useEquals)
{
// Do not output if there is no value
if (Value is null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Only output separator and value if needed
if (_required || (!_required && Value != uint.MinValue))
{
// Separator
if (useEquals)
builder.Append('=');
else
builder.Append(' ');
// Value
builder.Append(Value.ToString());
}
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
// Ensure the value exists
if (index + 1 >= parts.Length)
{
Value = _required ? null : uint.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(parts[index + 1], out uint? value) && value is not null)
{
index++;
Value = value;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : uint.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// Check for equal separated
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
{
// Split the string, using the first equal sign as the separator
string[] tempSplit = part.Split('=');
string key = tempSplit[0];
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
// Ensure the value exists
if (string.IsNullOrEmpty(val))
{
Value = _required ? null : uint.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(val, out uint? value) && value is not null)
{
Value = value;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : uint.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
return false;
}
/// <summary>
/// Parse a value from a string
/// </summary>
private static bool ParseValue(string str, out uint? output)
{
// If the next value is valid
if (uint.TryParse(str, out uint value))
{
output = value;
return true;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(str, out long factor);
if (uint.TryParse(baseVal, out value))
{
output = (uint)(value * factor);
return true;
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (uint.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
output = (uint)(value * factor);
return true;
}
// The value could not be parsed
output = null;
return false;
}
}
}

View File

@@ -0,0 +1,189 @@
using System;
using System.Globalization;
using System.Text;
namespace MPF.ExecutionContexts.Data
{
/// <summary>
/// Represents an UInt64 flag with an optional trailing value
/// </summary>
public class UInt64Input : Input<ulong?>
{
#region Properties
/// <summary>
/// Indicates a minimum value (inclusive) for the flag
/// </summary>
public ulong? MinValue { get; set; } = null;
/// <summary>
/// Indicates a maximum value (inclusive) for the flag
/// </summary>
public ulong? MaxValue { get; set; } = null;
#endregion
#region Constructors
/// <inheritdoc/>
public UInt64Input(string name)
: base(name) { }
/// <inheritdoc/>
public UInt64Input(string name, bool required)
: base(name, required) { }
/// <inheritdoc/>
public UInt64Input(string shortName, string longName)
: base(shortName, longName) { }
/// <inheritdoc/>
public UInt64Input(string shortName, string longName, bool required)
: base(shortName, longName, required) { }
/// <inheritdoc/>
public UInt64Input(string[] names)
: base(names) { }
/// <inheritdoc/>
public UInt64Input(string[] names, bool required)
: base(names, required) { }
#endregion
/// <inheritdoc/>
public override string Format(bool useEquals)
{
// Do not output if there is no value
if (Value is null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Only output separator and value if needed
if (_required || (!_required && Value != ulong.MinValue))
{
// Separator
if (useEquals)
builder.Append('=');
else
builder.Append(' ');
// Value
builder.Append(Value.ToString());
}
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
// Ensure the value exists
if (index + 1 >= parts.Length)
{
Value = _required ? null : ulong.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(parts[index + 1], out ulong? value) && value is not null)
{
index++;
Value = value;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : ulong.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// Check for equal separated
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
{
// Split the string, using the first equal sign as the separator
string[] tempSplit = part.Split('=');
string key = tempSplit[0];
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
// Ensure the value exists
if (string.IsNullOrEmpty(val))
{
Value = _required ? null : ulong.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(val, out ulong? value) && value is not null)
{
Value = value;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : ulong.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
return false;
}
/// <summary>
/// Parse a value from a string
/// </summary>
private static bool ParseValue(string str, out ulong? output)
{
// If the next value is valid
if (ulong.TryParse(str, out ulong value))
{
output = value;
return true;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(str, out long factor);
if (ulong.TryParse(baseVal, out value))
{
output = value * (ulong)factor;
return true;
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (ulong.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
output = value * (ulong)factor;
return true;
}
// The value could not be parsed
output = null;
return false;
}
}
}

View File

@@ -0,0 +1,189 @@
using System;
using System.Globalization;
using System.Text;
namespace MPF.ExecutionContexts.Data
{
/// <summary>
/// Represents an UInt8 flag with an optional trailing value
/// </summary>
public class UInt8Input : Input<byte?>
{
#region Properties
/// <summary>
/// Indicates a minimum value (inclusive) for the flag
/// </summary>
public byte? MinValue { get; set; } = null;
/// <summary>
/// Indicates a maximum value (inclusive) for the flag
/// </summary>
public byte? MaxValue { get; set; } = null;
#endregion
#region Constructors
/// <inheritdoc/>
public UInt8Input(string name)
: base(name) { }
/// <inheritdoc/>
public UInt8Input(string name, bool required)
: base(name, required) { }
/// <inheritdoc/>
public UInt8Input(string shortName, string longName)
: base(shortName, longName) { }
/// <inheritdoc/>
public UInt8Input(string shortName, string longName, bool required)
: base(shortName, longName, required) { }
/// <inheritdoc/>
public UInt8Input(string[] names)
: base(names) { }
/// <inheritdoc/>
public UInt8Input(string[] names, bool required)
: base(names, required) { }
#endregion
/// <inheritdoc/>
public override string Format(bool useEquals)
{
// Do not output if there is no value
if (Value is null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Only output separator and value if needed
if (_required || (!_required && Value != byte.MinValue))
{
// Separator
if (useEquals)
builder.Append('=');
else
builder.Append(' ');
// Value
builder.Append(Value.ToString());
}
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
// Ensure the value exists
if (index + 1 >= parts.Length)
{
Value = _required ? null : byte.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(parts[index + 1], out byte? value) && value is not null)
{
index++;
Value = value;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : byte.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// Check for equal separated
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
{
// Split the string, using the first equal sign as the separator
string[] tempSplit = part.Split('=');
string key = tempSplit[0];
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
// Ensure the value exists
if (string.IsNullOrEmpty(val))
{
Value = _required ? null : byte.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(val, out byte? value) && value is not null)
{
Value = value;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : byte.MinValue;
Value = (MinValue is not null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue is not null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
return false;
}
/// <summary>
/// Parse a value from a string
/// </summary>
private static bool ParseValue(string str, out byte? output)
{
// If the next value is valid
if (byte.TryParse(str, out byte value))
{
output = value;
return true;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(str, out long factor);
if (byte.TryParse(baseVal, out value))
{
output = (byte)(value * factor);
return true;
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (byte.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
output = (byte)(value * factor);
return true;
}
// The value could not be parsed
output = null;
return false;
}
}
}

View File

@@ -0,0 +1,36 @@
namespace MPF.ExecutionContexts.DiscImageCreator
{
/// <summary>
/// Top-level commands for DiscImageCreator
/// </summary>
public static class CommandStrings
{
public const string NONE = "";
public const string Audio = "audio";
public const string AuthPS3 = "authps3";
public const string BluRay = "bd";
public const string Close = "close";
public const string CompactDisc = "cd";
public const string Data = "data";
public const string DigitalVideoDisc = "dvd";
public const string Disk = "disk";
public const string DriveSpeed = "ls";
public const string Eject = "eject";
public const string Floppy = "fd";
public const string GDROM = "gd";
public const string MDS = "mds";
public const string Merge = "merge";
public const string Reset = "reset";
public const string SACD = "sacd";
public const string Start = "start";
public const string Stop = "stop";
public const string Sub = "sub";
public const string Swap = "swap";
public const string Tape = "tape";
public const string Version = "/v";
public const string XBOX = "xbox";
public const string XBOXSwap = "xboxswap";
public const string XGD2Swap = "xgd2swap";
public const string XGD3Swap = "xgd3swap";
}
}

View File

@@ -0,0 +1,102 @@
using SabreTools.RedumpLib.Data;
namespace MPF.ExecutionContexts.DiscImageCreator
{
public static class Converters
{
#region Cross-enumeration conversions
/// <summary>
/// Get the most common known system for a given MediaType
/// </summary>
/// <param name="baseCommand">Command value to check</param>
/// <returns>RedumpSystem if possible, null on error</returns>
public static RedumpSystem? ToRedumpSystem(string baseCommand)
{
return baseCommand switch
{
CommandStrings.Audio => (RedumpSystem?)RedumpSystem.AudioCD,
CommandStrings.CompactDisc
or CommandStrings.Data
or CommandStrings.DigitalVideoDisc
or CommandStrings.Disk
or CommandStrings.Floppy
or CommandStrings.Tape => (RedumpSystem?)RedumpSystem.IBMPCcompatible,
CommandStrings.GDROM
or CommandStrings.Swap => (RedumpSystem?)RedumpSystem.SegaDreamcast,
CommandStrings.BluRay => (RedumpSystem?)RedumpSystem.SonyPlayStation3,
CommandStrings.SACD => (RedumpSystem?)RedumpSystem.SuperAudioCD,
CommandStrings.XBOX
or CommandStrings.XBOXSwap => (RedumpSystem?)RedumpSystem.MicrosoftXbox,
CommandStrings.XGD2Swap
or CommandStrings.XGD3Swap => (RedumpSystem?)RedumpSystem.MicrosoftXbox360,
_ => null,
};
}
/// <summary>
/// Get the MediaType associated with a given base command
/// </summary>
/// <param name="baseCommand">Command value to check</param>
/// <returns>MediaType if possible, null on error</returns>
/// <remarks>This takes the "safe" route by assuming the larger of any given format</remarks>
public static MediaType? ToMediaType(string? baseCommand)
{
return baseCommand switch
{
CommandStrings.Audio
or CommandStrings.CompactDisc
or CommandStrings.Data
or CommandStrings.SACD => (MediaType?)MediaType.CDROM,
CommandStrings.GDROM
or CommandStrings.Swap => (MediaType?)MediaType.GDROM,
CommandStrings.DigitalVideoDisc
or CommandStrings.XBOX
or CommandStrings.XBOXSwap
or CommandStrings.XGD2Swap
or CommandStrings.XGD3Swap => (MediaType?)MediaType.DVD,
CommandStrings.BluRay => (MediaType?)MediaType.BluRay,
// Non-optical
CommandStrings.Floppy => (MediaType?)MediaType.FloppyDisk,
CommandStrings.Disk => (MediaType?)MediaType.HardDisk,
CommandStrings.Tape => (MediaType?)MediaType.DataCartridge,
_ => null,
};
}
/// <summary>
/// Get the default extension for a given disc type
/// </summary>
/// <param name="type">MediaType value to check</param>
/// <returns>Valid extension (with leading '.'), null on error</returns>
public static string? Extension(MediaType? type)
{
#pragma warning disable IDE0072
return type switch
{
MediaType.CDROM
or MediaType.GDROM
or MediaType.Cartridge
or MediaType.HardDisk
or MediaType.CompactFlash
or MediaType.MMC
or MediaType.SDCard
or MediaType.FlashDrive => ".bin",
MediaType.DVD
or MediaType.HDDVD
or MediaType.BluRay
or MediaType.NintendoWiiOpticalDisc => ".iso",
MediaType.LaserDisc
or MediaType.NintendoGameCubeGameDisc => ".raw",
MediaType.NintendoWiiUOpticalDisc => ".wud",
MediaType.FloppyDisk => ".img",
MediaType.Cassette => ".wav",
_ => null,
};
#pragma warning restore IDE0072
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,38 +1,5 @@
namespace MPF.Core.Modules.DiscImageCreator
namespace MPF.ExecutionContexts.DiscImageCreator
{
/// <summary>
/// Top-level commands for DiscImageCreator
/// </summary>
public static class CommandStrings
{
public const string NONE = "";
public const string Audio = "audio";
public const string BluRay = "bd";
public const string Close = "close";
public const string CompactDisc = "cd";
public const string Data = "data";
public const string DigitalVideoDisc = "dvd";
public const string Disk = "disk";
public const string DriveSpeed = "ls";
public const string Eject = "eject";
public const string Floppy = "fd";
public const string GDROM = "gd";
public const string MDS = "mds";
public const string Merge = "merge";
public const string Reset = "reset";
public const string SACD = "sacd";
public const string Start = "start";
public const string Stop = "stop";
public const string Sub = "sub";
public const string Swap = "swap";
public const string Tape = "tape";
public const string Version = "/v";
public const string XBOX = "xbox";
public const string XBOXSwap = "xboxswap";
public const string XGD2Swap = "xgd2swap";
public const string XGD3Swap = "xgd3swap";
}
/// <summary>
/// Dumping flags for DiscImageCreator
/// </summary>
@@ -43,6 +10,7 @@ namespace MPF.Core.Modules.DiscImageCreator
public const string AtariJaguar = "/aj";
public const string BEOpcode = "/be";
public const string C2Opcode = "/c2";
public const string C2OpcodeNew = "/c2new";
public const string CopyrightManagementInformation = "/c";
public const string D8Opcode = "/d8";
public const string DatExpand = "/d";
@@ -50,7 +18,9 @@ namespace MPF.Core.Modules.DiscImageCreator
public const string DVDReread = "/rr";
public const string ExtractMicroSoftCabFile = "/mscf";
public const string Fix = "/fix";
public const string ForceDescrambleSector = "/fdesc";
public const string ForceUnitAccess = "/f";
public const string FullToc = "/fulltoc";
public const string MultiSectorRead = "/mr";
public const string NoFixSubP = "/np";
public const string NoFixSubQ = "/nq";
@@ -69,9 +39,12 @@ namespace MPF.Core.Modules.DiscImageCreator
public const string SeventyFour = "/74";
public const string SkipSector = "/sk";
public const string SubchannelReadLevel = "/s";
public const string Tages = "/t";
public const string Toc = "/toc";
public const string TryReadingPregap = "/trp";
public const string UseAnchorVolumeDescriptorPointer = "/avdp";
public const string VideoNow = "/vn";
public const string VideoNowColor = "/vnc";
public const string VideoNowXP = "/vnx";
}
}
}

View File

@@ -0,0 +1,26 @@
namespace MPF.ExecutionContexts.DiscImageCreator
{
public static class SettingConstants
{
public const string DVDRereadCount = "DICDVDRereadCount";
public const int DVDRereadCountDefault = 10;
public const string MultiSectorRead = "DICMultiSectorRead";
public const bool MultiSectorReadDefault = false;
public const string MultiSectorReadValue = "DICMultiSectorReadValue";
public const int MultiSectorReadValueDefault = 0;
public const string ParanoidMode = "DICParanoidMode";
public const bool ParanoidModeDefault = false;
public const string QuietMode = "DICQuietMode";
public const bool QuietModeDefault = false;
public const string RereadCount = "DICRereadCount";
public const int RereadCountDefault = 20;
public const string UseCMIFlag = "DICUseCMIFlag";
public const bool UseCMIFlagDefault = false;
}
}

View File

@@ -0,0 +1,10 @@
namespace MPF.ExecutionContexts.Dreamdump
{
/// <summary>
/// Top-level commands for Dreamdump
/// </summary>
public static class CommandStrings
{
public const string NONE = "";
}
}

View File

@@ -0,0 +1,15 @@
namespace MPF.ExecutionContexts.Dreamdump
{
/// <summary>
/// Drive sector order option
/// </summary>
public enum SectorOrder
{
NONE = 0,
DATA_C2,
DATA_SUB,
DATA_C2_SUB,
DATA_SUB_C2,
}
}

View File

@@ -0,0 +1,257 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using MPF.ExecutionContexts.Data;
using SabreTools.RedumpLib.Data;
namespace MPF.ExecutionContexts.Dreamdump
{
/// <summary>
/// Represents a generic set of Dreamdump parameters
/// </summary>
public sealed class ExecutionContext : BaseExecutionContext
{
#region Generic Dumping Information
/// <inheritdoc/>
public override string? InputPath
=> (_inputs[FlagStrings.Drive] as StringInput)?.Value?.Trim('"');
/// <inheritdoc/>
public override string? OutputPath => Path.Combine(
(_inputs[FlagStrings.ImagePath] as StringInput)?.Value?.Trim('"') ?? string.Empty,
(_inputs[FlagStrings.ImageName] as StringInput)?.Value?.Trim('"') ?? string.Empty)
+ GetDefaultExtension(MediaType);
/// <inheritdoc/>
public override int? Speed
{
get
{
return (_inputs[FlagStrings.Speed] as Int32Input)?.Value;
}
set
{
if (value is not null && value > 0)
{
this[FlagStrings.Speed] = true;
(_inputs[FlagStrings.Speed] as Int32Input)?.SetValue(value);
}
else
{
this[FlagStrings.Speed] = false;
(_inputs[FlagStrings.Speed] as Int32Input)?.SetValue(null);
}
}
}
#endregion
#region Flag Values
/// <summary>
/// Set of all command flags
/// </summary>
private readonly Dictionary<string, Input> _inputs = new()
{
// Special
[FlagStrings.ForceQTOC] = new FlagInput(FlagStrings.ForceQTOC),
[FlagStrings.Train] = new FlagInput(FlagStrings.Train),
[FlagStrings.Retries] = new UInt8Input(FlagStrings.Retries),
// Paths
[FlagStrings.ImageName] = new StringInput(FlagStrings.ImageName) { Quotes = true },
[FlagStrings.ImagePath] = new StringInput(FlagStrings.ImagePath) { Quotes = true },
// Drive Part
[FlagStrings.ReadOffset] = new Int16Input(FlagStrings.ReadOffset),
[FlagStrings.ReadAtOnce] = new UInt8Input(FlagStrings.ReadAtOnce),
[FlagStrings.Speed] = new UInt16Input(FlagStrings.Speed),
[FlagStrings.SectorOrder] = new StringInput(FlagStrings.SectorOrder),
[FlagStrings.Drive] = new StringInput(FlagStrings.Drive),
};
#endregion
/// <inheritdoc/>
public ExecutionContext(string? parameters) : base(parameters) { }
/// <inheritdoc/>
public ExecutionContext(RedumpSystem? system,
MediaType? type,
string? drivePath,
string filename,
int? driveSpeed,
Dictionary<string, string?> options)
: base(system, type, drivePath, filename, driveSpeed, options)
{
}
#region BaseExecutionContext Implementations
/// <inheritdoc/>
/// <remarks>Command support is irrelevant for Dreamdump</remarks>
public override Dictionary<string, List<string>> GetCommandSupport()
{
return new Dictionary<string, List<string>>()
{
[CommandStrings.NONE] =
[
// Special
FlagStrings.ForceQTOC,
FlagStrings.Train,
FlagStrings.Retries,
// Paths
FlagStrings.ImageName,
FlagStrings.ImagePath,
// Drive Part
FlagStrings.ReadOffset,
FlagStrings.ReadAtOnce,
FlagStrings.Speed,
FlagStrings.SectorOrder,
FlagStrings.Drive,
],
};
}
/// <inheritdoc/>
public override string GenerateParameters()
{
var parameters = new StringBuilder();
// Loop though and append all existing
foreach (var kvp in _inputs)
{
// If the value doesn't exist
string formatted = kvp.Value.Format(useEquals: true);
if (formatted.Length == 0)
continue;
// Append the parameter
parameters.Append($"{formatted} ");
}
return parameters.ToString().TrimEnd();
}
/// <inheritdoc/>
public override string? GetDefaultExtension(MediaType? mediaType) => ".bin";
/// <inheritdoc/>
public override MediaType? GetMediaType() => SabreTools.RedumpLib.Data.MediaType.GDROM;
/// <inheritdoc/>
public override bool IsDumpingCommand() => true;
/// <inheritdoc/>
protected override void ResetValues()
{
BaseCommand = CommandStrings.NONE;
flags = [];
foreach (var kvp in _inputs)
kvp.Value.ClearValue();
}
/// <inheritdoc/>
protected override void SetDefaultParameters(string? drivePath,
string filename,
int? driveSpeed,
Dictionary<string, string?> options)
{
BaseCommand = CommandStrings.NONE;
if (drivePath is not null)
{
this[FlagStrings.Drive] = true;
(_inputs[FlagStrings.Drive] as StringInput)?.SetValue(drivePath);
}
if (driveSpeed is not null && driveSpeed > 0)
{
this[FlagStrings.Speed] = true;
(_inputs[FlagStrings.Speed] as UInt16Input)?.SetValue((ushort)driveSpeed);
}
else
{
this[FlagStrings.Speed] = false;
(_inputs[FlagStrings.Speed] as UInt16Input)?.SetValue(null);
}
// Set user-defined options
string? sectorOrder = GetStringSetting(options, SettingConstants.SectorOrder, SettingConstants.SectorOrderDefault);
if (!string.IsNullOrEmpty(sectorOrder) && sectorOrder != SectorOrder.NONE.ToString())
{
this[FlagStrings.SectorOrder] = true;
(_inputs[FlagStrings.SectorOrder] as StringInput)?.SetValue(sectorOrder!);
}
// Set the output paths
if (!string.IsNullOrEmpty(filename))
{
var imagePath = Path.GetDirectoryName(filename);
if (!string.IsNullOrEmpty(imagePath))
{
this[FlagStrings.ImagePath] = true;
(_inputs[FlagStrings.ImagePath] as StringInput)?.SetValue(imagePath!);
}
string imageName = Path.GetFileNameWithoutExtension(filename);
if (!string.IsNullOrEmpty(imageName))
{
this[FlagStrings.ImageName] = true;
(_inputs[FlagStrings.ImageName] as StringInput)?.SetValue(imageName!);
}
}
byte retries = GetUInt8Setting(options, SettingConstants.RereadCount, SettingConstants.RereadCountDefault);
if (retries > 0)
{
this[FlagStrings.Retries] = true;
(_inputs[FlagStrings.Retries] as UInt8Input)?.SetValue(retries);
}
}
/// <inheritdoc/>
protected override bool ValidateAndSetParameters(string? parameters)
{
// The string has to be valid by itself first
if (string.IsNullOrEmpty(parameters))
return false;
// Now split the string into parts for easier validation
string[] parts = SplitParameterString(parameters!);
// Setup the modes
BaseCommand = null;
// Loop through all auxiliary flags, if necessary
int index = 0;
for (int i = index; i < parts.Length; i++)
{
// Match all possible flags
foreach (var kvp in _inputs)
{
// If the value was not a match
if (!kvp.Value.Process(parts, ref i))
continue;
// Set the flag
this[kvp.Key] = true;
}
}
// If the image name was not set, set it with a default value
if (string.IsNullOrEmpty((_inputs[FlagStrings.ImageName] as StringInput)?.Value))
(_inputs[FlagStrings.ImageName] as StringInput)?.SetValue($"track_{DateTime.Now:yyyyMMdd-HHmm}");
return true;
}
#endregion
}
}

View File

@@ -0,0 +1,33 @@
namespace MPF.ExecutionContexts.Dreamdump
{
/// <summary>
/// Dumping flags for Dreamdump
/// </summary>
public static class FlagStrings
{
#region Special
public const string ForceQTOC = "--force-qtoc";
public const string Train = "--train";
public const string Retries = "--retries";
#endregion
#region Paths
public const string ImageName = "--image-name";
public const string ImagePath = "--image-path";
#endregion
#region Drive Part
public const string ReadOffset = "--read-offset";
public const string ReadAtOnce = "--read-at-once"; // [0,40] (Linux), [0,20] (Windows)
public const string Speed = "--speed";
public const string SectorOrder = "--sector-order";
public const string Drive = "--drive";
#endregion
}
}

View File

@@ -0,0 +1,11 @@
namespace MPF.ExecutionContexts.Dreamdump
{
public static class SettingConstants
{
public const string RereadCount = "DreamdumpRereadCount";
public const int RereadCountDefault = 20;
public const string SectorOrder = "DreamdumpSectorOrder";
public static readonly string SectorOrderDefault = Dreamdump.SectorOrder.NONE.ToString();
}
}

View File

@@ -0,0 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Assembly Properties -->
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<IncludeSymbols>true</IncludeSymbols>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<VersionPrefix>3.6.0</VersionPrefix>
<WarningsNotAsErrors>NU5104</WarningsNotAsErrors>
<!-- Package Properties -->
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Description>Common code for all MPF execution contexts</Description>
<Copyright>Copyright (c) Matt Nadareski 2019-2025</Copyright>
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
<RepositoryType>git</RepositoryType>
</PropertyGroup>
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="MPF.ExecutionContexts.Test" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.RedumpLib" Version="[1.9.1]" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,13 @@
# MPF.ExecutionContexts
This library represents the logic needed to invoke 3 different dumping programs:
- [Aaru](github.com/aaru-dps/Aaru)
- [DiscImageCreator](github.com/saramibreak/DiscImageCreator)
- [Redumper](https://github.com/superg/redumper)
These execution wrappers allow for generating valid parameters for each of the programs as well as provide some helpers that make it easier to determine what those parameters are.
External options are defined in order to help create reasonable default parameter sets for different combinations of media type and system.
Paths to the programs need to be provided if they are expected to be invoked as a part of another program. The expected versions of these programs can be found in either the changelog or the publish script in the parent project.

View File

@@ -0,0 +1,32 @@
namespace MPF.ExecutionContexts.Redumper
{
/// <summary>
/// Top-level commands for Redumper
/// </summary>
public static class CommandStrings
{
public const string NONE = "";
public const string Disc = "disc";
public const string Rings = "rings";
public const string Dump = "dump";
public const string DumpExtra = "dump::extra";
public const string Refine = "refine";
public const string Verify = "verify";
public const string DVDKey = "dvdkey";
public const string Eject = "eject";
public const string DVDIsoKey = "dvdisokey";
public const string Protection = "protection";
public const string Split = "split";
public const string Hash = "hash";
public const string Info = "info";
public const string Skeleton = "skeleton";
public const string FlashMT1339 = "flash::mt1339";
public const string FlashSD616 = "flash::sd616";
public const string FlashPlextor = "flash::plextor";
public const string Subchannel = "subchannel";
public const string Debug = "debug";
public const string FixMSF = "fixmsf";
public const string DebugFlip = "debug::flip";
public const string DriveTest = "drive::test";
}
}

View File

@@ -0,0 +1,34 @@
using SabreTools.RedumpLib.Data;
namespace MPF.ExecutionContexts.Redumper
{
public static class Converters
{
#region Cross-enumeration conversions
/// <summary>
/// Get the default extension for a given disc type
/// </summary>
/// <param name="type">MediaType value to check</param>
/// <returns>Valid extension (with leading '.'), null on error</returns>
public static string? Extension(MediaType? type)
{
#pragma warning disable IDE0072
return type switch
{
MediaType.CDROM
or MediaType.GDROM => ".bin",
MediaType.DVD
or MediaType.HDDVD
or MediaType.BluRay
or MediaType.NintendoWiiOpticalDisc => ".iso",
MediaType.NintendoGameCubeGameDisc => ".raw",
MediaType.NintendoWiiUOpticalDisc => ".wud",
_ => null,
};
#pragma warning restore IDE0072
}
#endregion
}
}

Some files were not shown because too many files have changed in this diff Show More