Compare commits

..

166 Commits
3.2.4 ... 3.3.0

Author SHA1 Message Date
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
205 changed files with 15286 additions and 5104 deletions

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

@@ -0,0 +1,40 @@
name: Build and Test
on:
push:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
6.0.x
8.0.x
9.0.x
- name: Run tests
run: dotnet test
- name: Run publish script
run: ./publish-nix.sh -dp
- name: Upload to rolling
uses: ncipollo/release-action@v1.14.0
with:
allowUpdates: True
artifacts: "*.nupkg,*.snupkg,*.zip"
body: 'Last built commit: ${{ github.sha }}'
name: 'Rolling Release'
prerelease: True
replacesArtifacts: True
tag: "rolling"
updateOnlyUnreleased: True

View File

@@ -1,53 +0,0 @@
name: MPF Check
on:
push:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
project: [MPF.Check]
runtime: [win-x86, win-x64, win-arm64, linux-x64, linux-arm64, osx-x64, osx-arm64]
framework: [net9.0] #[net20, net35, net40, net452, net472, net48, netcoreapp3.1, net5.0, net6.0, net7.0, net8.0, net9.0]
conf: [Debug] #[Release, Debug]
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet publish ${{ matrix.project }}/${{ matrix.project }}.csproj -f ${{ matrix.framework }} -r ${{ matrix.runtime }} -c ${{ matrix.conf == 'Release' && 'Release -p:DebugType=None -p:DebugSymbols=false' || 'Debug'}} --self-contained true --version-suffix ${{ github.sha }} ${{ (startsWith(matrix.framework, 'net5') || startsWith(matrix.framework, 'net6') || startsWith(matrix.framework, 'net7') || startsWith(matrix.framework, 'net8') || startsWith(matrix.framework, 'net9')) && '-p:PublishSingleFile=true' || ''}}
- name: Archive build
run: |
cd ${{ matrix.project }}/bin/${{ matrix.conf }}/${{ matrix.framework }}/${{ matrix.runtime }}/publish/
zip -r ${{ github.workspace }}/${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}.zip ./
- name: Upload build
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}
path: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}.zip
- name: Upload to rolling
uses: ncipollo/release-action@v1.14.0
with:
allowUpdates: True
artifacts: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}.zip
body: 'Last built commit: ${{ github.sha }}'
name: 'Rolling Release'
prerelease: True
replacesArtifacts: True
tag: "rolling"
updateOnlyUnreleased: True

View File

@@ -1,53 +0,0 @@
name: MPF CLI
on:
push:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
project: [MPF.CLI]
runtime: [win-x86, win-x64, win-arm64, linux-x64, linux-arm64, osx-x64, osx-arm64]
framework: [net9.0] #[net20, net35, net40, net452, net472, net48, netcoreapp3.1, net5.0, net6.0, net7.0, net8.0, net9.0]
conf: [Debug] #[Release, Debug]
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet publish ${{ matrix.project }}/${{ matrix.project }}.csproj -f ${{ matrix.framework }} -r ${{ matrix.runtime }} -c ${{ matrix.conf == 'Release' && 'Release -p:DebugType=None -p:DebugSymbols=false' || 'Debug'}} --self-contained true --version-suffix ${{ github.sha }} ${{ (startsWith(matrix.framework, 'net5') || startsWith(matrix.framework, 'net6') || startsWith(matrix.framework, 'net7') || startsWith(matrix.framework, 'net8') || startsWith(matrix.framework, 'net9')) && '-p:PublishSingleFile=true' || ''}}
- name: Archive build
run: |
cd ${{ matrix.project }}/bin/${{ matrix.conf }}/${{ matrix.framework }}/${{ matrix.runtime }}/publish/
zip -r ${{ github.workspace }}/${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}.zip ./
- name: Upload build
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}
path: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}.zip
- name: Upload to rolling
uses: ncipollo/release-action@v1.14.0
with:
allowUpdates: True
artifacts: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}.zip
body: 'Last built commit: ${{ github.sha }}'
name: 'Rolling Release'
prerelease: True
replacesArtifacts: True
tag: "rolling"
updateOnlyUnreleased: True

View File

@@ -1,61 +0,0 @@
name: Nuget Pack
on:
push:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore
- name: Pack
run: dotnet pack
- name: Upload Execution Contexts package
uses: actions/upload-artifact@v4
with:
name: 'Execution Contexts Package'
path: 'MPF.ExecutionContexts/bin/Release/*.nupkg'
- name: Upload Execution Contexts to rolling
uses: ncipollo/release-action@v1.14.0
with:
allowUpdates: True
artifacts: 'MPF.ExecutionContexts/bin/Release/*.nupkg'
body: 'Last built commit: ${{ github.sha }}'
name: 'Rolling Release'
prerelease: True
replacesArtifacts: True
tag: "rolling"
updateOnlyUnreleased: True
- name: Upload Processors package
uses: actions/upload-artifact@v4
with:
name: 'Processors Package'
path: 'MPF.Processors/bin/Release/*.nupkg'
- name: Upload Execution Contexts to rolling
uses: ncipollo/release-action@v1.14.0
with:
allowUpdates: True
artifacts: 'MPF.Processors/bin/Release/*.nupkg'
body: 'Last built commit: ${{ github.sha }}'
name: 'Rolling Release'
prerelease: True
replacesArtifacts: True
tag: "rolling"
updateOnlyUnreleased: True

View File

@@ -1,67 +0,0 @@
name: MPF UI
on:
push:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
project: [MPF.UI]
runtime: [win-x86, win-x64]
framework: [net9.0-windows] #[net40, net452, net472, net48, netcoreapp3.1, net5.0-windows, net6.0-windows, net7.0-windows, net8.0-windows, net9.0-windows]
conf: [Debug] #[Release, Debug]
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet publish ${{ matrix.project }}/${{ matrix.project }}.csproj -f ${{ matrix.framework }} -r ${{ matrix.runtime }} -c ${{ matrix.conf == 'Release' && 'Release -p:DebugType=None -p:DebugSymbols=false' || 'Debug'}} --self-contained true --version-suffix ${{ github.sha }} ${{ (startsWith(matrix.framework, 'net5') || startsWith(matrix.framework, 'net6') || startsWith(matrix.framework, 'net7') || startsWith(matrix.framework, 'net8') || startsWith(matrix.framework, 'net9')) && '-p:PublishSingleFile=true' || ''}}
- name: Bundle DiscImageCreator
run: |
wget https://github.com/user-attachments/files/17211434/DiscImageCreator_20241001.zip
unzip -u DiscImageCreator_20241001.zip
mkdir -p MPF.UI/bin/${{ matrix.conf }}/${{ matrix.framework }}/${{ matrix.runtime }}/publish/Programs/Creator
mv Release_ANSI/* MPF.UI/bin/${{ matrix.conf }}/${{ matrix.framework }}/${{ matrix.runtime }}/publish/Programs/Creator/
- name: Bundle Redumper
run: |
wget https://github.com/superg/redumper/releases/download/build_438/redumper-2024.11.03_build438-win64.zip
unzip redumper-2024.11.03_build438-win64.zip
mkdir -p MPF.UI/bin/${{ matrix.conf }}/${{ matrix.framework }}/${{ matrix.runtime }}/publish/Programs/Redumper
mv redumper-2024.11.03_build438-win64/bin/redumper.exe MPF.UI/bin/${{ matrix.conf }}/${{ matrix.framework }}/${{ matrix.runtime }}/publish/Programs/Redumper/
- name: Archive build
run: |
cd ${{ matrix.project }}/bin/${{ matrix.conf }}/${{ matrix.framework }}/${{ matrix.runtime }}/publish/
zip -r ${{ github.workspace }}/${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}.zip ./
- name: Upload build
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}
path: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}.zip
- name: Upload to rolling
uses: ncipollo/release-action@v1.14.0
with:
allowUpdates: True
artifacts: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}.zip
body: 'Last built commit: ${{ github.sha }}'
name: 'Rolling Release'
prerelease: True
replacesArtifacts: True
tag: "rolling"
updateOnlyUnreleased: True

View File

@@ -11,13 +11,16 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
dotnet-version: |
6.0.x
8.0.x
9.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
run: dotnet build
- name: Test
run: dotnet test --no-restore --verbosity normal
run: dotnet test

1
.gitignore vendored
View File

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

16
.vscode/launch.json vendored
View File

@@ -5,7 +5,7 @@
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (console)",
"name": ".NET Core Launch (Check)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
@@ -18,6 +18,20 @@
"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/net9.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 Attach",
"type": "coreclr",

View File

@@ -1,3 +1,168 @@
### 3.3.0 (2025-01-03)
- Update packages
- Add skeleton test projects for individual libraries
- Move existing tests to new projects
- Add BaseProcessor tests
- Add processor base implementation tests
- Ensure SS.bin only required for DVD
- Update tests to account for new file count
- Add tests around some Aaru helpers
- Add tests around CleanRip helpers
- Fix CleanRip test access
- Add tests around XBC helpers
- Fix failing XBC test
- Perform better path emptiness checks
- Add tests around UIC helpers
- Add tests around PS3 CFW helpers
- Enable test running on package and PR
- Fix missing test data
- Add tests around Redumper helpers
- Add sanity check output file tests
- Add tests around DIC helpers
- Add safety around sidecar generation
- Use recommended Min/Max/TryParse
- Add tests around ProcessingTool
- Add BaseExecutionContext tests
- Add currently unused Input type
- Split Input type into typed classes
- Add flag for value being set
- Add unused inputs to Aaru
- Add self-formatting to Input types
- Handle issue with old .NET
- Let inputs read equal-separated values
- Fix some formatting issues with Input types
- Replace Aaru pre-command flags
- Use string builders where possible
- Add Aaru parameters tests
- Replace Aaru flag values with input types
- Add Redumper parameters tests
- Add quotes option to string input
- Replace Redumper flag values with input types
- Add DIC parameters tests
- Add unused min/max parameters for numeric inputs
- Add Int32 array input type
- Wire up input boundaries
- Fix required Int32 array input
- Ensure dumping commands are tested
- Add tests around default values
- Increase sleep time in queue
- Unify queue handling in processing queue
- Add non-tools frontend tests
- Update RedumpLib to 1.6.1
- Ensure consistency in frontend code
- Ensure Redumper support matrix is consistent
- Add FrontendTool tests
- Update protection tool tests
- Remove unnecessary namespace prefixes
- Clean up original Drive tests
- Add debug flag to publish scripts
- Add gated program downloads to publish scripts
- Migrate to using publish script for GHA
- Update README to remove AppVeyor references
- Remove unused gated using statement
- Add alternate config location
- Add safety check around empty config files
- Add launch config for CLI
- Remove unnecessary re-splitting of path
- Always filter out game engines and packers
- Remove now-redundant option
- Always omit EA CD-Key
- Add packer filtering tests
- Simplify prefix filtering
- Fix issue with odd quoting
- Add DumpingParameters for DIC and Redumper
- Better deal with volume labels
- Fix bug with volume labels
- Slight formatting tweaks
- Update BOS to 3.3.2
- Enable handling non-SS Xbox discs
- Use proper base path for redumper output check
- Verify securom sector count
- Update packages
- Simplify direct package references
- Remove vestigial progress indicators
- Remove non-working last line log code
- Fix access level for log queue
- Fix access level for log document
- Simplify ProcessLogLine method
- Use explicit InvokeAsync when possible
- (EXPERIMENTAL) Skip log line queue
- Fully remove processing queue code
- Introduce maximum log length
- Print PS4/PS5 app.pkg info
- Ensure .NET versions are installed for testing
- Remove use of psxt001
- Minor formatting tweaks; add TODO
- Use simpler cuesheet reader in Redumper
- Fix now-incorrect test values
- Better SecuROM handling for DIC and Redumper
- Include native libraries for self-extract
- Preserve program metadata on publish
- Allow symbols to be packed
- Fix important typo
- Remove vestigial configuration file
- Remove reference to removed file
- Add README files for two libraries
- Simplify output name assembly logic
- Fix output name null edge case
- Selectively rebuild program list
- Use IBM PC as default system out of the box
- Separate params checkbox from input
- Disable more UI elements when editing
- Ensure parameters checkbox is enabled to start
- Fix log line for default system use
- Retire and replace blue secret text
- Enable tabs in input fields by default
- Adjust row count in protection options
- Pedantic GUI changes
- More pendantic GUI changes
- Remove unused progress bar
- Disable all UI elements on protect scan
- Account for menu items for disable/enable
- Allow check and IRD most of the time
- Check for partial dumps
- Slightly reduce nesting of file pre-dump checks
- Slightly increase nesting of file pre-dump checks
- Improve system detection
- Avoid unnecessary null checks
- Pass options to process user info separately
- Use internal options instead of external
- Use Invoke explicitly for delegates
- Wrap log compression in a thread
- Do not display invalid credentials on empty
- Tab input only needed for ringcodes
- More fields behind RedumpCompatible option
- Parse redumper BIG.DAT info
- Unify DisplayUserMessage definitions
- Clean up unused disabled warnings
- Missed one
- Minor UI changes
- Hide empty partially matched list
- Reenable XGD1 PVD reporting
- Improve PS4/PS5 parsing
- Don't add special field keys with no reason
- Add pure-getkey output names for PS3CFW
- Partially clean up PS3CFW
- Wrap some PhysicalTool method calls
- Minor UI and other fixes
- Force path update if default changed
- Force showing tooltips on disabled items
- Update RedumpLib to 1.6.3
- Minor UI changes to DIW
- Be consistent with filename extensions
- Remove unnecessary action step
- Update copyright
- Update BinaryObjectScanner to 3.3.4
- Add and use internal program short names
- Fix BinaryObjectScanner update
- Fix short name test
- Update RedumpLib to 1.6.4
- Fix misunderstanding on perfect offset
- Handle SCSI error count
- Update to DIC 20250101
- Fix system detection logging
### 3.2.4 (2024-11-24)
- Update Redumper to build 438
@@ -193,7 +358,7 @@
- Add include artifacts flag for check, sanitize options
- Remove old --protect-file mentions (JohnVeness)
- Update RedumpLib to 1.4.1
- Enable loading seed JSON (Deterous)
- Enable loading seed JSON
### 3.2.0 (2024-06-20)
@@ -269,7 +434,7 @@
- Clean up usings
- Remove automatic eject and reset options
- Remove options from UI
- Remove firmware output for Redumper (Deterous)
- Remove firmware output for Redumper
- Merge EnumConverter and EnumExtensions
- Move event args to root of Core
- Move processing queue to root of Core
@@ -309,7 +474,7 @@
- Rename main application to MPF.UI
- Fix build scripts
- Make protection file output required
- Standardize PS1-5 outputs and parsing (Deterous)
- Standardize PS1-5 outputs and parsing
- Update Redumper to build 371
- Tools always run in separate window
- Move ConsoleLogger to Check CLI
@@ -385,22 +550,22 @@
### 3.1.9 (2024-05-19)
- Update Redumper to build 325
- Fix CleanRip not pulling info (Deterous)
- Fix XboxOne/XboxSX Filename bug (Deterous)
- Trim PIC for XboxOne/XboxSX (Deterous)
- Fix CleanRip not pulling info
- Fix XboxOne/XboxSX Filename bug
- Trim PIC for XboxOne/XboxSX
- Get volume label from UIC outputs
- Add site code listing to Check
- Update RedumpLib and related
- Update BinaryObjectScanner to 3.1.11
- Remove now-unused Hash enum
- Use IO implementation of IniFile
- Add Xbox Backup Creator support to MPF.Check (Deterous)
- Add Xbox Backup Creator support to MPF.Check
- Update BinaryObjectScanner to 3.1.12
- Prefer PlayStation info from Redumper logs (Deterous)
- Prefer PlayStation info from Redumper logs
### 3.1.8 (2024-05-09)
- Option for default Redumper leadin retries (Deterous)
- Option for default Redumper leadin retries
- Omit false positives on formatting protections
- Critical update to BinaryObjectScanner 3.1.10
- Add _PFI.bin support for UIC
@@ -411,9 +576,9 @@
### 3.1.6 (2024-04-27)
- Fix parameter parsing for `=` symbol (Deterous)
- Define better default categories (Deterous)
- Custom non-redump Redumper options (Deterous)
- Fix parameter parsing for `=` symbol
- Define better default categories
- Custom non-redump Redumper options
- Update packages
- Update packages
@@ -430,10 +595,10 @@
- Fix information pulling for redumper (fuzz6001)
- Update packages
- Update BinaryObjectScanner to 3.1.4
- Detect Xbox Series X discs (Deterous)
- Detect Xbox Series X discs
- Enable Windows targeting for test project
- Fix test project project includes
- Fix CleanRip hash output for Check (Deterous)
- Fix CleanRip hash output for Check
- Enable label-side mastering SID and toolstamp
- Enable remaining fields for label-side information
- Update BinaryObjectScanner to 3.1.5
@@ -450,38 +615,38 @@
- Remove GHA pull request builds
- Add PR check workflow
- Don't link to AppVeyor artifacts page anymore
- Add PS3 CFW support to MPF.Check (Deterous)
- Hide size if value is 0 (Deterous)
- Fix title normalization (Deterous)
- Add PS3 CFW support to MPF.Check
- Hide size if value is 0
- Fix title normalization
- Ensure no labels are empty
- Use SabreTools.Hashing
- Update to SabreTools.RedumpLib 1.3.5
- Update packages to latest
- Enable LibIRD for all .NET frameworks (Deterous)
- Enable LibIRD for all .NET frameworks
- Try updating PR check action
- Fix config access persmission (Deterous)
- Fix Check UI deadlock (Deterous)
- Fix config access persmission
- Fix Check UI deadlock
- Fix formatting output formatting
- Update LibIRD to 0.9.0 (Deterous)
- Update LibIRD to 0.9.0
- Update packages
- Fix Redumper generic drive type (Deterous)
- Add MPF version to Submission info (Deterous)
- Fix Redumper generic drive type
- Add MPF version to Submission info
- Update to RedumpLib 1.3.6
### 3.1.2 (2024-02-27)
- Remove debugging lines from build script
- Port build script fixes from BOS
- Fix double git hash version (feat. Deterous)
- Fix double git hash version
- Readd x86 builds by default
- Hide unavailable dumping programs (Deterous)
- Hide unavailable dumping programs
- Remove DIC and Aaru bundles from CI
- Add x86 builds to AppVeyor
- Make AppVeyor builds framework-dependent
- Fix misattributed artifact
- Update README with current build instructions
- Opt-in automatic IRD creation after PS3 dump (Deterous)
- Add CI via Github Workflows (Deterous)
- Opt-in automatic IRD creation after PS3 dump
- Add CI via Github Workflows
- Reorganize solution items
- Split CI workflow files
- Add GHA CI status badges
@@ -511,19 +676,19 @@
- Show hashes in readonly data
- Update to BinaryObjectScanner 3.1.0
- Add Mattel HyperScan detection
- Pull PS3 Disc Key from redump (Deterous)
- Pull PS3 Disc Key from redump
### 3.1.1 (2024-02-20)
- Remove .NET 6 from auto-builds
- Make Redumper the default for new users
- Fix DIC log parsing for SS version (Deterous)
- Fix DIC log parsing for SS version
- Write outputs with UTF-8
- Add funworld Photo Play detection
- Fix Aaru drive parameter generation
- Limit DVD protection outputs
- Add a GUI for PS3 IRD Creation (Deterous)
- Update LibIRD, disable UI elements when creating IRD (Deterous)
- Add a GUI for PS3 IRD Creation
- Update LibIRD, disable UI elements when creating IRD
### 3.1.0 (2024-02-06)
@@ -531,33 +696,33 @@
- Update Redumper to build 294
- Fix commented out code
- Make missing hash data clearer
- Get BD PIC Identifier for redumper (Deterous)
- Support redumper skeleton and hash files (Deterous)
- Get BD PIC Identifier for redumper
- Support redumper skeleton and hash files
- Support ringcode and PIC for triple/quad-layer (fuzz6001)
- Cleanup !protectionInfo.txt (Deterous)
- Update Redumper to build 311 (Deterous)
- Use PSX/PS2 serial as filename when Volume Label not present (Deterous)
- Allow variables in output path (Deterous)
- Check for presence of complete dump from other programs (Deterous)
- Retrieve volume label from logs (Deterous)
- Cleanup !protectionInfo.txt
- Update Redumper to build 311
- Use PSX/PS2 serial as filename when Volume Label not present
- Allow variables in output path
- Check for presence of complete dump from other programs
- Retrieve volume label from logs
- Correct missing space in PVD (fuzz6001)
- Prevent crashing on invalid parameters (Deterous)
- Detect CDTV discs (Deterous)
- Differentiate CD32 from CDTV (Deterous)
- Normalise Disc Titles in Submission Info (Deterous)
- Prevent crashing on invalid parameters
- Detect CDTV discs
- Differentiate CD32 from CDTV
- Normalise Disc Titles in Submission Info
- Skip warning line in Redumper log
- Add a GUI for MPF.Check (Deterous)
- Add a GUI for MPF.Check
- Fix information pulling for CleanRip and UIC
- Add UMD handling for the disc info window
- Detect Photo CD
- Parse PSX/PS2/KP2 exe date from logs (Deterous)
- Exclude extra tracks when finding disc matches (Deterous)
- Verbose Redumper log by default (Deterous)
- Parse PSX/PS2/KP2 exe date from logs
- Exclude extra tracks when finding disc matches
- Verbose Redumper log by default
- Retrieve serial from Cleanrip
- Fix build from rushed code
- Remove `-disc2` from Cleanrip serial
- Enable Windows builds on Linux and Mac
- Fix compiler warning (Deterous)
- Fix compiler warning
### 3.0.3 (2023-12-04)
@@ -645,15 +810,15 @@
### 2.7.5 (2023-11-06)
- Remove psxt001z Pkg Ref in MPF.Test (Deterous)
- Remove psxt001z Pkg Ref in MPF.Test
- Update Redumper to build 247
- Focus main window after child window closes (Deterous)
- Focus main window after child window closes
- Try to get PS3 data from SFB
- Fix PS3 version finding
- Pull PS3 Firmware Version (Deterous)
- Pull PS3 Firmware Version
- Fix default layerbreak output
- Enable browsing for Redumper path (Deterous)
- Update to MMI 3.0.0 (Deterous)
- Enable browsing for Redumper path
- Update to MMI 3.0.0
### 2.7.4 (2023-10-31)
@@ -674,7 +839,7 @@
- Compile most regex statements
- Handle a couple of messages
- Remove .manufacturer for Bluray
- Fix typo that disables DIC during media check (Deterous)
- Fix typo that disables DIC during media check
- Fix build
- Remove duplicate check
- Add PIC output for Redumper
@@ -703,7 +868,7 @@
- Add filename suffix setting (nw)
- Wire through filename suffix
- Expose suffix setting
- Set UDF CD threshold at 800MB (Deterous)
- Set UDF CD threshold at 800MB
- Update package versions
- Attempt to parse out PS5 params.json
- Fix CRC32 hashing
@@ -712,7 +877,7 @@
- Update to MMI 3.0.0-preview.4
- Fix two small nullability issues
- Use Array.Empty in hasher
- Always use relative path internally (Deterous)
- Always use relative path internally
### 2.7.2 (2023-10-17)
@@ -720,9 +885,9 @@
- Cleanup and gated code
- Gate some switch expressions
- Suppress some unnecessary messages
- Disable dumping button when Redumper selected with unsupported media type (Deterous)
- Improve check for which program supports which media (Deterous)
- Remove code for getting Universal Hash from DIC logs (Deterous)
- Disable dumping button when Redumper selected with unsupported media type
- Improve check for which program supports which media
- Remove code for getting Universal Hash from DIC logs
- Fix Redumper retry count not showing
- Enable parameters checkbox by default
- Update Redumper to build 230
@@ -742,7 +907,7 @@
- Unify handling of enable/disable events
- Enable nullability in Check
- Remove all but .NET 6 for AppVeyor packaging
- Place message boxes at center of main window (Deterous)
- Place message boxes at center of main window
- Enable nullability in MPF
- Enable nullability in MPF.UI.Core
- Enable nullability in MPF.Test
@@ -778,7 +943,7 @@
- Be smarter about media type based on system
- Consolidate into MPF.Core
- Fix failing tests
- Remove debug symbols in release builds (Deterous)
- Remove debug symbols in release builds
- Allow nullability for modern .NET
- Fix failing tests
- Remove unnecessary include
@@ -786,7 +951,7 @@
- Move LogLevel enumeration
- Split logging code a bit more
- Split info window code a bit more
- Clarify build instructions in README (Deterous)
- Clarify build instructions in README
- Split options window code a bit more
- Use binding for more disc info textboxes
- Handle Redump password changing better
@@ -812,7 +977,7 @@
- Fix media type ordering
- Fix dumping button not enabling
- Recentralize some Check functionality
- Fix media combobox not updating (Deterous)
- Fix media combobox not updating
### 2.6.6 (2023-10-04)
@@ -861,7 +1026,7 @@
- Handle extension changing only
- Swap order of operations for changing program
- Fix dumping path in DD
- Fix PlayStation serial code region parsing (Deterous)
- Fix PlayStation serial code region parsing
- Retrofit README
- Migrate to Nuget package for Redump
- Remove dd for Windows

View File

@@ -5,19 +5,20 @@
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.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.2.4</VersionPrefix>
<VersionPrefix>3.3.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-2024</Copyright>
<Copyright>Copyright (c) Matt Nadareski 2019-2025</Copyright>
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
<RepositoryType>git</RepositoryType>
@@ -42,14 +43,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="BinaryObjectScanner" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="3.2.3" GeneratePathProperty="true">
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="SabreTools.RedumpLib" Version="1.5.2" />
</ItemGroup>
<ItemGroup>
<Content Include="$(PkgBinaryObjectScanner)\content\**" PackagePath="contentFiles\any\any;content" CopyToOutputDirectory="Always" PackageCopyToOutput="true" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.4" />
</ItemGroup>
</Project>

View File

@@ -3,7 +3,6 @@ using System.IO;
#if NET40
using System.Threading.Tasks;
#endif
using BinaryObjectScanner;
using MPF.Frontend;
using MPF.Frontend.Tools;
using SabreTools.RedumpLib.Data;
@@ -48,16 +47,19 @@ namespace MPF.CLI
}
// Validate the supplied credentials
bool? validated = RedumpClient.ValidateCredentials(options.RedumpUsername ?? string.Empty, options.RedumpPassword ?? string.Empty).GetAwaiter().GetResult();
string message = validated switch
if (!string.IsNullOrEmpty(options.RedumpUsername) && !string.IsNullOrEmpty(options.RedumpPassword))
{
true => "Redump username and password accepted!",
false => "Redump username and password denied!",
null => "An error occurred validating your credentials!",
};
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!",
};
if (!string.IsNullOrEmpty(message))
Console.WriteLine(message);
if (!string.IsNullOrEmpty(message))
Console.WriteLine(message);
}
// Process any custom parameters
int startIndex = 2;
@@ -124,15 +126,9 @@ namespace MPF.CLI
}
env.SetExecutionContext(paramStr);
// Make new Progress objects
var resultProgress = new Progress<ResultEventArgs>();
resultProgress.ProgressChanged += ConsoleLogger.ProgressUpdated;
var protectionProgress = new Progress<ProtectionProgress>();
protectionProgress.ProgressChanged += ConsoleLogger.ProgressUpdated;
// Invoke the dumping program
Console.WriteLine($"Invoking {options.InternalProgram} using '{paramStr}'");
var dumpResult = env.Run(resultProgress).GetAwaiter().GetResult();
var dumpResult = env.Run().GetAwaiter().GetResult();
Console.WriteLine(dumpResult.Message);
if (!dumpResult)
return;
@@ -158,7 +154,7 @@ namespace MPF.CLI
}
// Finally, attempt to do the output dance
var verifyResult = env.VerifyAndSaveDumpOutput(resultProgress, protectionProgress)
var verifyResult = env.VerifyAndSaveDumpOutput()
.ConfigureAwait(false).GetAwaiter().GetResult();
Console.WriteLine(verifyResult.Message);
}
@@ -228,12 +224,12 @@ namespace MPF.CLI
if (args[startIndex].StartsWith("-u=") || args[startIndex].StartsWith("--use="))
{
string internalProgram = args[startIndex].Split('=')[1];
options.InternalProgram = Frontend.Options.ToInternalProgram(internalProgram);
options.InternalProgram = internalProgram.ToInternalProgram();
}
else if (args[startIndex] == "-u" || args[startIndex] == "--use")
{
string internalProgram = args[startIndex + 1];
options.InternalProgram = Frontend.Options.ToInternalProgram(internalProgram);
options.InternalProgram = internalProgram.ToInternalProgram();
startIndex++;
}

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

@@ -1,25 +0,0 @@
using System;
using BinaryObjectScanner;
using MPF.Frontend;
namespace MPF.Check
{
public static class ConsoleLogger
{
/// <summary>
/// Simple process counter to write to console
/// </summary>
public static void ProgressUpdated(object? sender, ResultEventArgs value)
{
Console.WriteLine(value.Message);
}
/// <summary>
/// Simple process counter to write to console
/// </summary>
public static void ProgressUpdated(object? sender, ProtectionProgress value)
{
Console.WriteLine($"{value.Percentage * 100:N2}%: {value.Filename} - {value.Protection}");
}
}
}

View File

@@ -5,19 +5,20 @@
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.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.2.4</VersionPrefix>
<VersionPrefix>3.3.0</VersionPrefix>
<!-- 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-2024</Copyright>
<Copyright>Copyright (c) Matt Nadareski 2019-2025</Copyright>
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
<RepositoryType>git</RepositoryType>
@@ -37,23 +38,12 @@
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MPF.Frontend\MPF.Frontend.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BinaryObjectScanner" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="3.2.3" GeneratePathProperty="true">
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="SabreTools.RedumpLib" Version="1.5.2" />
</ItemGroup>
<ItemGroup>
<Content Include="$(PkgBinaryObjectScanner)\content\**" PackagePath="contentFiles\any\any;content" CopyToOutputDirectory="Always" PackageCopyToOutput="true" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.4" />
</ItemGroup>
</Project>

View File

@@ -3,7 +3,6 @@ using System.IO;
#if NET40
using System.Threading.Tasks;
#endif
using BinaryObjectScanner;
using MPF.Frontend;
using MPF.Frontend.Tools;
using SabreTools.RedumpLib;
@@ -35,7 +34,6 @@ namespace MPF.Check
// Protection Scanning Options
ScanArchivesForProtection = true,
ScanPackersForProtection = false,
IncludeDebugProtectionInformation = false,
HideDriveLetters = false,
@@ -70,23 +68,20 @@ namespace MPF.Check
return;
}
// Make new Progress objects
var resultProgress = new Progress<ResultEventArgs>();
resultProgress.ProgressChanged += ConsoleLogger.ProgressUpdated;
var protectionProgress = new Progress<ProtectionProgress>();
protectionProgress.ProgressChanged += ConsoleLogger.ProgressUpdated;
// Validate the supplied credentials
bool? validated = RedumpClient.ValidateCredentials(options.RedumpUsername ?? string.Empty, options.RedumpPassword ?? string.Empty).GetAwaiter().GetResult();
string message = validated switch
if (!string.IsNullOrEmpty(options.RedumpUsername) && !string.IsNullOrEmpty(options.RedumpPassword))
{
true => "Redump username and password accepted!",
false => "Redump username and password denied!",
null => "An error occurred validating your credentials!",
};
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!",
};
if (!string.IsNullOrEmpty(message))
Console.WriteLine(message);
if (!string.IsNullOrEmpty(message))
Console.WriteLine(message);
}
// Loop through all the rest of the args
for (int i = startIndex; i < args.Length; i++)
@@ -109,7 +104,7 @@ namespace MPF.Check
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, seedInfo: opts.Seed)
var result = env.VerifyAndSaveDumpOutput(seedInfo: opts.Seed)
.ConfigureAwait(false).GetAwaiter().GetResult();
Console.WriteLine(result.Message);
}
@@ -145,7 +140,6 @@ namespace MPF.Check
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-packers Enable scanning for packers (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");
@@ -167,7 +161,6 @@ namespace MPF.Check
// These values require multiple parts to be active
bool scan = false,
enableArchives = true,
enablePackers = false,
enableDebug = false,
hideDriveLetters = false;
@@ -189,12 +182,12 @@ namespace MPF.Check
if (args[startIndex].StartsWith("-u=") || args[startIndex].StartsWith("--use="))
{
string internalProgram = args[startIndex].Split('=')[1];
options.InternalProgram = Frontend.Options.ToInternalProgram(internalProgram);
options.InternalProgram = internalProgram.ToInternalProgram();
}
else if (args[startIndex] == "-u" || args[startIndex] == "--use")
{
string internalProgram = args[startIndex + 1];
options.InternalProgram = Frontend.Options.ToInternalProgram(internalProgram);
options.InternalProgram = internalProgram.ToInternalProgram();
startIndex++;
}
@@ -266,12 +259,6 @@ namespace MPF.Check
enableArchives = false;
}
// Enable scanning for packers (requires --scan)
else if (args[startIndex].Equals("--enable-packers"))
{
enablePackers = true;
}
// Enable debug protection information (requires --scan)
else if (args[startIndex].Equals("--enable-debug"))
{
@@ -324,7 +311,6 @@ namespace MPF.Check
// Now deal with the complex options
options.ScanForProtection = scan && !string.IsNullOrEmpty(opts.DevicePath);
options.ScanArchivesForProtection = enableArchives && scan && !string.IsNullOrEmpty(opts.DevicePath);
options.ScanPackersForProtection = enablePackers && scan && !string.IsNullOrEmpty(opts.DevicePath);
options.IncludeDebugProtectionInformation = enableDebug && scan && !string.IsNullOrEmpty(opts.DevicePath);
options.HideDriveLetters = hideDriveLetters && scan && !string.IsNullOrEmpty(opts.DevicePath);

View File

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

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 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 --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 --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 --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 --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 --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 --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,465 @@
using System.Collections.Generic;
using MPF.ExecutionContexts.DiscImageCreator;
using SabreTools.RedumpLib.Data;
using Xunit;
namespace MPF.ExecutionContexts.Test
{
public class DiscImageCreatorTests
{
// TODO: Add Converters.ToRedumpSystem test
// TODO: Add Converters.ToMediaType test
#region Converters.Extension
[Theory]
[InlineData(null, null)]
[InlineData(MediaType.CDROM, ".bin")]
[InlineData(MediaType.GDROM, ".bin")]
[InlineData(MediaType.Cartridge, ".bin")]
[InlineData(MediaType.HardDisk, ".bin")]
[InlineData(MediaType.CompactFlash, ".bin")]
[InlineData(MediaType.MMC, ".bin")]
[InlineData(MediaType.SDCard, ".bin")]
[InlineData(MediaType.FlashDrive, ".bin")]
[InlineData(MediaType.DVD, ".iso")]
[InlineData(MediaType.HDDVD, ".iso")]
[InlineData(MediaType.BluRay, ".iso")]
[InlineData(MediaType.NintendoWiiOpticalDisc, ".iso")]
[InlineData(MediaType.LaserDisc, ".raw")]
[InlineData(MediaType.NintendoGameCubeGameDisc, ".raw")]
[InlineData(MediaType.NintendoWiiUOpticalDisc, ".wud")]
[InlineData(MediaType.FloppyDisk, ".img")]
[InlineData(MediaType.Cassette, ".wav")]
[InlineData(MediaType.ApertureCard, null)]
public void ExtensionTest(MediaType? type, string? expected)
{
string? actual = Converters.Extension(type);
Assert.Equal(expected, actual);
}
#endregion
#region Default Values
private static 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 /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 /d8 /d /q /f 0 /np /nq /nr /r /am /sf 1 /ss /sk 1 0 /s 0 /t";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region BluRay
[Theory]
[InlineData("bd F filename.bin 0 /d /q /rr 0 /f 0 /ra /avdp")]
public void BluRayTest(string parameters)
{
string? expected = "bd F \"filename.bin\" 0 /d /q /rr 0 /f 0 /ra /avdp";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region Close
[Theory]
[InlineData("close f")]
public void CloseTest(string parameters)
{
string? expected = "close f";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region CompactDisc
[Theory]
[InlineData("cd f filename.bin 0 /a 0 /p /aj /be raw /c2 1 2 3 1 5 6 /d8 /d /q /mscf /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 /d8 /d /q /mscf /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 /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 /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 /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 /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 /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 /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,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)
{
FlagInput 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)
{
BooleanInput 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)
{
Int8Input 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)
{
UInt8Input 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)
{
Int16Input 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)
{
UInt16Input 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)
{
Int32Input 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)
{
UInt32Input 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)
{
Int64Input 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)
{
UInt64Input 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)
{
StringInput 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

@@ -11,17 +11,16 @@
<ItemGroup>
<ProjectReference Include="..\MPF.ExecutionContexts\MPF.ExecutionContexts.csproj" />
<ProjectReference Include="..\MPF.Frontend\MPF.Frontend.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeCoverage" Version="17.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.5.2" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.4" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
<PackageReference Include="xunit.analyzers" Version="1.17.0" />
<PackageReference Include="xunit.analyzers" Version="1.18.0" />
<PackageReference Include="xunit.assert" Version="2.9.2" />
<PackageReference Include="xunit.core" Version="2.9.2" />
<PackageReference Include="xunit.extensibility.core" Version="2.9.2" />
@@ -30,7 +29,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -0,0 +1,416 @@
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 Dictionary<string, string?> AllOptions = new()
{
[SettingConstants.EnableDebug] = "true",
[SettingConstants.EnableLeadinRetry] = "true",
[SettingConstants.EnableVerbose] = "true",
[SettingConstants.LeadinRetryCount] = "1000",
[SettingConstants.ReadMethod] = "BE",
[SettingConstants.RereadCount] = "1000",
[SettingConstants.SectorOrder] = "DATA_C2_SUB",
[SettingConstants.UseGenericDriveType] = "true",
};
[Theory]
[InlineData(null, null, null, "filename.bin", null, "")]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, "/dev/sr0", "path/filename.bin", 2, "cd skeleton --verbose --debug --drive=/dev/sr0 --speed=1000 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB")]
[InlineData(RedumpSystem.SuperAudioCD, MediaType.CDROM, "/dev/sr0", "path/filename.bin", 2, "sacd --verbose --debug --drive=/dev/sr0 --speed=1000 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB")]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, "/dev/sr0", "path/filename.bin", 2, "dvd --verbose --debug --drive=/dev/sr0 --speed=1000 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB")]
[InlineData(RedumpSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc, "/dev/sr0", "path/filename.bin", 2, "dvd --verbose --debug --drive=/dev/sr0 --speed=1000 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB")]
[InlineData(RedumpSystem.NintendoWii, MediaType.NintendoWiiOpticalDisc, "/dev/sr0", "path/filename.bin", 2, "dvd --verbose --debug --drive=/dev/sr0 --speed=1000 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB")]
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, "/dev/sr0", "path/filename.bin", 2, "dvd --verbose --debug --drive=/dev/sr0 --speed=1000 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB")]
[InlineData(RedumpSystem.BDVideo, MediaType.BluRay, "/dev/sr0", "path/filename.bin", 2, "bd --verbose --debug --drive=/dev/sr0 --speed=1000 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB")]
[InlineData(RedumpSystem.NintendoWiiU, MediaType.NintendoWiiUOpticalDisc, "/dev/sr0", "path/filename.bin", 2, "bd --verbose --debug --drive=/dev/sr0 --speed=1000 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB")]
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 CD
[Theory]
[InlineData("cd -h --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("cd --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void CDTest(string parameters)
{
string? expected = "cd --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
[Theory]
[InlineData("cd --drive=dr --image-path=\"directory name\" --image-name=\"image name.bin\"")]
public void SpacesTest(string parameters)
{
string? expected = "cd --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 DVD
[Theory]
[InlineData("dvd -h --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("dvd --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void DVDTest(string parameters)
{
string? expected = "dvd --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region BD
[Theory]
[InlineData("bd -h --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("bd --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void BDTest(string parameters)
{
string? expected = "bd --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region SACD
[Theory]
[InlineData("sacd -h --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("sacd --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void SACDTest(string parameters)
{
string? expected = "sacd --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region New
[Theory]
[InlineData("new -h --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("new --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void NewTest(string parameters)
{
string? expected = "new --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
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 --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("rings --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void RingsTest(string parameters)
{
string? expected = "rings --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
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 --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("dump --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void DumpTest(string parameters)
{
string? expected = "dump --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region DumpNew
[Theory]
[InlineData("dumpnew -h --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("dumpnew --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void DumpNewTest(string parameters)
{
string? expected = "dumpnew --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.True(context.IsDumpingCommand());
}
#endregion
#region Refine
[Theory]
[InlineData("refine -h --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("refine --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void RefineTest(string parameters)
{
string? expected = "refine --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
#region RefineNew
[Theory]
[InlineData("refinenew -h --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("refinenew --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void RefineNewTest(string parameters)
{
string? expected = "refinenew --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
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 --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("verify --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void VerifyTest(string parameters)
{
string? expected = "verify --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
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 --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("dvdkey --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void DVDKeyTest(string parameters)
{
string? expected = "dvdkey --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
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 --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("eject --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void EjectTest(string parameters)
{
string? expected = "eject --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
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 --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("dvdisokey --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void DVDIsoKeyTest(string parameters)
{
string? expected = "dvdisokey --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
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 --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("protection --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --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 --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
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 --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("split --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void SplitTest(string parameters)
{
string? expected = "split --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
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 --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("hash --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void HashTest(string parameters)
{
string? expected = "hash --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
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 --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("info --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void InfoTest(string parameters)
{
string? expected = "info --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
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 --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("skeleton --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void SkeletonTest(string parameters)
{
string? expected = "skeleton --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
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 --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("debug --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void DebugTest(string parameters)
{
string? expected = "debug --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
Assert.False(context.IsDumpingCommand());
}
#endregion
// Currently disabled
#region FixMSF
// [Theory]
// [InlineData("fixmsf -h --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
// [InlineData("fixmsf --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
// public void FixMSFTest(string parameters)
// {
// string? expected = "fixmsf --help --version --verbose --auto-eject --drive=dr --speed=0 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext";
// var context = new ExecutionContext(parameters);
// string? actual = context.GenerateParameters();
// Assert.Equal(expected, actual);
// }
#endregion
}
}

View File

@@ -7,25 +7,35 @@ namespace MPF.ExecutionContexts.Aaru
{
public const string NONE = "";
// Archive Family
#region Archive Family
public const string ArchivePrefixShort = "arc";
public const string ArchivePrefixLong = "archive";
public const string ArchiveInfo = "info";
// Database Family
#endregion
#region Database Family
public const string DatabasePrefixShort = "db";
public const string DatabasePrefixLong = "database";
public const string DatabaseStats = "stats";
public const string DatabaseUpdate = "update";
// Device Family
#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";
// Filesystem Family
#endregion
#region Filesystem Family
public const string FilesystemPrefixShort = "fi";
public const string FilesystemPrefixShortAlt = "fs";
public const string FilesystemPrefixLong = "filesystem";
@@ -35,7 +45,10 @@ namespace MPF.ExecutionContexts.Aaru
public const string FilesystemListLong = "list";
public const string FilesystemOptions = "options";
// Image Family
#endregion
#region Image Family
public const string ImagePrefixShort = "i";
public const string ImagePrefixLong = "image";
public const string ImageChecksumShort = "chk";
@@ -51,18 +64,26 @@ namespace MPF.ExecutionContexts.Aaru
public const string ImagePrint = "print";
public const string ImageVerify = "verify";
// Media Family
#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";
// Standalone Commands
#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
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,21 @@ namespace MPF.ExecutionContexts.Aaru
/// </summary>
public static class FlagStrings
{
// Boolean flags
#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";
@@ -14,8 +28,6 @@ namespace MPF.ExecutionContexts.Aaru
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";
@@ -35,9 +47,6 @@ namespace MPF.ExecutionContexts.Aaru
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";
@@ -75,26 +84,32 @@ namespace MPF.ExecutionContexts.Aaru
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
#endregion
#region Int8 flags
public const string SpeedLong = "--speed";
// Int16 flags
#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";
// Int32 flags
#endregion
#region Int32 flags
public const string BlockSizeShort = "-b";
public const string BlockSizeLong = "--block-size";
public const string CountShort = "-c";
@@ -105,13 +120,19 @@ namespace MPF.ExecutionContexts.Aaru
public const string SkipShort = "-k";
public const string SkipLong = "--skip";
// Int64 flags
#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";
// String flags
#endregion
#region String flags
public const string CommentsLong = "--comments";
public const string CreatorLong = "--creator";
public const string DriveManufacturerLong = "--drive-manufacturer";
@@ -121,9 +142,8 @@ namespace MPF.ExecutionContexts.Aaru
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 FormatLong = "--format";
public const string GeometryShort = "-g";
public const string GeometryLong = "--geometry";
public const string ImgBurnLogShort = "-b";
@@ -147,5 +167,7 @@ namespace MPF.ExecutionContexts.Aaru
public const string SubchannelLong = "--subchannel";
public const string XMLSidecarShort = "-x";
public const string XMLSidecarLong = "--cicm-xml";
#endregion
}
}

View File

@@ -242,7 +242,7 @@ namespace MPF.ExecutionContexts
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
protected static bool GetBooleanSetting(Dictionary<string, string?> settings, string key, bool defaultValue)
internal static bool GetBooleanSetting(Dictionary<string, string?> settings, string key, bool defaultValue)
{
if (settings.ContainsKey(key))
{
@@ -264,7 +264,7 @@ namespace MPF.ExecutionContexts
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
protected static int GetInt32Setting(Dictionary<string, string?> settings, string key, int defaultValue)
internal static int GetInt32Setting(Dictionary<string, string?> settings, string key, int defaultValue)
{
if (settings.ContainsKey(key))
{
@@ -286,7 +286,7 @@ namespace MPF.ExecutionContexts
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
protected static string? GetStringSetting(Dictionary<string, string?> settings, string key, string? defaultValue)
internal static string? GetStringSetting(Dictionary<string, string?> settings, string key, string? defaultValue)
{
if (settings.ContainsKey(key))
return settings[key];
@@ -301,29 +301,28 @@ namespace MPF.ExecutionContexts
/// <summary>
/// Split a parameters string into a list while taking quotes into account
/// </summary>
/// <see href="https://stackoverflow.com/questions/14655023/split-a-string-that-has-white-spaces-unless-they-are-enclosed-within-quotes"/>
protected static List<string> SplitParameterString(string parameters)
internal static string[] SplitParameterString(string parameters)
{
// Ensure the parameter string is trimmed
parameters = parameters.Trim();
// Split the string using Regex
var matches = Regex.Matches(parameters, @"([a-zA-Z\-]*=)?[\""].+?[\""]|[^ ]+", RegexOptions.Compiled);
var matches = Regex.Matches(parameters, @"([a-zA-Z0-9\-]*=)?[\""].+?[\""]|[^ ]+", RegexOptions.Compiled);
// Get just the values from the matches
var matchArr = new Match[matches.Count];
matches.CopyTo(matchArr, 0);
return [.. Array.ConvertAll(matchArr, m => m.Value)];
return Array.ConvertAll(matchArr, m => m.Value);
}
/// <summary>
/// Returns whether or not the selected item exists
/// </summary>
/// <param name="parameters">List of parameters to check against</param>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="index">Current index</param>
/// <returns>True if the next item exists, false otherwise</returns>
protected static bool DoesExist(List<string> parameters, int index)
=> index < parameters.Count;
internal static bool DoesExist(string[] parts, int index)
=> index >= 0 && index < parts.Length;
/// <summary>
/// Gets if the flag is supported by the current command
@@ -346,7 +345,7 @@ namespace MPF.ExecutionContexts
/// </summary>
/// <param name="parameter">String value to check</param>
/// <returns>True if it's a valid bool, false otherwise</returns>
protected static bool IsValidBool(string parameter)
internal static bool IsValidBool(string parameter)
=> bool.TryParse(parameter, out bool _);
/// <summary>
@@ -356,14 +355,14 @@ namespace MPF.ExecutionContexts
/// <param name="lowerBound">Lower bound (>=)</param>
/// <param name="upperBound">Upper bound (<=)</param>
/// <returns>True if it's a valid byte, false otherwise</returns>
protected static bool IsValidInt8(string parameter, sbyte lowerBound = -1, sbyte upperBound = -1)
internal static bool IsValidInt8(string parameter, sbyte? lowerBound = null, sbyte? upperBound = null)
{
string value = ExtractFactorFromValue(parameter, out _);
if (!sbyte.TryParse(value, out sbyte temp))
return false;
else if (lowerBound != -1 && temp < lowerBound)
else if (lowerBound != null && temp < lowerBound)
return false;
else if (upperBound != -1 && temp > upperBound)
else if (upperBound != null && temp > upperBound)
return false;
return true;
@@ -376,14 +375,14 @@ namespace MPF.ExecutionContexts
/// <param name="lowerBound">Lower bound (>=)</param>
/// <param name="upperBound">Upper bound (<=)</param>
/// <returns>True if it's a valid Int16, false otherwise</returns>
protected static bool IsValidInt16(string parameter, short lowerBound = -1, short upperBound = -1)
internal static bool IsValidInt16(string parameter, short? lowerBound = null, short? upperBound = null)
{
string value = ExtractFactorFromValue(parameter, out _);
if (!short.TryParse(value, out short temp))
return false;
else if (lowerBound != -1 && temp < lowerBound)
else if (lowerBound != null && temp < lowerBound)
return false;
else if (upperBound != -1 && temp > upperBound)
else if (upperBound != null && temp > upperBound)
return false;
return true;
@@ -396,14 +395,14 @@ namespace MPF.ExecutionContexts
/// <param name="lowerBound">Lower bound (>=)</param>
/// <param name="upperBound">Upper bound (<=)</param>
/// <returns>True if it's a valid Int32, false otherwise</returns>
protected static bool IsValidInt32(string parameter, int lowerBound = -1, int upperBound = -1)
internal static bool IsValidInt32(string parameter, int? lowerBound = null, int? upperBound = null)
{
string value = ExtractFactorFromValue(parameter, out _);
if (!int.TryParse(value, out int temp))
return false;
else if (lowerBound != -1 && temp < lowerBound)
else if (lowerBound != null && temp < lowerBound)
return false;
else if (upperBound != -1 && temp > upperBound)
else if (upperBound != null && temp > upperBound)
return false;
return true;
@@ -416,14 +415,14 @@ namespace MPF.ExecutionContexts
/// <param name="lowerBound">Lower bound (>=)</param>
/// <param name="upperBound">Upper bound (<=)</param>
/// <returns>True if it's a valid Int64, false otherwise</returns>
protected static bool IsValidInt64(string parameter, long lowerBound = -1, long upperBound = -1)
internal static bool IsValidInt64(string parameter, long? lowerBound = null, long? upperBound = null)
{
string value = ExtractFactorFromValue(parameter, out _);
if (!long.TryParse(value, out long temp))
return false;
else if (lowerBound != -1 && temp < lowerBound)
else if (lowerBound != null && temp < lowerBound)
return false;
else if (upperBound != -1 && temp > upperBound)
else if (upperBound != null && temp > upperBound)
return false;
return true;
@@ -432,22 +431,22 @@ namespace MPF.ExecutionContexts
/// <summary>
/// Process a flag parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="flagString">Flag string, if available</param>
/// <param name="i">Reference to the position in the parts</param>
/// <returns>True if the parameter was processed successfully or skipped, false otherwise</returns>
protected bool ProcessFlagParameter(List<string> parts, string flagString, ref int i)
protected bool ProcessFlagParameter(string[] parts, string flagString, ref int i)
=> ProcessFlagParameter(parts, null, flagString, ref i);
/// <summary>
/// Process a flag parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="shortFlagString">Short flag string, if available</param>
/// <param name="longFlagString">Long flag string, if available</param>
/// <param name="i">Reference to the position in the parts</param>
/// <returns>True if the parameter was processed successfully or skipped, false otherwise</returns>
protected bool ProcessFlagParameter(List<string> parts, string? shortFlagString, string longFlagString, ref int i)
protected bool ProcessFlagParameter(string[] parts, string? shortFlagString, string longFlagString, ref int i)
{
if (parts == null)
return false;
@@ -466,24 +465,24 @@ namespace MPF.ExecutionContexts
/// <summary>
/// Process a boolean parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="flagString">Flag string, if available</param>
/// <param name="i">Reference to the position in the parts</param>
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
/// <returns>True if the parameter was processed successfully or skipped, false otherwise</returns>
protected bool ProcessBooleanParameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
protected bool ProcessBooleanParameter(string[] parts, string flagString, ref int i, bool missingAllowed = false)
=> ProcessBooleanParameter(parts, null, flagString, ref i, missingAllowed);
/// <summary>
/// Process a boolean parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="shortFlagString">Short flag string, if available</param>
/// <param name="longFlagString">Long flag string, if available</param>
/// <param name="i">Reference to the position in the parts</param>
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
/// <returns>True if the parameter was processed successfully or skipped, false otherwise</returns>
protected bool ProcessBooleanParameter(List<string> parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
protected bool ProcessBooleanParameter(string[] parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
{
if (parts == null)
return false;
@@ -541,24 +540,24 @@ namespace MPF.ExecutionContexts
/// <summary>
/// Process a sbyte parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="flagString">Flag string, if available</param>
/// <param name="i">Reference to the position in the parts</param>
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
/// <returns>SByte value if success, SByte.MinValue if skipped, null on error/returns>
protected sbyte? ProcessInt8Parameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
protected sbyte? ProcessInt8Parameter(string[] parts, string flagString, ref int i, bool missingAllowed = false)
=> ProcessInt8Parameter(parts, null, flagString, ref i, missingAllowed);
/// <summary>
/// Process an sbyte parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="shortFlagString">Short flag string, if available</param>
/// <param name="longFlagString">Long flag string, if available</param>
/// <param name="i">Reference to the position in the parts</param>
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
/// <returns>SByte value if success, SByte.MinValue if skipped, null on error/returns>
protected sbyte? ProcessInt8Parameter(List<string> parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
protected sbyte? ProcessInt8Parameter(string[] parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
{
if (parts == null)
return null;
@@ -629,24 +628,24 @@ namespace MPF.ExecutionContexts
/// <summary>
/// Process an Int16 parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="flagString">Flag string, if available</param>
/// <param name="i">Reference to the position in the parts</param>
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
/// <returns>Int16 value if success, Int16.MinValue if skipped, null on error/returns>
protected short? ProcessInt16Parameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
protected short? ProcessInt16Parameter(string[] parts, string flagString, ref int i, bool missingAllowed = false)
=> ProcessInt16Parameter(parts, null, flagString, ref i, missingAllowed);
/// <summary>
/// Process an Int16 parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="shortFlagString">Short flag string, if available</param>
/// <param name="longFlagString">Long flag string, if available</param>
/// <param name="i">Reference to the position in the parts</param>
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
/// <returns>Int16 value if success, Int16.MinValue if skipped, null on error/returns>
protected short? ProcessInt16Parameter(List<string> parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
protected short? ProcessInt16Parameter(string[] parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
{
if (parts == null)
return null;
@@ -716,24 +715,24 @@ namespace MPF.ExecutionContexts
/// <summary>
/// Process an Int32 parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="flagString">Flag string, if available</param>
/// <param name="i">Reference to the position in the parts</param>
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
/// <returns>Int32 value if success, Int32.MinValue if skipped, null on error/returns>
protected int? ProcessInt32Parameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
protected int? ProcessInt32Parameter(string[] parts, string flagString, ref int i, bool missingAllowed = false)
=> ProcessInt32Parameter(parts, null, flagString, ref i, missingAllowed);
/// <summary>
/// Process an Int32 parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="shortFlagString">Short flag string, if available</param>
/// <param name="longFlagString">Long flag string, if available</param>
/// <param name="i">Reference to the position in the parts</param>
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
/// <returns>Int32 value if success, Int32.MinValue if skipped, null on error/returns>
protected int? ProcessInt32Parameter(List<string> parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
protected int? ProcessInt32Parameter(string[] parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
{
if (parts == null)
return null;
@@ -797,30 +796,30 @@ namespace MPF.ExecutionContexts
return null;
}
return Int32.MinValue;
return int.MinValue;
}
/// <summary>
/// Process an Int64 parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="flagString">Flag string, if available</param>
/// <param name="i">Reference to the position in the parts</param>
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
/// <returns>Int64 value if success, Int64.MinValue if skipped, null on error/returns>
protected long? ProcessInt64Parameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
protected long? ProcessInt64Parameter(string[] parts, string flagString, ref int i, bool missingAllowed = false)
=> ProcessInt64Parameter(parts, null, flagString, ref i, missingAllowed);
/// <summary>
/// Process an Int64 parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="shortFlagString">Short flag string, if available</param>
/// <param name="longFlagString">Long flag string, if available</param>
/// <param name="i">Reference to the position in the parts</param>
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
/// <returns>Int64 value if success, Int64.MinValue if skipped, null on error/returns>
protected long? ProcessInt64Parameter(List<string> parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
protected long? ProcessInt64Parameter(string[] parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
{
if (parts == null)
return null;
@@ -884,30 +883,30 @@ namespace MPF.ExecutionContexts
return null;
}
return Int64.MinValue;
return long.MinValue;
}
/// <summary>
/// Process an string parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="flagString">Flag string, if available</param>
/// <param name="i">Reference to the position in the parts</param>
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
/// <returns>String value if possible, string.Empty on missing, null on error</returns>
protected string? ProcessStringParameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
protected string? ProcessStringParameter(string[] parts, string flagString, ref int i, bool missingAllowed = false)
=> ProcessStringParameter(parts, null, flagString, ref i, missingAllowed);
/// <summary>
/// Process a string parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="shortFlagString">Short flag string, if available</param>
/// <param name="longFlagString">Long flag string, if available</param>
/// <param name="i">Reference to the position in the parts</param>
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
/// <returns>String value if possible, string.Empty on missing, null on error</returns>
protected string? ProcessStringParameter(List<string> parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
protected string? ProcessStringParameter(string[] parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
{
if (parts == null)
return null;
@@ -963,24 +962,24 @@ namespace MPF.ExecutionContexts
/// <summary>
/// Process a byte parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="flagString">Flag string, if available</param>
/// <param name="i">Reference to the position in the parts</param>
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
/// <returns>Byte value if success, Byte.MinValue if skipped, null on error/returns>
protected byte? ProcessUInt8Parameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
protected byte? ProcessUInt8Parameter(string[] parts, string flagString, ref int i, bool missingAllowed = false)
=> ProcessUInt8Parameter(parts, null, flagString, ref i, missingAllowed);
/// <summary>
/// Process a byte parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="shortFlagString">Short flag string, if available</param>
/// <param name="longFlagString">Long flag string, if available</param>
/// <param name="i">Reference to the position in the parts</param>
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
/// <returns>Byte value if success, Byte.MinValue if skipped, null on error/returns>
protected byte? ProcessUInt8Parameter(List<string> parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
protected byte? ProcessUInt8Parameter(string[] parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
{
if (parts == null)
return null;
@@ -1053,7 +1052,7 @@ namespace MPF.ExecutionContexts
/// </summary>
/// <param name="value">String value to treat as suffixed number</param>
/// <returns>Trimmed value and multiplication factor</returns>
private static string ExtractFactorFromValue(string value, out long factor)
internal static string ExtractFactorFromValue(string value, out long factor)
{
value = value.Trim('"');
factor = 1;
@@ -1115,7 +1114,7 @@ namespace MPF.ExecutionContexts
/// </summary>
/// <param name="value">String with removed leading 0x</param>
/// <returns></returns>
private static string RemoveHexIdentifier(string value)
internal static string RemoveHexIdentifier(string value)
{
if (value.Length <= 2)
return value;

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 == 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 == false)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check the name
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
Value = true;
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,261 @@
using System;
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 (value.EndsWith("c", StringComparison.Ordinal))
{
factor = 1;
value = value.TrimEnd('c');
}
// Words
else if (value.EndsWith("w", StringComparison.Ordinal))
{
factor = 2;
value = value.TrimEnd('w');
}
// Double Words
else if (value.EndsWith("d", StringComparison.Ordinal))
{
factor = 4;
value = value.TrimEnd('d');
}
// Quad Words
else if (value.EndsWith("q", StringComparison.Ordinal))
{
factor = 8;
value = value.TrimEnd('q');
}
// Kilobytes
else if (value.EndsWith("k", StringComparison.Ordinal))
{
factor = 1024;
value = value.TrimEnd('k');
}
// Megabytes
else if (value.EndsWith("M", StringComparison.Ordinal))
{
factor = 1024 * 1024;
value = value.TrimEnd('M');
}
// Gigabytes
else if (value.EndsWith("G", StringComparison.Ordinal))
{
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;
return value.Substring(2);
}
#endregion
}
/// <summary>
/// Represents a single input for an execution context
/// </summary>
public abstract class Input<T> : Input
{
#region Properties
/// <summary>
/// Represents the last value stored
/// </summary>
public T? Value { get; protected set; }
/// <inheritdoc/>
public override bool ValueSet => Value != null;
#endregion
#region Constructors
/// <inheritdoc/>
public Input(string name)
: base(name) { }
/// <inheritdoc/>
public Input(string name, bool required)
: base(name, required) { }
/// <inheritdoc/>
public Input(string shortName, string longName)
: base(shortName, longName) { }
/// <inheritdoc/>
public Input(string shortName, string longName, bool required)
: base(shortName, longName, required) { }
/// <inheritdoc/>
public Input(string[] names)
: base(names) { }
/// <inheritdoc/>
public Input(string[] names, bool required)
: base(names, required) { }
#endregion
#region Functionality
/// <inheritdoc/>
public override void ClearValue()
{
Value = default;
}
/// <summary>
/// Set a new value
/// </summary>
public void SetValue(T value)
{
Value = value;
}
#endregion
}
}

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 == null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Only output separator and value if needed
if (_required || (!_required && Value != short.MinValue))
{
// Separator
if (useEquals)
builder.Append("=");
else
builder.Append(" ");
// Value
builder.Append(Value.ToString());
}
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
// Ensure the value exists
if (index + 1 >= parts.Length)
{
Value = _required ? null : short.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(parts[index + 1], out short? value) && value != null)
{
index++;
Value = value;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : short.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// Check for equal separated
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
{
// Split the string, using the first equal sign as the separator
string[] tempSplit = part.Split('=');
string key = tempSplit[0];
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
// Ensure the value exists
if (string.IsNullOrEmpty(val))
{
Value = _required ? null : short.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(val, out short? value) && value != null)
{
Value = value;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : short.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
return false;
}
/// <summary>
/// Parse a value from a string
/// </summary>
private static bool ParseValue(string str, out short? output)
{
// If the next value is valid
if (short.TryParse(str, out short value))
{
output = value;
return true;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(str, out long factor);
if (short.TryParse(baseVal, out value))
{
output = (short)(value * factor);
return true;
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (short.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
output = (short)(value * factor);
return true;
}
// The value could not be parsed
output = null;
return false;
}
}
}

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 == null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Only output separator and value if needed
if (_required || (!_required && Value != null))
{
// Separator
if (useEquals)
builder.Append("=");
else
builder.Append(" ");
// Value
int?[] nonNull = Array.FindAll(Value, i => i != null);
string[] stringValues = Array.ConvertAll(nonNull, i => i.ToString() ?? string.Empty);
builder.Append(string.Join(" ", stringValues));
}
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
Value = new int?[Size];
for (int i = 0; i < Size; i++)
{
// Ensure the value exists
if (index + 1 >= parts.Length)
return !_required;
// If the next value is valid
if (ParseValue(parts[index + 1], out int? value) && value != null)
{
index++;
Value[i] = value;
Value[i] = (MinValue != null && Value[i] < MinValue) ? MinValue : Value[i];
Value[i] = (MaxValue != null && Value[i] > MaxValue) ? MaxValue : Value[i];
continue;
}
// Return value based on required flag
return !_required;
}
return true;
}
return false;
}
/// <summary>
/// Parse a value from a string
/// </summary>
private static bool ParseValue(string str, out int? output)
{
// If the next value is valid
if (int.TryParse(str, out int value))
{
output = value;
return true;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(str, out long factor);
if (int.TryParse(baseVal, out value))
{
output = (int)(value * factor);
return true;
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (int.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
output = (int)(value * factor);
return true;
}
// The value could not be parsed
output = null;
return false;
}
}
}

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 == null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Only output separator and value if needed
if (_required || (!_required && Value != int.MinValue))
{
// Separator
if (useEquals)
builder.Append("=");
else
builder.Append(" ");
// Value
builder.Append(Value.ToString());
}
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
// Ensure the value exists
if (index + 1 >= parts.Length)
{
Value = _required ? null : int.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(parts[index + 1], out int? value) && value != null)
{
index++;
Value = value;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : int.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// Check for equal separated
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
{
// Split the string, using the first equal sign as the separator
string[] tempSplit = part.Split('=');
string key = tempSplit[0];
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
// Ensure the value exists
if (string.IsNullOrEmpty(val))
{
Value = _required ? null : int.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(val, out int? value) && value != null)
{
Value = value;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : int.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
return false;
}
/// <summary>
/// Parse a value from a string
/// </summary>
private static bool ParseValue(string str, out int? output)
{
// If the next value is valid
if (int.TryParse(str, out int value))
{
output = value;
return true;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(str, out long factor);
if (int.TryParse(baseVal, out value))
{
output = (int)(value * factor);
return true;
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (int.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
output = (int)(value * factor);
return true;
}
// The value could not be parsed
output = null;
return false;
}
}
}

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 == null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Only output separator and value if needed
if (_required || (!_required && Value != long.MinValue))
{
// Separator
if (useEquals)
builder.Append("=");
else
builder.Append(" ");
// Value
builder.Append(Value.ToString());
}
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
// Ensure the value exists
if (index + 1 >= parts.Length)
{
Value = _required ? null : long.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(parts[index + 1], out long? value) && value != null)
{
index++;
Value = value;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : long.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// Check for equal separated
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
{
// Split the string, using the first equal sign as the separator
string[] tempSplit = part.Split('=');
string key = tempSplit[0];
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
// Ensure the value exists
if (string.IsNullOrEmpty(val))
{
Value = _required ? null : long.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(val, out long? value) && value != null)
{
Value = value;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : long.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
return false;
}
/// <summary>
/// Parse a value from a string
/// </summary>
private static bool ParseValue(string str, out long? output)
{
// If the next value is valid
if (long.TryParse(str, out long value))
{
output = value;
return true;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(str, out long factor);
if (long.TryParse(baseVal, out value))
{
output = (long)(value * factor);
return true;
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (long.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
output = (long)(value * factor);
return true;
}
// The value could not be parsed
output = null;
return false;
}
}
}

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 == null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Only output separator and value if needed
if (_required || (!_required && Value != sbyte.MinValue))
{
// Separator
if (useEquals)
builder.Append("=");
else
builder.Append(" ");
// Value
builder.Append(Value.ToString());
}
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
// Ensure the value exists
if (index + 1 >= parts.Length)
{
Value = _required ? null : sbyte.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(parts[index + 1], out sbyte? value) && value != null)
{
index++;
Value = value;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : sbyte.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// Check for equal separated
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
{
// Split the string, using the first equal sign as the separator
string[] tempSplit = part.Split('=');
string key = tempSplit[0];
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
// Ensure the value exists
if (string.IsNullOrEmpty(val))
{
Value = _required ? null : sbyte.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(val, out sbyte? value) && value != null)
{
Value = value;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : sbyte.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
return false;
}
/// <summary>
/// Parse a value from a string
/// </summary>
private static bool ParseValue(string str, out sbyte? output)
{
// If the next value is valid
if (sbyte.TryParse(str, out sbyte value))
{
output = value;
return true;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(str, out long factor);
if (sbyte.TryParse(baseVal, out value))
{
output = (sbyte)(value * factor);
return true;
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (sbyte.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
output = (sbyte)(value * factor);
return true;
}
// The value could not be parsed
output = null;
return false;
}
}
}

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 == 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 == null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Only output separator and value if needed
if (_required || (!_required && Value != ushort.MinValue))
{
// Separator
if (useEquals)
builder.Append("=");
else
builder.Append(" ");
// Value
builder.Append(Value.ToString());
}
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
// Ensure the value exists
if (index + 1 >= parts.Length)
{
Value = _required ? null : ushort.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(parts[index + 1], out ushort? value) && value != null)
{
index++;
Value = value;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : ushort.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// Check for equal separated
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
{
// Split the string, using the first equal sign as the separator
string[] tempSplit = part.Split('=');
string key = tempSplit[0];
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
// Ensure the value exists
if (string.IsNullOrEmpty(val))
{
Value = _required ? null : ushort.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(val, out ushort? value) && value != null)
{
Value = value;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : ushort.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
return false;
}
/// <summary>
/// Parse a value from a string
/// </summary>
private static bool ParseValue(string str, out ushort? output)
{
// If the next value is valid
if (ushort.TryParse(str, out ushort value))
{
output = value;
return true;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(str, out long factor);
if (ushort.TryParse(baseVal, out value))
{
output = (ushort)(value * factor);
return true;
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (ushort.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
output = (ushort)(value * factor);
return true;
}
// The value could not be parsed
output = null;
return false;
}
}
}

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 == null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Only output separator and value if needed
if (_required || (!_required && Value != uint.MinValue))
{
// Separator
if (useEquals)
builder.Append("=");
else
builder.Append(" ");
// Value
builder.Append(Value.ToString());
}
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
// Ensure the value exists
if (index + 1 >= parts.Length)
{
Value = _required ? null : uint.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(parts[index + 1], out uint? value) && value != null)
{
index++;
Value = value;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : uint.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// Check for equal separated
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
{
// Split the string, using the first equal sign as the separator
string[] tempSplit = part.Split('=');
string key = tempSplit[0];
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
// Ensure the value exists
if (string.IsNullOrEmpty(val))
{
Value = _required ? null : uint.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(val, out uint? value) && value != null)
{
Value = value;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : uint.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
return false;
}
/// <summary>
/// Parse a value from a string
/// </summary>
private static bool ParseValue(string str, out uint? output)
{
// If the next value is valid
if (uint.TryParse(str, out uint value))
{
output = value;
return true;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(str, out long factor);
if (uint.TryParse(baseVal, out value))
{
output = (uint)(value * factor);
return true;
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (uint.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
output = (uint)(value * factor);
return true;
}
// The value could not be parsed
output = null;
return false;
}
}
}

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 == null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Only output separator and value if needed
if (_required || (!_required && Value != ulong.MinValue))
{
// Separator
if (useEquals)
builder.Append("=");
else
builder.Append(" ");
// Value
builder.Append(Value.ToString());
}
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
// Ensure the value exists
if (index + 1 >= parts.Length)
{
Value = _required ? null : ulong.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(parts[index + 1], out ulong? value) && value != null)
{
index++;
Value = value;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : ulong.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// Check for equal separated
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
{
// Split the string, using the first equal sign as the separator
string[] tempSplit = part.Split('=');
string key = tempSplit[0];
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
// Ensure the value exists
if (string.IsNullOrEmpty(val))
{
Value = _required ? null : ulong.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(val, out ulong? value) && value != null)
{
Value = value;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : ulong.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
return false;
}
/// <summary>
/// Parse a value from a string
/// </summary>
private static bool ParseValue(string str, out ulong? output)
{
// If the next value is valid
if (ulong.TryParse(str, out ulong value))
{
output = value;
return true;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(str, out long factor);
if (ulong.TryParse(baseVal, out value))
{
output = (ulong)(value * (ulong)factor);
return true;
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (ulong.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
output = (ulong)(value * (ulong)factor);
return true;
}
// The value could not be parsed
output = null;
return false;
}
}
}

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 == null)
return string.Empty;
// Build the output format
var builder = new StringBuilder();
// Flag name
builder.Append(Name);
// Only output separator and value if needed
if (_required || (!_required && Value != byte.MinValue))
{
// Separator
if (useEquals)
builder.Append("=");
else
builder.Append(" ");
// Value
builder.Append(Value.ToString());
}
return builder.ToString();
}
/// <inheritdoc/>
public override bool Process(string[] parts, ref int index)
{
// Check the parts array
if (index < 0 || index >= parts.Length)
return false;
// Check for space-separated
string part = parts[index];
if (part == Name || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => n == part) > -1))
{
// Ensure the value exists
if (index + 1 >= parts.Length)
{
Value = _required ? null : byte.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(parts[index + 1], out byte? value) && value != null)
{
index++;
Value = value;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : byte.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// Check for equal separated
if (part.StartsWith($"{Name}=") || (_altNames.Length > 0 && Array.FindIndex(_altNames, n => part.StartsWith($"{n}=")) > -1))
{
// Split the string, using the first equal sign as the separator
string[] tempSplit = part.Split('=');
string key = tempSplit[0];
string val = string.Join("=", tempSplit, 1, tempSplit.Length - 1);
// Ensure the value exists
if (string.IsNullOrEmpty(val))
{
Value = _required ? null : byte.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
// If the next value is valid
if (ParseValue(val, out byte? value) && value != null)
{
Value = value;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return true;
}
// Return value based on required flag
Value = _required ? null : byte.MinValue;
Value = (MinValue != null && Value < MinValue) ? MinValue : Value;
Value = (MaxValue != null && Value > MaxValue) ? MaxValue : Value;
return !_required;
}
return false;
}
/// <summary>
/// Parse a value from a string
/// </summary>
private static bool ParseValue(string str, out byte? output)
{
// If the next value is valid
if (byte.TryParse(str, out byte value))
{
output = value;
return true;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(str, out long factor);
if (byte.TryParse(baseVal, out value))
{
output = (byte)(value * factor);
return true;
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (byte.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
output = (byte)(value * factor);
return true;
}
// The value could not be parsed
output = null;
return false;
}
}
}

View File

@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using System.Text;
using SabreTools.RedumpLib.Data;
namespace MPF.ExecutionContexts.DiscImageCreator
@@ -225,6 +225,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
FlagStrings.DisableBeep,
FlagStrings.ExtractMicroSoftCabFile,
FlagStrings.ForceUnitAccess,
FlagStrings.FullToc,
FlagStrings.MultiSectorRead,
FlagStrings.NoFixSubP,
FlagStrings.NoFixSubQ,
@@ -236,6 +237,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
FlagStrings.ScanSectorProtect,
FlagStrings.SeventyFour,
FlagStrings.SubchannelReadLevel,
FlagStrings.Toc,
FlagStrings.TryReadingPregap,
FlagStrings.VideoNow,
FlagStrings.VideoNowColor,
@@ -393,12 +395,12 @@ namespace MPF.ExecutionContexts.DiscImageCreator
/// <inheritdoc/>
public override string? GenerateParameters()
{
var parameters = new List<string>();
var parameters = new StringBuilder();
BaseCommand ??= CommandStrings.NONE;
if (!string.IsNullOrEmpty(BaseCommand))
parameters.Add(BaseCommand);
parameters.Append($"{BaseCommand} ");
else
return null;
@@ -427,9 +429,9 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (DrivePath != null)
{
if (DrivePath.Contains(" "))
parameters.Add($"\"{DrivePath}\"");
parameters.Append($"\"{DrivePath}\" ");
else
parameters.Add(DrivePath);
parameters.Append($"{DrivePath} ");
}
else
{
@@ -458,7 +460,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
|| BaseCommand == CommandStrings.XGD3Swap)
{
if (Filename != null)
parameters.Add("\"" + Filename.Trim('"') + "\"");
parameters.Append($"\"{Filename.Trim('"')}\" ");
else
return null;
}
@@ -467,7 +469,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (BaseCommand == CommandStrings.Merge)
{
if (OptiarcFilename != null)
parameters.Add("\"" + OptiarcFilename.Trim('"') + "\"");
parameters.Append($"\"{OptiarcFilename.Trim('"')}\" ");
else
return null;
}
@@ -487,7 +489,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
|| BaseCommand == CommandStrings.XGD3Swap)
{
if (DriveSpeed != null)
parameters.Add(DriveSpeed.ToString() ?? string.Empty);
parameters.Append($"{DriveSpeed} ");
else
return null;
}
@@ -498,8 +500,8 @@ namespace MPF.ExecutionContexts.DiscImageCreator
{
if (StartLBAValue != null && EndLBAValue != null)
{
parameters.Add(StartLBAValue.ToString() ?? string.Empty);
parameters.Add(EndLBAValue.ToString() ?? string.Empty);
parameters.Append($"{StartLBAValue} ");
parameters.Append($"{EndLBAValue} ");
}
else
return null;
@@ -510,9 +512,9 @@ namespace MPF.ExecutionContexts.DiscImageCreator
{
if (this[FlagStrings.AddOffset] == true)
{
parameters.Add(FlagStrings.AddOffset);
parameters.Append($"{FlagStrings.AddOffset} ");
if (AddOffsetValue != null)
parameters.Add(AddOffsetValue.ToString() ?? string.Empty);
parameters.Append($"{AddOffsetValue} ");
}
}
@@ -520,25 +522,24 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (IsFlagSupported(FlagStrings.AMSF))
{
if (this[FlagStrings.AMSF] == true)
parameters.Add(FlagStrings.AMSF);
parameters.Append($"{FlagStrings.AMSF} ");
}
// Atari Jaguar CD
if (IsFlagSupported(FlagStrings.AtariJaguar))
{
if (this[FlagStrings.AtariJaguar] == true)
parameters.Add(FlagStrings.AtariJaguar);
parameters.Append($"{FlagStrings.AtariJaguar} ");
}
// BE Opcode
if (IsFlagSupported(FlagStrings.BEOpcode))
{
if (this[FlagStrings.BEOpcode] == true && this[FlagStrings.D8Opcode] != true)
if (this[FlagStrings.BEOpcode] == true)
{
parameters.Add(FlagStrings.BEOpcode);
if (BEOpcodeValue != null
&& (BEOpcodeValue == "raw" || BEOpcodeValue == "pack"))
parameters.Add(BEOpcodeValue);
parameters.Append($"{FlagStrings.BEOpcode} ");
if (BEOpcodeValue != null)
parameters.Append($"{BEOpcodeValue} ");
}
}
@@ -547,37 +548,37 @@ namespace MPF.ExecutionContexts.DiscImageCreator
{
if (this[FlagStrings.C2Opcode] == true)
{
parameters.Add(FlagStrings.C2Opcode);
parameters.Append($"{FlagStrings.C2Opcode} ");
if (C2OpcodeValue[0] != null)
{
if (C2OpcodeValue[0] > 0)
parameters.Add(C2OpcodeValue[0].ToString() ?? string.Empty);
parameters.Append($"{C2OpcodeValue[0]} ");
else
return null;
}
if (C2OpcodeValue[1] != null)
{
parameters.Add(C2OpcodeValue[1].ToString() ?? string.Empty);
parameters.Append($"{C2OpcodeValue[1]} ");
}
if (C2OpcodeValue[2] != null)
{
parameters.Add(C2OpcodeValue[2].ToString() ?? string.Empty);
parameters.Append($"{C2OpcodeValue[2]} ");
}
if (C2OpcodeValue[3] != null)
{
if (C2OpcodeValue[3] == 0)
{
parameters.Add(C2OpcodeValue[3].ToString() ?? string.Empty);
parameters.Append($"{C2OpcodeValue[3]} ");
}
else if (C2OpcodeValue[3] == 1)
{
parameters.Add(C2OpcodeValue[3].ToString() ?? string.Empty);
parameters.Append($"{C2OpcodeValue[3]} ");
if (C2OpcodeValue[4] != null && C2OpcodeValue[5] != null)
{
if (C2OpcodeValue[4] > 0 && C2OpcodeValue[5] > 0)
{
parameters.Add(C2OpcodeValue[4].ToString() ?? string.Empty);
parameters.Add(C2OpcodeValue[5].ToString() ?? string.Empty);
parameters.Append($"{C2OpcodeValue[4]} ");
parameters.Append($"{C2OpcodeValue[5]} ");
}
else
{
@@ -597,28 +598,28 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (IsFlagSupported(FlagStrings.CopyrightManagementInformation))
{
if (this[FlagStrings.CopyrightManagementInformation] == true)
parameters.Add(FlagStrings.CopyrightManagementInformation);
parameters.Append($"{FlagStrings.CopyrightManagementInformation} ");
}
// D8 Opcode
if (IsFlagSupported(FlagStrings.D8Opcode))
{
if (this[FlagStrings.D8Opcode] == true)
parameters.Add(FlagStrings.D8Opcode);
parameters.Append($"{FlagStrings.D8Opcode} ");
}
// DAT Expand
if (IsFlagSupported(FlagStrings.DatExpand))
{
if (this[FlagStrings.DatExpand] == true)
parameters.Add(FlagStrings.DatExpand);
parameters.Append($"{FlagStrings.DatExpand} ");
}
// Disable Beep
if (IsFlagSupported(FlagStrings.DisableBeep))
{
if (this[FlagStrings.DisableBeep] == true)
parameters.Add(FlagStrings.DisableBeep);
parameters.Append($"{FlagStrings.DisableBeep} ");
}
// DVD/HD-DVD/BD Reread
@@ -626,9 +627,9 @@ namespace MPF.ExecutionContexts.DiscImageCreator
{
if (this[FlagStrings.DVDReread] == true)
{
parameters.Add(FlagStrings.DVDReread);
parameters.Append($"{FlagStrings.DVDReread} ");
if (DVDRereadValue != null)
parameters.Add(DVDRereadValue.ToString() ?? string.Empty);
parameters.Append($"{DVDRereadValue} ");
}
}
@@ -636,7 +637,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (IsFlagSupported(FlagStrings.ExtractMicroSoftCabFile))
{
if (this[FlagStrings.ExtractMicroSoftCabFile] == true)
parameters.Add(FlagStrings.ExtractMicroSoftCabFile);
parameters.Append($"{FlagStrings.ExtractMicroSoftCabFile} ");
}
// Fix
@@ -644,9 +645,9 @@ namespace MPF.ExecutionContexts.DiscImageCreator
{
if (this[FlagStrings.Fix] == true)
{
parameters.Add(FlagStrings.Fix);
parameters.Append($"{FlagStrings.Fix} ");
if (FixValue != null)
parameters.Add(FixValue.ToString() ?? string.Empty);
parameters.Append($"{FixValue} ");
else
return null;
}
@@ -657,20 +658,27 @@ namespace MPF.ExecutionContexts.DiscImageCreator
{
if (this[FlagStrings.ForceUnitAccess] == true)
{
parameters.Add(FlagStrings.ForceUnitAccess);
parameters.Append($"{FlagStrings.ForceUnitAccess} ");
if (ForceUnitAccessValue != null)
parameters.Add(ForceUnitAccessValue.ToString() ?? string.Empty);
parameters.Append($"{ForceUnitAccessValue} ");
}
}
// Full TOC
if (IsFlagSupported(FlagStrings.FullToc))
{
if (this[FlagStrings.FullToc] == true)
parameters.Append($"{FlagStrings.FullToc} ");
}
// Multi-Sector Read
if (IsFlagSupported(FlagStrings.MultiSectorRead))
{
if (this[FlagStrings.MultiSectorRead] == true)
{
parameters.Add(FlagStrings.MultiSectorRead);
parameters.Append($"{FlagStrings.MultiSectorRead} ");
if (MultiSectorReadValue != null)
parameters.Add(MultiSectorReadValue.ToString() ?? string.Empty);
parameters.Append($"{MultiSectorReadValue} ");
}
}
@@ -678,35 +686,35 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (IsFlagSupported(FlagStrings.NoFixSubP))
{
if (this[FlagStrings.NoFixSubP] == true)
parameters.Add(FlagStrings.NoFixSubP);
parameters.Append($"{FlagStrings.NoFixSubP} ");
}
// Not fix SubQ
if (IsFlagSupported(FlagStrings.NoFixSubQ))
{
if (this[FlagStrings.NoFixSubQ] == true)
parameters.Add(FlagStrings.NoFixSubQ);
parameters.Append($"{FlagStrings.NoFixSubQ} ");
}
// Not fix SubQ (PlayStation LibCrypt)
if (IsFlagSupported(FlagStrings.NoFixSubQLibCrypt))
{
if (this[FlagStrings.NoFixSubQLibCrypt] == true)
parameters.Add(FlagStrings.NoFixSubQLibCrypt);
parameters.Append($"{FlagStrings.NoFixSubQLibCrypt} ");
}
// Not fix SubQ (SecuROM)
if (IsFlagSupported(FlagStrings.NoFixSubQSecuROM))
{
if (this[FlagStrings.NoFixSubQSecuROM] == true)
parameters.Add(FlagStrings.NoFixSubQSecuROM);
parameters.Append($"{FlagStrings.NoFixSubQSecuROM} ");
}
// Not fix SubRtoW
if (IsFlagSupported(FlagStrings.NoFixSubRtoW))
{
if (this[FlagStrings.NoFixSubRtoW] == true)
parameters.Add(FlagStrings.NoFixSubRtoW);
parameters.Append($"{FlagStrings.NoFixSubRtoW} ");
}
// Not skip security sectors
@@ -714,9 +722,9 @@ namespace MPF.ExecutionContexts.DiscImageCreator
{
if (this[FlagStrings.NoSkipSS] == true)
{
parameters.Add(FlagStrings.NoSkipSS);
parameters.Append($"{FlagStrings.NoSkipSS} ");
if (NoSkipSecuritySectorValue != null)
parameters.Add(NoSkipSecuritySectorValue.ToString() ?? string.Empty);
parameters.Append($"{NoSkipSecuritySectorValue} ");
}
}
@@ -725,9 +733,9 @@ namespace MPF.ExecutionContexts.DiscImageCreator
{
if (this[FlagStrings.PadSector] == true)
{
parameters.Add(FlagStrings.PadSector);
parameters.Append($"{FlagStrings.PadSector} ");
if (PadSectorValue != null)
parameters.Add(PadSectorValue.ToString() ?? string.Empty);
parameters.Append($"{PadSectorValue} ");
}
}
@@ -736,12 +744,16 @@ namespace MPF.ExecutionContexts.DiscImageCreator
{
if (this[FlagStrings.Range] == true)
{
if (RangeStartLBAValue == null || RangeEndLBAValue == null)
return null;
parameters.Append($"{FlagStrings.Range} ");
parameters.Add(FlagStrings.Range);
parameters.Add(RangeStartLBAValue.ToString() ?? string.Empty);
parameters.Add(RangeEndLBAValue.ToString() ?? string.Empty);
if (BaseCommand == CommandStrings.DigitalVideoDisc)
{
if (RangeStartLBAValue == null || RangeEndLBAValue == null)
return null;
parameters.Append($"{RangeStartLBAValue} ");
parameters.Append($"{RangeEndLBAValue} ");
}
}
}
@@ -749,14 +761,14 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (IsFlagSupported(FlagStrings.Raw))
{
if (this[FlagStrings.Raw] == true)
parameters.Add(FlagStrings.Raw);
parameters.Append($"{FlagStrings.Raw} ");
}
// Resume
if (IsFlagSupported(FlagStrings.Resume))
{
if (this[FlagStrings.Resume] == true)
parameters.Add(FlagStrings.Resume);
parameters.Append($"{FlagStrings.Resume} ");
}
// Reverse read
@@ -764,15 +776,15 @@ namespace MPF.ExecutionContexts.DiscImageCreator
{
if (this[FlagStrings.Reverse] == true)
{
parameters.Add(FlagStrings.Reverse);
parameters.Append($"{FlagStrings.Reverse} ");
if (BaseCommand == CommandStrings.DigitalVideoDisc)
{
if (ReverseStartLBAValue == null || ReverseEndLBAValue == null)
return null;
parameters.Add(ReverseStartLBAValue.ToString() ?? string.Empty);
parameters.Add(ReverseEndLBAValue.ToString() ?? string.Empty);
parameters.Append($"{ReverseStartLBAValue} ");
parameters.Append($"{ReverseEndLBAValue} ");
}
}
}
@@ -781,7 +793,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (IsFlagSupported(FlagStrings.ScanAntiMod))
{
if (this[FlagStrings.ScanAntiMod] == true)
parameters.Add(FlagStrings.ScanAntiMod);
parameters.Append($"{FlagStrings.ScanAntiMod} ");
}
// Scan file to detect protect
@@ -789,11 +801,11 @@ namespace MPF.ExecutionContexts.DiscImageCreator
{
if (this[FlagStrings.ScanFileProtect] == true)
{
parameters.Add(FlagStrings.ScanFileProtect);
parameters.Append($"{FlagStrings.ScanFileProtect} ");
if (ScanFileProtectValue != null)
{
if (ScanFileProtectValue > 0)
parameters.Add(ScanFileProtectValue.ToString() ?? string.Empty);
parameters.Append($"{ScanFileProtectValue} ");
else
return null;
}
@@ -804,14 +816,14 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (IsFlagSupported(FlagStrings.ScanSectorProtect))
{
if (this[FlagStrings.ScanSectorProtect] == true)
parameters.Add(FlagStrings.ScanSectorProtect);
parameters.Append($"{FlagStrings.ScanSectorProtect} ");
}
// Scan 74:00:00 (Saturn)
if (IsFlagSupported(FlagStrings.SeventyFour))
{
if (this[FlagStrings.SeventyFour] == true)
parameters.Add(FlagStrings.SeventyFour);
parameters.Append($"{FlagStrings.SeventyFour} ");
}
// Skip sectors
@@ -819,18 +831,18 @@ namespace MPF.ExecutionContexts.DiscImageCreator
{
if (this[FlagStrings.SkipSector] == true)
{
parameters.Add(FlagStrings.SkipSector);
parameters.Append($"{FlagStrings.SkipSector} ");
if (SkipSectorValue[0] != null)
{
if (SkipSectorValue[0] > 0)
parameters.Add(SkipSectorValue[0].ToString() ?? string.Empty);
parameters.Append($"{SkipSectorValue[0]} ");
else
return null;
}
if (SkipSectorValue[1] != null)
{
if (SkipSectorValue[1] == 0)
parameters.Add(SkipSectorValue[1].ToString() ?? string.Empty);
parameters.Append($"{SkipSectorValue[1]} ");
}
}
}
@@ -840,11 +852,11 @@ namespace MPF.ExecutionContexts.DiscImageCreator
{
if (this[FlagStrings.SubchannelReadLevel] == true)
{
parameters.Add(FlagStrings.SubchannelReadLevel);
parameters.Append($"{FlagStrings.SubchannelReadLevel} ");
if (SubchannelReadLevelValue != null)
{
if (SubchannelReadLevelValue >= 0 && SubchannelReadLevelValue <= 2)
parameters.Add(SubchannelReadLevelValue.ToString() ?? string.Empty);
parameters.Append($"{SubchannelReadLevelValue} ");
else
return null;
}
@@ -855,21 +867,28 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (IsFlagSupported(FlagStrings.Tages))
{
if (this[FlagStrings.Tages] == true)
parameters.Add(FlagStrings.Tages);
parameters.Append($"{FlagStrings.Tages} ");
}
// TOC
if (IsFlagSupported(FlagStrings.Toc))
{
if (this[FlagStrings.Toc] == true)
parameters.Append($"{FlagStrings.Toc} ");
}
// Try Reading Pregap
if (IsFlagSupported(FlagStrings.TryReadingPregap))
{
if (this[FlagStrings.TryReadingPregap] == true)
parameters.Add(FlagStrings.TryReadingPregap);
parameters.Append($"{FlagStrings.TryReadingPregap} ");
}
// Use Anchor Volume Descriptor Pointer
if (IsFlagSupported(FlagStrings.UseAnchorVolumeDescriptorPointer))
{
if (this[FlagStrings.UseAnchorVolumeDescriptorPointer] == true)
parameters.Add(FlagStrings.UseAnchorVolumeDescriptorPointer);
parameters.Append($"{FlagStrings.UseAnchorVolumeDescriptorPointer} ");
}
// VideoNow
@@ -877,11 +896,11 @@ namespace MPF.ExecutionContexts.DiscImageCreator
{
if (this[FlagStrings.VideoNow] == true)
{
parameters.Add(FlagStrings.VideoNow);
parameters.Append($"{FlagStrings.VideoNow} ");
if (VideoNowValue != null)
{
if (VideoNowValue >= 0)
parameters.Add(VideoNowValue.ToString() ?? string.Empty);
parameters.Append($"{VideoNowValue} ");
else
return null;
}
@@ -892,17 +911,17 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (IsFlagSupported(FlagStrings.VideoNowColor))
{
if (this[FlagStrings.VideoNowColor] == true)
parameters.Add(FlagStrings.VideoNowColor);
parameters.Append($"{FlagStrings.VideoNowColor} ");
}
// VideoNowXP
if (IsFlagSupported(FlagStrings.VideoNowXP))
{
if (this[FlagStrings.VideoNowXP] == true)
parameters.Add(FlagStrings.VideoNowXP);
parameters.Append($"{FlagStrings.VideoNowXP} ");
}
return string.Join(" ", [.. parameters]);
return parameters.ToString().TrimEnd();
}
/// <inheritdoc/>
@@ -1061,6 +1080,9 @@ namespace MPF.ExecutionContexts.DiscImageCreator
case SabreTools.RedumpLib.Data.MediaType.NintendoWiiOpticalDisc:
this[FlagStrings.Raw] = true;
break;
case SabreTools.RedumpLib.Data.MediaType.NintendoWiiUOpticalDisc:
// Currently no defaults set
break;
// Non-optical
case SabreTools.RedumpLib.Data.MediaType.FloppyDisk:
@@ -1079,7 +1101,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
return false;
// Now split the string into parts for easier validation
List<string> parts = SplitParameterString(parameters!);
string[] parts = SplitParameterString(parameters!);
// Determine what the commandline should look like given the first item
BaseCommand = parts[0];
@@ -1089,7 +1111,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
switch (BaseCommand)
{
case CommandStrings.Audio:
if (parts.Count < 6)
if (parts.Length < 6)
return false;
// Blindly assume the path exists
@@ -1103,23 +1125,23 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (!IsValidInt32(parts[3], lowerBound: 0, upperBound: 72))
return false;
else
DriveSpeed = Int32.Parse(parts[3]);
DriveSpeed = int.Parse(parts[3]);
if (!IsValidInt32(parts[4]))
return false;
else
StartLBAValue = Int32.Parse(parts[4]);
StartLBAValue = int.Parse(parts[4]);
if (!IsValidInt32(parts[5]))
return false;
else
EndLBAValue = Int32.Parse(parts[5]);
EndLBAValue = int.Parse(parts[5]);
index = 6;
break;
case CommandStrings.BluRay:
if (parts.Count < 4)
if (parts.Length < 4)
return false;
// Blindly assume the path exists
@@ -1133,13 +1155,13 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (!IsValidInt32(parts[3], lowerBound: 0, upperBound: 72))
return false;
else
DriveSpeed = Int32.Parse(parts[3]);
DriveSpeed = int.Parse(parts[3]);
index = 4;
break;
case CommandStrings.Close:
if (parts.Count != 2)
if (parts.Length != 2)
return false;
// Blindly assume the path exists
@@ -1148,7 +1170,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
break;
case CommandStrings.CompactDisc:
if (parts.Count < 4)
if (parts.Length < 4)
return false;
// Blindly assume the path exists
@@ -1162,13 +1184,13 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (!IsValidInt32(parts[3], lowerBound: 0, upperBound: 72))
return false;
else
DriveSpeed = Int32.Parse(parts[3]);
DriveSpeed = int.Parse(parts[3]);
index = 4;
break;
case CommandStrings.Data:
if (parts.Count < 6)
if (parts.Length < 6)
return false;
// Blindly assume the path exists
@@ -1182,23 +1204,23 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (!IsValidInt32(parts[3], lowerBound: 0, upperBound: 72))
return false;
else
DriveSpeed = Int32.Parse(parts[3]);
DriveSpeed = int.Parse(parts[3]);
if (!IsValidInt32(parts[4]))
return false;
else
StartLBAValue = Int32.Parse(parts[4]);
StartLBAValue = int.Parse(parts[4]);
if (!IsValidInt32(parts[5]))
return false;
else
EndLBAValue = Int32.Parse(parts[5]);
EndLBAValue = int.Parse(parts[5]);
index = 6;
break;
case CommandStrings.DigitalVideoDisc:
if (parts.Count < 4)
if (parts.Length < 4)
return false;
// Blindly assume the path exists
@@ -1212,13 +1234,13 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (!IsValidInt32(parts[3], lowerBound: 0, upperBound: 24)) // Officially 0-16
return false;
else
DriveSpeed = Int32.Parse(parts[3]);
DriveSpeed = int.Parse(parts[3]);
index = 4;
break;
case CommandStrings.Disk:
if (parts.Count != 3)
if (parts.Length < 3)
return false;
// Blindly assume the path exists
@@ -1229,10 +1251,11 @@ namespace MPF.ExecutionContexts.DiscImageCreator
else
Filename = parts[2];
index = 3;
break;
case CommandStrings.DriveSpeed:
if (parts.Count != 2)
if (parts.Length != 2)
return false;
// Blindly assume the path exists
@@ -1240,7 +1263,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
break;
case CommandStrings.Eject:
if (parts.Count != 2)
if (parts.Length != 2)
return false;
// Blindly assume the path exists
@@ -1249,7 +1272,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
break;
case CommandStrings.Floppy:
if (parts.Count != 3)
if (parts.Length < 3)
return false;
// Blindly assume the path exists
@@ -1260,10 +1283,11 @@ namespace MPF.ExecutionContexts.DiscImageCreator
else
Filename = parts[2];
index = 3;
break;
case CommandStrings.GDROM:
if (parts.Count < 4)
if (parts.Length < 4)
return false;
// Blindly assume the path exists
@@ -1277,16 +1301,16 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (!IsValidInt32(parts[3], lowerBound: 0, upperBound: 72))
return false;
else
DriveSpeed = Int32.Parse(parts[3]);
DriveSpeed = int.Parse(parts[3]);
index = 4;
break;
case CommandStrings.MDS:
if (parts.Count != 2)
if (parts.Length != 2)
return false;
if (IsFlagSupported(parts[1]) || !File.Exists(parts[1]))
if (IsFlagSupported(parts[1]))
return false;
else
Filename = parts[1];
@@ -1294,15 +1318,15 @@ namespace MPF.ExecutionContexts.DiscImageCreator
break;
case CommandStrings.Merge:
if (parts.Count != 3)
if (parts.Length != 3)
return false;
if (IsFlagSupported(parts[1]) || !File.Exists(parts[1]))
if (IsFlagSupported(parts[1]))
return false;
else
Filename = parts[1];
if (IsFlagSupported(parts[2]) || !File.Exists(parts[2]))
if (IsFlagSupported(parts[2]))
return false;
else
OptiarcFilename = parts[2];
@@ -1310,7 +1334,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
break;
case CommandStrings.Reset:
if (parts.Count != 2)
if (parts.Length != 2)
return false;
// Blindly assume the path exists
@@ -1319,7 +1343,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
break;
case CommandStrings.SACD:
if (parts.Count < 4)
if (parts.Length < 4)
return false;
// Blindly assume the path exists
@@ -1333,13 +1357,13 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (!IsValidInt32(parts[3], lowerBound: 0, upperBound: 16))
return false;
else
DriveSpeed = Int32.Parse(parts[3]);
DriveSpeed = int.Parse(parts[3]);
index = 4;
break;
case CommandStrings.Start:
if (parts.Count != 2)
if (parts.Length != 2)
return false;
// Blindly assume the path exists
@@ -1348,7 +1372,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
break;
case CommandStrings.Stop:
if (parts.Count != 2)
if (parts.Length != 2)
return false;
// Blindly assume the path exists
@@ -1357,10 +1381,10 @@ namespace MPF.ExecutionContexts.DiscImageCreator
break;
case CommandStrings.Sub:
if (parts.Count != 2)
if (parts.Length != 2)
return false;
if (IsFlagSupported(parts[1]) || !File.Exists(parts[1]))
if (IsFlagSupported(parts[1]))
return false;
else
Filename = parts[1];
@@ -1368,7 +1392,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
break;
case CommandStrings.Swap:
if (parts.Count < 4)
if (parts.Length < 4)
return false;
// Blindly assume the path exists
@@ -1382,16 +1406,16 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (!IsValidInt32(parts[3], lowerBound: 0, upperBound: 72))
return false;
else
DriveSpeed = Int32.Parse(parts[3]);
DriveSpeed = int.Parse(parts[3]);
index = 4;
break;
case CommandStrings.Tape:
if (parts.Count != 2)
if (parts.Length != 2)
return false;
if (IsFlagSupported(parts[1]) || !File.Exists(parts[1]))
if (IsFlagSupported(parts[1]))
return false;
else
Filename = parts[1];
@@ -1399,13 +1423,13 @@ namespace MPF.ExecutionContexts.DiscImageCreator
break;
case CommandStrings.Version:
if (parts.Count != 1)
if (parts.Length != 1)
return false;
break;
case CommandStrings.XBOX:
if (parts.Count < 4)
if (parts.Length < 4)
return false;
// Blindly assume the path exists
@@ -1419,7 +1443,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (!IsValidInt32(parts[3], lowerBound: 0, upperBound: 72))
return false;
else
DriveSpeed = Int32.Parse(parts[3]);
DriveSpeed = int.Parse(parts[3]);
index = 4;
break;
@@ -1427,7 +1451,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
case CommandStrings.XBOXSwap:
case CommandStrings.XGD2Swap:
case CommandStrings.XGD3Swap:
if (parts.Count < 4)
if (parts.Length < 4)
return false;
// Blindly assume the path exists
@@ -1441,15 +1465,11 @@ namespace MPF.ExecutionContexts.DiscImageCreator
if (!IsValidInt32(parts[3], lowerBound: 0, upperBound: 72))
return false;
else
DriveSpeed = Int32.Parse(parts[3]);
for (int i = 4; i < parts.Count; i++)
{
if (!Int64.TryParse(parts[i], out long temp))
return false;
}
DriveSpeed = int.Parse(parts[3]);
index = 4;
break;
default:
return false;
}
@@ -1457,16 +1477,16 @@ namespace MPF.ExecutionContexts.DiscImageCreator
// Loop through all auxiliary flags, if necessary
if (index > 0)
{
for (int i = index; i < parts.Count; i++)
for (int i = index; i < parts.Length; i++)
{
// Flag read-out values
byte? byteValue = null;
int? intValue = null;
string? stringValue = null;
byte? byteValue;
int? intValue;
string? stringValue;
// Add Offset
intValue = ProcessInt32Parameter(parts, FlagStrings.AddOffset, ref i, missingAllowed: true);
if (intValue != null && intValue != Int32.MinValue)
if (intValue != null && intValue != int.MinValue)
AddOffsetValue = intValue;
// AMSF
@@ -1505,7 +1525,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
}
else
{
C2OpcodeValue[j] = Int32.Parse(parts[i + 1]);
C2OpcodeValue[j] = int.Parse(parts[i + 1]);
i++;
}
}
@@ -1525,7 +1545,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
// DVD/HD-DVD/BD Reread
intValue = ProcessInt32Parameter(parts, FlagStrings.DVDReread, ref i, missingAllowed: true);
if (intValue != null && intValue != Int32.MinValue)
if (intValue != null && intValue != int.MinValue)
DVDRereadValue = intValue;
// Extract MS-CAB
@@ -1533,17 +1553,20 @@ namespace MPF.ExecutionContexts.DiscImageCreator
// Fix
intValue = ProcessInt32Parameter(parts, FlagStrings.Fix, ref i);
if (intValue != null && intValue != Int32.MinValue)
if (intValue != null && intValue != int.MinValue)
FixValue = intValue;
// Force Unit Access
intValue = ProcessInt32Parameter(parts, FlagStrings.ForceUnitAccess, ref i, missingAllowed: true);
if (intValue != null && intValue != Int32.MinValue && intValue >= 0)
if (intValue != null && intValue != int.MinValue && intValue >= 0)
ForceUnitAccessValue = intValue;
// Full TOC
ProcessFlagParameter(parts, FlagStrings.FullToc, ref i);
// Multi-Sector Read
intValue = ProcessInt32Parameter(parts, FlagStrings.MultiSectorRead, ref i, missingAllowed: true);
if (intValue != null && intValue != Int32.MinValue && intValue >= 0)
if (intValue != null && intValue != int.MinValue && intValue >= 0)
MultiSectorReadValue = intValue;
// NoFixSubP
@@ -1563,7 +1586,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
// NoSkipSS
intValue = ProcessInt32Parameter(parts, FlagStrings.NoSkipSS, ref i, missingAllowed: true);
if (intValue != null && intValue != Int32.MinValue && intValue >= 0)
if (intValue != null && intValue != int.MinValue && intValue >= 0)
NoSkipSecuritySectorValue = intValue;
// PadSector
@@ -1579,15 +1602,15 @@ namespace MPF.ExecutionContexts.DiscImageCreator
{
if (!DoesExist(parts, i + 1) || !DoesExist(parts, i + 2))
return false;
else if (!IsValidInt32(parts[i + 1], lowerBound: 0) || !IsValidInt32(parts[i + 2], lowerBound: 0))
else if (!IsValidInt32(parts[i + 1], lowerBound: -1) || !IsValidInt32(parts[i + 2], lowerBound: -1))
return false;
RangeStartLBAValue = Int32.Parse(parts[i + 1]);
RangeEndLBAValue = Int32.Parse(parts[i + 2]);
RangeStartLBAValue = int.Parse(parts[i + 1]);
RangeEndLBAValue = int.Parse(parts[i + 2]);
i += 2;
}
this[FlagStrings.Reverse] = true;
this[FlagStrings.Range] = true;
}
// Raw
@@ -1607,8 +1630,8 @@ namespace MPF.ExecutionContexts.DiscImageCreator
else if (!IsValidInt32(parts[i + 1], lowerBound: 0) || !IsValidInt32(parts[i + 2], lowerBound: 0))
return false;
ReverseStartLBAValue = Int32.Parse(parts[i + 1]);
ReverseEndLBAValue = Int32.Parse(parts[i + 2]);
ReverseStartLBAValue = int.Parse(parts[i + 1]);
ReverseEndLBAValue = int.Parse(parts[i + 2]);
i += 2;
}
@@ -1620,7 +1643,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
// ScanFileProtect
intValue = ProcessInt32Parameter(parts, FlagStrings.ScanFileProtect, ref i, missingAllowed: true);
if (intValue != null && intValue != Int32.MinValue && intValue >= 0)
if (intValue != null && intValue != int.MinValue && intValue >= 0)
ScanFileProtectValue = intValue;
// ScanSectorProtect
@@ -1650,7 +1673,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
}
else
{
SkipSectorValue[j] = Int32.Parse(parts[i + 1]);
SkipSectorValue[j] = int.Parse(parts[i + 1]);
i++;
}
}
@@ -1661,15 +1684,24 @@ namespace MPF.ExecutionContexts.DiscImageCreator
// SubchannelReadLevel
intValue = ProcessInt32Parameter(parts, FlagStrings.SubchannelReadLevel, ref i, missingAllowed: true);
if (intValue != null && intValue != Int32.MinValue && intValue >= 0 && intValue <= 2)
if (intValue != null && intValue != int.MinValue && intValue >= 0 && intValue <= 2)
SubchannelReadLevelValue = intValue;
// SeventyFour
// Tages
ProcessFlagParameter(parts, FlagStrings.Tages, ref i);
// TOC
ProcessFlagParameter(parts, FlagStrings.Toc, ref i);
// TryReadingPregap
ProcessFlagParameter(parts, FlagStrings.TryReadingPregap, ref i);
// UseAnchorVolumeDescriptorPointer
ProcessFlagParameter(parts, FlagStrings.UseAnchorVolumeDescriptorPointer, ref i);
// VideoNow
intValue = ProcessInt32Parameter(parts, FlagStrings.VideoNow, ref i, missingAllowed: true);
if (intValue != null && intValue != Int32.MinValue && intValue >= 0)
if (intValue != null && intValue != int.MinValue && intValue >= 0)
VideoNowValue = intValue;
// VideoNowColor
@@ -1733,6 +1765,9 @@ namespace MPF.ExecutionContexts.DiscImageCreator
case SabreTools.RedumpLib.Data.MediaType.NintendoWiiOpticalDisc:
BaseCommand = CommandStrings.DigitalVideoDisc;
return;
case SabreTools.RedumpLib.Data.MediaType.NintendoWiiUOpticalDisc:
BaseCommand = CommandStrings.BluRay;
return;
case SabreTools.RedumpLib.Data.MediaType.FloppyDisk:
BaseCommand = CommandStrings.Floppy;
return;

View File

@@ -18,6 +18,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
public const string ExtractMicroSoftCabFile = "/mscf";
public const string Fix = "/fix";
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";
@@ -37,6 +38,7 @@ namespace MPF.ExecutionContexts.DiscImageCreator
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";

View File

@@ -5,28 +5,34 @@
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.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.2.4</VersionPrefix>
<VersionPrefix>3.3.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-2024</Copyright>
<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>
<InternalsVisibleTo Include="MPF.Test" />
<None Include="README.md" Pack="true" PackagePath="" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.RedumpLib" Version="1.5.2" />
<InternalsVisibleTo Include="MPF.ExecutionContexts.Test" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.4" />
</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

@@ -15,10 +15,14 @@ namespace MPF.ExecutionContexts.Redumper
{
return type switch
{
MediaType.CDROM => ".bin",
MediaType.CDROM
or MediaType.GDROM => ".bin",
MediaType.DVD
or MediaType.HDDVD
or MediaType.BluRay => ".iso",
or MediaType.BluRay
or MediaType.NintendoWiiOpticalDisc => ".iso",
MediaType.NintendoGameCubeGameDisc => ".raw",
MediaType.NintendoWiiUOpticalDisc => ".wud",
_ => null,
};
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using MPF.ExecutionContexts.Data;
using SabreTools.RedumpLib.Data;
namespace MPF.ExecutionContexts.Redumper
@@ -13,16 +14,27 @@ namespace MPF.ExecutionContexts.Redumper
#region Generic Dumping Information
/// <inheritdoc/>
public override string? InputPath => DriveValue?.Trim('"');
public override string? InputPath
=> (_inputs[FlagStrings.Drive] as StringInput)?.Value?.Trim('"');
/// <inheritdoc/>
public override string? OutputPath => Path.Combine(
ImagePathValue?.Trim('"') ?? string.Empty,
ImageNameValue?.Trim('"') ?? string.Empty)
(_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 => SpeedValue;
public override int? Speed
{
get
{
return (_inputs[FlagStrings.Speed] as Int32Input)?.Value;
}
set
{
(_inputs[FlagStrings.Speed] as Int32Input)?.SetValue(value);
}
}
#endregion
@@ -33,125 +45,63 @@ namespace MPF.ExecutionContexts.Redumper
/// </summary>
public List<string>? ModeValues { get; set; }
#region General
/// <summary>
/// Drive to use, first available drive with disc, if not provided
/// Set of all command flags
/// </summary>
public string? DriveValue { get; set; }
private readonly Dictionary<string, Input> _inputs = new()
{
// General
[FlagStrings.HelpLong] = new FlagInput(FlagStrings.HelpShort, FlagStrings.HelpLong),
[FlagStrings.Version] = new FlagInput(FlagStrings.Version),
[FlagStrings.Verbose] = new FlagInput(FlagStrings.Verbose),
[FlagStrings.AutoEject] = new FlagInput(FlagStrings.AutoEject),
[FlagStrings.Debug] = new FlagInput(FlagStrings.Debug),
[FlagStrings.Drive] = new StringInput(FlagStrings.Drive),
[FlagStrings.Speed] = new Int32Input(FlagStrings.Speed),
[FlagStrings.Retries] = new Int32Input(FlagStrings.Retries),
[FlagStrings.ImagePath] = new StringInput(FlagStrings.ImagePath) { Quotes = true },
[FlagStrings.ImageName] = new StringInput(FlagStrings.ImageName) { Quotes = true },
[FlagStrings.Overwrite] = new FlagInput(FlagStrings.Overwrite),
/// <summary>
/// Drive read speed, optimal drive speed will be used if not provided
/// </summary>
public int? SpeedValue { get; set; }
// Drive Configuration
[FlagStrings.Overwrite] = new FlagInput(FlagStrings.Overwrite),
[FlagStrings.DriveType] = new StringInput(FlagStrings.DriveType),
[FlagStrings.DriveReadOffset] = new Int32Input(FlagStrings.DriveReadOffset),
[FlagStrings.DriveC2Shift] = new Int32Input(FlagStrings.DriveC2Shift),
[FlagStrings.DrivePregapStart] = new Int32Input(FlagStrings.DrivePregapStart),
[FlagStrings.DriveReadMethod] = new StringInput(FlagStrings.DriveReadMethod),
[FlagStrings.DriveSectorOrder] = new StringInput(FlagStrings.DriveSectorOrder),
/// <summary>
/// Number of sector retries in case of SCSI/C2 error (default: 0)
/// </summary>
public int? RetriesValue { get; set; }
// Drive Specific
[FlagStrings.PlextorSkipLeadin] = new FlagInput(FlagStrings.PlextorSkipLeadin),
[FlagStrings.PlextorLeadinRetries] = new Int32Input(FlagStrings.PlextorLeadinRetries),
[FlagStrings.AsusSkipLeadout] = new FlagInput(FlagStrings.AsusSkipLeadout),
/// <summary>
/// Dump files base directory
/// </summary>
public string? ImagePathValue { get; set; }
// Offset
[FlagStrings.ForceOffset] = new Int32Input(FlagStrings.ForceOffset),
[FlagStrings.AudioSilenceThreshold] = new Int32Input(FlagStrings.AudioSilenceThreshold),
[FlagStrings.CorrectOffsetShift] = new FlagInput(FlagStrings.CorrectOffsetShift),
[FlagStrings.OffsetShiftRelocate] = new FlagInput(FlagStrings.OffsetShiftRelocate),
/// <summary>
/// Dump files prefix, autogenerated in dump mode, if not provided
/// </summary>
public string? ImageNameValue { get; set; }
// Split
[FlagStrings.ForceSplit] = new FlagInput(FlagStrings.ForceSplit),
[FlagStrings.LeaveUnchanged] = new FlagInput(FlagStrings.LeaveUnchanged),
[FlagStrings.ForceQTOC] = new FlagInput(FlagStrings.ForceQTOC),
[FlagStrings.SkipFill] = new UInt8Input(FlagStrings.SkipFill),
[FlagStrings.ISO9660Trim] = new FlagInput(FlagStrings.ISO9660Trim),
#endregion
#region Drive Configuration
/// <summary>
/// Override drive type, possible values: GENERIC, PLEXTOR, LG_ASUS
/// </summary>
public string? DriveTypeValue { get; set; }
/// <summary>
/// Override drive read offset
/// </summary>
public int? DriveReadOffsetValue { get; set; }
/// <summary>
/// Override drive C2 shift
/// </summary>
public int? DriveC2ShiftValue { get; set; }
/// <summary>
/// Override drive pre-gap start LBA
/// </summary>
public int? DrivePregapStartValue { get; set; }
/// <summary>
/// Override drive read method, possible values: BE, D8, BE_CDDA
/// </summary>
public string? DriveReadMethodValue { get; set; }
/// <summary>
/// Override drive sector order, possible values: DATA_C2_SUB, DATA_SUB_C2
/// </summary>
public string? DriveSectorOrderValue { get; set; }
#endregion
#region Offset
/// <summary>
/// Override offset autodetection and use supplied value
/// </summary>
public int? ForceOffsetValue { get; set; }
/// <summary>
/// Maximum absolute sample value to treat it as silence (default: 32)
/// </summary>
public int? AudioSilenceThresholdValue { get; set; }
#endregion
#region Split
/// <summary>
/// Fill byte value for skipped sectors (default: 0x55)
/// </summary>
public byte? SkipFillValue { get; set; }
#endregion
#region Miscellaneous
/// <summary>
/// LBA to start dumping from
/// </summary>
public int? LBAStartValue { get; set; }
/// <summary>
/// LBA to stop dumping at (everything before the value), useful for discs with fake TOC
/// </summary>
public int? LBAEndValue { get; set; }
/// <summary>
/// LBA ranges of sectors to skip
/// </summary>
public string? SkipValue { get; set; }
/// <summary>
/// Write offset for dumps when reading as data
/// </summary>
public int? DumpWriteOffsetValue { get; set; }
/// <summary>
/// Number of sectors to read at once on initial dump, DVD only (Default 32)
/// </summary>
public int? DumpReadSizeValue { get; set; }
/// <summary>
/// Maximum number of lead-in retries per session (Default 4)
/// </summary>
public int? PlextorLeadinRetriesValue { get; set; }
#endregion
// Miscellaneous
[FlagStrings.LBAStart] = new Int32Input(FlagStrings.LBAStart),
[FlagStrings.LBAEnd] = new Int32Input(FlagStrings.LBAEnd),
[FlagStrings.RefineSubchannel] = new FlagInput(FlagStrings.RefineSubchannel),
[FlagStrings.Skip] = new StringInput(FlagStrings.Skip),
[FlagStrings.DumpWriteOffset] = new Int32Input(FlagStrings.DumpWriteOffset),
[FlagStrings.DumpReadSize] = new Int32Input(FlagStrings.DumpReadSize),
[FlagStrings.OverreadLeadout] = new FlagInput(FlagStrings.OverreadLeadout),
[FlagStrings.ForceUnscrambled] = new FlagInput(FlagStrings.ForceUnscrambled),
[FlagStrings.LegacySubs] = new FlagInput(FlagStrings.LegacySubs),
[FlagStrings.DisableCDText] = new FlagInput(FlagStrings.DisableCDText),
};
#endregion
@@ -242,259 +192,28 @@ namespace MPF.ExecutionContexts.Redumper
/// </remarks>
public override string GenerateParameters()
{
var parameters = new List<string>();
var parameters = new StringBuilder();
ModeValues ??= [CommandStrings.NONE];
// Modes
parameters.AddRange(ModeValues);
string modes = string.Join(" ", [.. ModeValues]);
if (modes.Length > 0)
parameters.Append($"{modes} ");
#region General
// Help
if (this[FlagStrings.HelpLong] == true)
parameters.Add(FlagStrings.HelpLong);
// Version
if (this[FlagStrings.Version] == true)
parameters.Add(FlagStrings.Version);
// Verbose
if (this[FlagStrings.Verbose] == true)
parameters.Add(FlagStrings.Verbose);
// Auto Eject
if (this[FlagStrings.AutoEject] == true)
parameters.Add(FlagStrings.AutoEject);
// Debug
if (this[FlagStrings.Debug] == true)
parameters.Add(FlagStrings.Debug);
// Drive
if (this[FlagStrings.Drive] == true)
// Loop though and append all existing
foreach (var kvp in _inputs)
{
if (DriveValue != null)
{
if (DriveValue.Contains(" "))
parameters.Add($"{FlagStrings.Drive}=\"{DriveValue}\"");
else
parameters.Add($"{FlagStrings.Drive}={DriveValue}");
}
// If the value doesn't exist
string formatted = kvp.Value.Format(useEquals: true);
if (formatted.Length == 0)
continue;
// Append the parameter
parameters.Append($"{formatted} ");
}
// Speed
if (this[FlagStrings.Speed] == true)
{
if (SpeedValue != null)
parameters.Add($"{FlagStrings.Speed}={SpeedValue}");
}
// Retries
if (this[FlagStrings.Retries] == true)
{
if (RetriesValue != null)
parameters.Add($"{FlagStrings.Retries}={RetriesValue}");
}
// Image Path
if (this[FlagStrings.ImagePath] == true)
{
if (ImagePathValue != null)
parameters.Add($"{FlagStrings.ImagePath}={ImagePathValue}");
}
// Image Name
if (this[FlagStrings.ImageName] == true)
{
if (ImageNameValue != null)
parameters.Add($"{FlagStrings.ImageName}={ImageNameValue}");
}
// Overwrite
if (this[FlagStrings.Overwrite] == true)
parameters.Add(FlagStrings.Overwrite);
#endregion
#region Drive Configuration
// Drive Type
if (this[FlagStrings.DriveType] == true)
{
if (DriveTypeValue != null)
parameters.Add($"{FlagStrings.DriveType}={DriveTypeValue}");
}
// Drive Read Offset
if (this[FlagStrings.DriveReadOffset] == true)
{
if (DriveReadOffsetValue != null)
parameters.Add($"{FlagStrings.DriveReadOffset}={DriveReadOffsetValue}");
}
// Drive C2 Shift
if (this[FlagStrings.DriveC2Shift] == true)
{
if (DriveC2ShiftValue != null)
parameters.Add($"{FlagStrings.DriveC2Shift}={DriveC2ShiftValue}");
}
// Drive Pregap Start
if (this[FlagStrings.DrivePregapStart] == true)
{
if (DrivePregapStartValue != null)
parameters.Add($"{FlagStrings.DrivePregapStart}={DrivePregapStartValue}");
}
// Drive Read Method
if (this[FlagStrings.DriveReadMethod] == true)
{
if (DriveReadMethodValue != null)
parameters.Add($"{FlagStrings.DriveReadMethod}={DriveReadMethodValue}");
}
// Drive Sector Order
if (this[FlagStrings.DriveSectorOrder] == true)
{
if (DriveSectorOrderValue != null)
parameters.Add($"{FlagStrings.DriveSectorOrder}={DriveSectorOrderValue}");
}
#endregion
#region Drive Specific
// Plextor Leadin Skip
if (this[FlagStrings.PlextorSkipLeadin] == true)
parameters.Add(FlagStrings.PlextorSkipLeadin);
// Plextor Leadin Retries
if (this[FlagStrings.PlextorLeadinRetries] == true)
{
if (PlextorLeadinRetriesValue != null)
parameters.Add($"{FlagStrings.PlextorLeadinRetries}={PlextorLeadinRetriesValue}");
}
// Asus Skip Leadout
if (this[FlagStrings.AsusSkipLeadout] == true)
parameters.Add(FlagStrings.AsusSkipLeadout);
#endregion
#region Offset
// Force Offset
if (this[FlagStrings.ForceOffset] == true)
{
if (ForceOffsetValue != null)
parameters.Add($"{FlagStrings.ForceOffset}={ForceOffsetValue}");
}
// Audio Silence Threshold
if (this[FlagStrings.AudioSilenceThreshold] == true)
{
if (AudioSilenceThresholdValue != null)
parameters.Add($"{FlagStrings.AudioSilenceThreshold}={AudioSilenceThresholdValue}");
}
// Correct Offset Shift
if (this[FlagStrings.CorrectOffsetShift] == true)
parameters.Add(FlagStrings.CorrectOffsetShift);
// Offset Shift Relocate
if (this[FlagStrings.OffsetShiftRelocate] == true)
parameters.Add(FlagStrings.OffsetShiftRelocate);
#endregion
#region Split
// Force Split
if (this[FlagStrings.ForceSplit] == true)
parameters.Add(FlagStrings.ForceSplit);
// Leave Unchanged
if (this[FlagStrings.LeaveUnchanged] == true)
parameters.Add(FlagStrings.LeaveUnchanged);
// Force QTOC
if (this[FlagStrings.ForceQTOC] == true)
parameters.Add(FlagStrings.ForceQTOC);
// Skip Fill
if (this[FlagStrings.SkipFill] == true)
{
if (SkipFillValue != null)
parameters.Add($"{FlagStrings.SkipFill}={SkipFillValue:x}");
}
// ISO9660 Trim
if (this[FlagStrings.ISO9660Trim] == true)
parameters.Add(FlagStrings.ISO9660Trim);
#endregion
#region Miscellaneous
// LBA Start
if (this[FlagStrings.LBAStart] == true)
{
if (LBAStartValue != null)
parameters.Add($"{FlagStrings.LBAStart}={LBAStartValue}");
}
// LBA End
if (this[FlagStrings.LBAEnd] == true)
{
if (LBAEndValue != null)
parameters.Add($"{FlagStrings.LBAEnd}={LBAEndValue}");
}
// Refine Subchannel
if (this[FlagStrings.RefineSubchannel] == true)
parameters.Add(FlagStrings.RefineSubchannel);
// Skip
if (this[FlagStrings.Skip] == true)
{
if (!string.IsNullOrEmpty(SkipValue))
parameters.Add($"{FlagStrings.Skip}={SkipValue}");
}
// Dump Write Offset
if (this[FlagStrings.DumpWriteOffset] == true)
{
if (DumpWriteOffsetValue != null)
parameters.Add($"{FlagStrings.DumpWriteOffset}={DumpWriteOffsetValue}");
}
// Dump Read Size
if (this[FlagStrings.DumpReadSize] == true)
{
if (DumpReadSizeValue != null && DumpReadSizeValue > 0)
parameters.Add($"{FlagStrings.DumpReadSize}={DumpReadSizeValue}");
}
// Overread Leadout
if (this[FlagStrings.OverreadLeadout] == true)
parameters.Add(FlagStrings.OverreadLeadout);
// Force Unscrambled
if (this[FlagStrings.ForceUnscrambled] == true)
parameters.Add(FlagStrings.ForceUnscrambled);
// Legacy Subs
if (this[FlagStrings.LegacySubs] == true)
parameters.Add(FlagStrings.LegacySubs);
// Disable CD Text
if (this[FlagStrings.DisableCDText] == true)
parameters.Add(FlagStrings.DisableCDText);
#endregion
return string.Join(" ", [.. parameters]);
return parameters.ToString().TrimEnd();
}
/// <inheritdoc/>
@@ -506,14 +225,13 @@ namespace MPF.ExecutionContexts.Redumper
/// <inheritdoc/>
public override bool IsDumpingCommand()
{
return BaseCommand == CommandStrings.NONE
|| BaseCommand?.Contains(CommandStrings.CD) == true
|| BaseCommand?.Contains(CommandStrings.DVD) == true
|| BaseCommand?.Contains(CommandStrings.BluRay) == true
|| BaseCommand?.Contains(CommandStrings.SACD) == true
|| BaseCommand?.Contains(CommandStrings.New) == true
|| BaseCommand?.Contains(CommandStrings.Dump) == true
|| BaseCommand?.Contains(CommandStrings.DumpNew) == true;
return ModeValues?.Contains(CommandStrings.CD) == true
|| ModeValues?.Contains(CommandStrings.DVD) == true
|| ModeValues?.Contains(CommandStrings.BluRay) == true
|| ModeValues?.Contains(CommandStrings.SACD) == true
|| ModeValues?.Contains(CommandStrings.New) == true
|| ModeValues?.Contains(CommandStrings.Dump) == true
|| ModeValues?.Contains(CommandStrings.DumpNew) == true;
}
/// <inheritdoc/>
@@ -523,33 +241,8 @@ namespace MPF.ExecutionContexts.Redumper
flags = [];
// General
DriveValue = null;
SpeedValue = null;
RetriesValue = null;
ImagePathValue = null;
ImageNameValue = null;
// Drive Configuration
DriveTypeValue = null;
DriveReadOffsetValue = null;
DriveC2ShiftValue = null;
DrivePregapStartValue = null;
DriveReadMethodValue = null;
DriveSectorOrderValue = null;
// Offset
ForceOffsetValue = null;
AudioSilenceThresholdValue = null;
// Split
SkipFillValue = null;
// Miscellaneous
LBAStartValue = null;
LBAEndValue = null;
SkipValue = null;
DumpReadSizeValue = null;
foreach (var kvp in _inputs)
kvp.Value.ClearValue();
}
/// <inheritdoc/>
@@ -558,15 +251,6 @@ namespace MPF.ExecutionContexts.Redumper
int? driveSpeed,
Dictionary<string, string?> options)
{
// If we don't have a CD, DVD, HD-DVD, or BD, we can't dump using redumper
if (MediaType != SabreTools.RedumpLib.Data.MediaType.CDROM
&& MediaType != SabreTools.RedumpLib.Data.MediaType.DVD
&& MediaType != SabreTools.RedumpLib.Data.MediaType.HDDVD
&& MediaType != SabreTools.RedumpLib.Data.MediaType.BluRay)
{
return;
}
BaseCommand = CommandStrings.NONE;
switch (MediaType)
{
@@ -578,12 +262,15 @@ namespace MPF.ExecutionContexts.Redumper
};
break;
case SabreTools.RedumpLib.Data.MediaType.DVD:
case SabreTools.RedumpLib.Data.MediaType.NintendoGameCubeGameDisc:
case SabreTools.RedumpLib.Data.MediaType.NintendoWiiOpticalDisc:
ModeValues = [CommandStrings.DVD];
break;
case SabreTools.RedumpLib.Data.MediaType.HDDVD: // TODO: Keep in sync if another command string shows up
ModeValues = [CommandStrings.DVD];
break;
case SabreTools.RedumpLib.Data.MediaType.BluRay:
case SabreTools.RedumpLib.Data.MediaType.NintendoWiiUOpticalDisc:
ModeValues = [CommandStrings.BluRay];
break;
default:
@@ -592,36 +279,42 @@ namespace MPF.ExecutionContexts.Redumper
}
this[FlagStrings.Drive] = true;
DriveValue = drivePath;
(_inputs[FlagStrings.Drive] as StringInput)?.SetValue(drivePath ?? string.Empty);
this[FlagStrings.Speed] = true;
SpeedValue = driveSpeed;
(_inputs[FlagStrings.Speed] as Int32Input)?.SetValue(driveSpeed);
// Set user-defined options
if (GetBooleanSetting(options, SettingConstants.EnableVerbose, SettingConstants.EnableVerboseDefault))
{
this[FlagStrings.Verbose] = true;
(_inputs[FlagStrings.Verbose] as FlagInput)?.SetValue(true);
}
if (GetBooleanSetting(options, SettingConstants.EnableDebug, SettingConstants.EnableDebugDefault))
{
this[FlagStrings.Debug] = true;
(_inputs[FlagStrings.Debug] as FlagInput)?.SetValue(true);
}
string? readMethod = GetStringSetting(options, SettingConstants.ReadMethod, SettingConstants.ReadMethodDefault);
if (!string.IsNullOrEmpty(readMethod) && readMethod != ReadMethod.NONE.ToString())
{
this[FlagStrings.DriveReadMethod] = true;
DriveReadMethodValue = readMethod;
(_inputs[FlagStrings.DriveReadMethod] as StringInput)?.SetValue(readMethod!);
}
string? sectorOrder = GetStringSetting(options, SettingConstants.SectorOrder, SettingConstants.SectorOrderDefault);
if (!string.IsNullOrEmpty(sectorOrder) && sectorOrder != SectorOrder.NONE.ToString())
{
this[FlagStrings.DriveSectorOrder] = true;
DriveSectorOrderValue = sectorOrder;
(_inputs[FlagStrings.DriveSectorOrder] as StringInput)?.SetValue(sectorOrder!);
}
if (GetBooleanSetting(options, SettingConstants.UseGenericDriveType, SettingConstants.UseGenericDriveTypeDefault))
{
this[FlagStrings.DriveType] = true;
DriveTypeValue = "GENERIC";
(_inputs[FlagStrings.DriveType] as StringInput)?.SetValue("GENERIC");
}
// Set the output paths
@@ -631,24 +324,24 @@ namespace MPF.ExecutionContexts.Redumper
if (!string.IsNullOrEmpty(imagePath))
{
this[FlagStrings.ImagePath] = true;
ImagePathValue = $"\"{imagePath}\"";
(_inputs[FlagStrings.ImagePath] as StringInput)?.SetValue(imagePath!);
}
string imageName = Path.GetFileNameWithoutExtension(filename);
if (!string.IsNullOrEmpty(imageName))
{
this[FlagStrings.ImageName] = true;
ImageNameValue = $"\"{imageName}\"";
(_inputs[FlagStrings.ImageName] as StringInput)?.SetValue(imageName!);
}
}
this[FlagStrings.Retries] = true;
RetriesValue = GetInt32Setting(options, SettingConstants.RereadCount, SettingConstants.RereadCountDefault);
(_inputs[FlagStrings.Retries] as Int32Input)?.SetValue(GetInt32Setting(options, SettingConstants.RereadCount, SettingConstants.RereadCountDefault));
if (GetBooleanSetting(options, SettingConstants.EnableLeadinRetry, SettingConstants.EnableLeadinRetryDefault))
{
this[FlagStrings.PlextorLeadinRetries] = true;
PlextorLeadinRetriesValue = GetInt32Setting(options, SettingConstants.LeadinRetryCount, SettingConstants.LeadinRetryCountDefault);
(_inputs[FlagStrings.Speed] as Int32Input)?.SetValue(GetInt32Setting(options, SettingConstants.LeadinRetryCount, SettingConstants.LeadinRetryCountDefault));
}
}
@@ -662,14 +355,14 @@ namespace MPF.ExecutionContexts.Redumper
return false;
// Now split the string into parts for easier validation
List<string> parts = SplitParameterString(parameters!);
string[] parts = SplitParameterString(parameters!);
// Setup the modes
ModeValues = [];
// All modes should be cached separately
int index = 0;
for (; index < parts.Count; index++)
for (; index < parts.Length; index++)
{
// Flag to see if we have a flag
bool isFlag = false;
@@ -697,7 +390,7 @@ namespace MPF.ExecutionContexts.Redumper
case CommandStrings.Info:
case CommandStrings.Skeleton:
case CommandStrings.Debug:
//case CommandStrings.FixMSF:
//case CommandStrings.FixMSF:
ModeValues.Add(part);
break;
@@ -720,195 +413,23 @@ namespace MPF.ExecutionContexts.Redumper
}
// Loop through all auxiliary flags, if necessary
for (int i = index; i < parts.Count; i++)
for (int i = index; i < parts.Length; i++)
{
// Flag read-out values
byte? byteValue = null;
int? intValue = null;
string? stringValue = null;
// Match all possible flags
foreach (var kvp in _inputs)
{
// If the value was not a match
if (!kvp.Value.Process(parts, ref i))
continue;
#region General
// Help
ProcessFlagParameter(parts, FlagStrings.HelpShort, FlagStrings.HelpLong, ref i);
// Version
ProcessFlagParameter(parts, FlagStrings.Version, ref i);
// Verbose
ProcessFlagParameter(parts, FlagStrings.Verbose, ref i);
// Debug
ProcessFlagParameter(parts, FlagStrings.Debug, ref i);
// Drive
stringValue = ProcessStringParameter(parts, FlagStrings.Drive, ref i);
if (!string.IsNullOrEmpty(stringValue))
DriveValue = stringValue;
// Speed
intValue = ProcessInt32Parameter(parts, FlagStrings.Speed, ref i);
if (intValue != null && intValue != Int32.MinValue)
SpeedValue = intValue;
// Retries
intValue = ProcessInt32Parameter(parts, FlagStrings.Retries, ref i);
if (intValue != null && intValue != Int32.MinValue)
RetriesValue = intValue;
// Image Path
stringValue = ProcessStringParameter(parts, FlagStrings.ImagePath, ref i);
if (!string.IsNullOrEmpty(stringValue))
ImagePathValue = $"\"{stringValue!.Trim('"')}\"";
// Image Name
stringValue = ProcessStringParameter(parts, FlagStrings.ImageName, ref i);
if (!string.IsNullOrEmpty(stringValue))
ImageNameValue = $"\"{stringValue!.Trim('"')}\"";
// Overwrite
ProcessFlagParameter(parts, FlagStrings.Overwrite, ref i);
#endregion
#region Drive Configuration
// Drive Type
stringValue = ProcessStringParameter(parts, FlagStrings.DriveType, ref i);
if (!string.IsNullOrEmpty(stringValue))
DriveTypeValue = stringValue;
// Drive Read Offset
intValue = ProcessInt32Parameter(parts, FlagStrings.DriveReadOffset, ref i);
if (intValue != null && intValue != Int32.MinValue)
DriveReadOffsetValue = intValue;
// Drive C2 Shift
intValue = ProcessInt32Parameter(parts, FlagStrings.DriveC2Shift, ref i);
if (intValue != null && intValue != Int32.MinValue)
DriveC2ShiftValue = intValue;
// Drive Pregap Start
intValue = ProcessInt32Parameter(parts, FlagStrings.DrivePregapStart, ref i);
if (intValue != null && intValue != Int32.MinValue)
DrivePregapStartValue = intValue;
// Drive Read Method
stringValue = ProcessStringParameter(parts, FlagStrings.DriveReadMethod, ref i);
if (!string.IsNullOrEmpty(stringValue))
DriveReadMethodValue = stringValue;
// Drive Sector Order
stringValue = ProcessStringParameter(parts, FlagStrings.DriveSectorOrder, ref i);
if (!string.IsNullOrEmpty(stringValue))
DriveSectorOrderValue = stringValue;
#endregion
#region Drive Specific
// Plextor Skip Leadin
ProcessFlagParameter(parts, FlagStrings.PlextorSkipLeadin, ref i);
// Plextor Leadin Retries
intValue = ProcessInt32Parameter(parts, FlagStrings.PlextorLeadinRetries, ref i);
if (intValue != null && intValue != Int32.MinValue)
PlextorLeadinRetriesValue = intValue;
// Asus Skip Leadout
ProcessFlagParameter(parts, FlagStrings.AsusSkipLeadout, ref i);
#endregion
#region Offset
// Force Offset
intValue = ProcessInt32Parameter(parts, FlagStrings.ForceOffset, ref i);
if (intValue != null && intValue != Int32.MinValue)
ForceOffsetValue = intValue;
// Audio Silence Threshold
intValue = ProcessInt32Parameter(parts, FlagStrings.AudioSilenceThreshold, ref i);
if (intValue != null && intValue != Int32.MinValue)
AudioSilenceThresholdValue = intValue;
// Correct Offset Shift
ProcessFlagParameter(parts, FlagStrings.CorrectOffsetShift, ref i);
// Correct Shift Relocate
ProcessFlagParameter(parts, FlagStrings.OffsetShiftRelocate, ref i);
#endregion
#region Split
// Force Split
ProcessFlagParameter(parts, FlagStrings.ForceSplit, ref i);
// Leave Unchanged
ProcessFlagParameter(parts, FlagStrings.LeaveUnchanged, ref i);
// Force QTOC
ProcessFlagParameter(parts, FlagStrings.ForceQTOC, ref i);
// Skip Fill
byteValue = ProcessUInt8Parameter(parts, FlagStrings.SkipFill, ref i);
if (byteValue != null && byteValue != Byte.MinValue)
SkipFillValue = byteValue;
// ISO9660 Trim
ProcessFlagParameter(parts, FlagStrings.ISO9660Trim, ref i);
#endregion
#region Miscellaneous
// LBA Start
intValue = ProcessInt32Parameter(parts, FlagStrings.LBAStart, ref i);
if (intValue != null && intValue != Int32.MinValue)
LBAStartValue = intValue;
// LBA End
intValue = ProcessInt32Parameter(parts, FlagStrings.LBAEnd, ref i);
if (intValue != null && intValue != Int32.MinValue)
LBAEndValue = intValue;
// Refine Subchannel
ProcessFlagParameter(parts, FlagStrings.RefineSubchannel, ref i);
// Skip
stringValue = ProcessStringParameter(parts, FlagStrings.Skip, ref i);
if (!string.IsNullOrEmpty(stringValue))
SkipValue = stringValue;
// Dump Write Offset
intValue = ProcessInt32Parameter(parts, FlagStrings.DumpWriteOffset, ref i);
if (intValue != null && intValue != Int32.MinValue)
DumpWriteOffsetValue = intValue;
// Dump Read Size
intValue = ProcessInt32Parameter(parts, FlagStrings.DumpReadSize, ref i);
if (intValue != null && intValue != Int32.MinValue)
DumpReadSizeValue = intValue;
// Overread Leadout
ProcessFlagParameter(parts, FlagStrings.OverreadLeadout, ref i);
// Force Unscrambled
ProcessFlagParameter(parts, FlagStrings.ForceUnscrambled, ref i);
// Legacy Subs
ProcessFlagParameter(parts, FlagStrings.LegacySubs, ref i);
// Disable CD Text
ProcessFlagParameter(parts, FlagStrings.DisableCDText, ref i);
#endregion
// Set the flag
this[kvp.Key] = true;
}
}
// If the image name was not set, set it with a default value
if (string.IsNullOrEmpty(ImageNameValue))
ImageNameValue = "track";
if (string.IsNullOrEmpty((_inputs[FlagStrings.ImageName] as StringInput)?.Value))
(_inputs[FlagStrings.ImageName] as StringInput)?.SetValue("track");
return true;
}

View File

@@ -5,7 +5,8 @@ namespace MPF.ExecutionContexts.Redumper
/// </summary>
public static class FlagStrings
{
// General
#region General
public const string HelpLong = "--help";
public const string HelpShort = "-h";
public const string Version = "--version";
@@ -19,7 +20,10 @@ namespace MPF.ExecutionContexts.Redumper
public const string ImageName = "--image-name";
public const string Overwrite = "--overwrite";
// Drive Configuration
#endregion
#region Drive Configuration
public const string DriveType = "--drive-type";
public const string DriveReadOffset = "--drive-read-offset";
public const string DriveC2Shift = "--drive-c2-shift";
@@ -27,25 +31,37 @@ namespace MPF.ExecutionContexts.Redumper
public const string DriveReadMethod = "--drive-read-method";
public const string DriveSectorOrder = "--drive-sector-order";
// Drive Specific
#endregion
#region Drive Specific
public const string PlextorSkipLeadin = "--plextor-skip-leadin";
public const string PlextorLeadinRetries = "--plextor-leadin-retries";
public const string AsusSkipLeadout = "--asus-skip-leadout";
// Offset
#endregion
#region Offset
public const string ForceOffset = "--force-offset";
public const string AudioSilenceThreshold = "--audio-silence-threshold";
public const string CorrectOffsetShift = "--correct-offset-shift";
public const string OffsetShiftRelocate = "--offset-shift-relocate";
// Split
#endregion
#region Split
public const string ForceSplit = "--force-split";
public const string LeaveUnchanged = "--leave-unchanged";
public const string ForceQTOC = "--force-qtoc";
public const string SkipFill = "--skip-fill";
public const string ISO9660Trim = "--iso9660-trim";
// Miscellaneous
#endregion
#region Miscellaneous
public const string LBAStart = "--lba-start";
public const string LBAEnd = "--lba-end";
public const string RefineSubchannel = "--refine-subchannel";
@@ -56,5 +72,7 @@ namespace MPF.ExecutionContexts.Redumper
public const string ForceUnscrambled = "--force-unscrambled";
public const string LegacySubs = "--legacy-subs";
public const string DisableCDText = "--disable-cdtext";
#endregion
}
}

View File

@@ -1,14 +1,13 @@
using System;
using System.Collections.Generic;
using System.IO;
using MPF.Frontend;
using Xunit;
namespace MPF.Test.Frontend
namespace MPF.Frontend.Test
{
public class EnumConverterTests
public class DriveTests
{
#region Cross-enumeration conversions
#region ToInternalDriveType
/// <summary>
/// DiscType values that map to InternalDriveType
@@ -56,40 +55,5 @@ namespace MPF.Test.Frontend
}
#endregion
#region Convert to Long Name
// TODO: Maybe add a test for the generic "GetLongName" method
/// <summary>
/// Check that every InternalProgram has a long name provided
/// </summary>
/// <param name="internalProgram">InternalProgram value to check</param>
[Theory]
[MemberData(nameof(GenerateInternalProgramTestData))]
public void InternalProgramLongNameTest(InternalProgram? internalProgram)
{
string actual = internalProgram.LongName();
Assert.NotNull(actual);
}
/// <summary>
/// Generate a test set of InternalProgram values
/// </summary>
/// <returns>MemberData-compatible list of InternalProgram values</returns>
public static List<object?[]> GenerateInternalProgramTestData()
{
var testData = new List<object?[]>() { new object?[] { null } };
foreach (InternalProgram? internalProgram in Enum.GetValues(typeof(InternalProgram)))
{
testData.Add([internalProgram]);
}
return testData;
}
#endregion
// TODO: Add from-string tests
}
}

View File

@@ -1,8 +1,7 @@
using MPF.Frontend;
using SabreTools.RedumpLib.Data;
using SabreTools.RedumpLib.Data;
using Xunit;
namespace MPF.Test.Frontend
namespace MPF.Frontend.Test
{
public class DumpEnvironmentTests
{

View File

@@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SabreTools.RedumpLib.Data;
using Xunit;
using RedumperReadMethod = MPF.ExecutionContexts.Redumper.ReadMethod;
using RedumperSectorOrder = MPF.ExecutionContexts.Redumper.SectorOrder;
namespace MPF.Frontend.Test
{
public class EnumExtensionsTests
{
#region Long Name
[Theory]
[InlineData(null, "Unknown")]
[InlineData(InternalProgram.NONE, "Unknown")]
[InlineData(InternalProgram.Aaru, "Aaru")]
[InlineData(InternalProgram.DiscImageCreator, "DiscImageCreator")]
[InlineData(InternalProgram.Redumper, "Redumper")]
[InlineData(InternalProgram.CleanRip, "CleanRip")]
[InlineData(InternalProgram.PS3CFW, "PS3 CFW")]
[InlineData(InternalProgram.UmdImageCreator, "UmdImageCreator")]
[InlineData(InternalProgram.XboxBackupCreator, "XboxBackupCreator")]
public void LongName_InternalProgram(InternalProgram? prog, string? expected)
{
string? actual = prog.LongName();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(null, "Unknown")]
[InlineData(RedumperReadMethod.NONE, "Default")]
[InlineData(RedumperReadMethod.D8, "D8")]
[InlineData(RedumperReadMethod.BE, "BE")]
[InlineData(RedumperReadMethod.BE_CDDA, "BE_CDDA")]
public void LongName_RedumperReadMethod(RedumperReadMethod? method, string? expected)
{
string? actual = method.LongName();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(null, "Unknown")]
[InlineData(RedumperSectorOrder.NONE, "Default")]
[InlineData(RedumperSectorOrder.DATA_C2_SUB, "DATA_C2_SUB")]
[InlineData(RedumperSectorOrder.DATA_SUB_C2, "DATA_SUB_C2")]
[InlineData(RedumperSectorOrder.DATA_SUB, "DATA_SUB")]
[InlineData(RedumperSectorOrder.DATA_C2, "DATA_C2")]
public void LongName_RedumperSectorOrder(RedumperSectorOrder? order, string? expected)
{
string? actual = order.LongName();
Assert.Equal(expected, actual);
}
#endregion
#region Short Name
[Theory]
[InlineData(null, "Unknown")]
[InlineData(InternalProgram.NONE, "Unknown")]
[InlineData(InternalProgram.Aaru, "aaru")]
[InlineData(InternalProgram.DiscImageCreator, "dic")]
[InlineData(InternalProgram.Redumper, "redumper")]
[InlineData(InternalProgram.CleanRip, "cleanrip")]
[InlineData(InternalProgram.PS3CFW, "ps3cfw")]
[InlineData(InternalProgram.UmdImageCreator, "uic")]
[InlineData(InternalProgram.XboxBackupCreator, "xbc")]
public void ShortName_InternalProgram(InternalProgram? prog, string? expected)
{
string? actual = prog.ShortName();
Assert.Equal(expected, actual);
}
#endregion
#region From String
[Theory]
[InlineData(null, InternalProgram.NONE)]
[InlineData("", InternalProgram.NONE)]
[InlineData("aaru", InternalProgram.Aaru)]
[InlineData("dic", InternalProgram.DiscImageCreator)]
[InlineData("redumper", InternalProgram.Redumper)]
[InlineData("cleanrip", InternalProgram.CleanRip)]
[InlineData("ps3cfw", InternalProgram.PS3CFW)]
[InlineData("uic", InternalProgram.UmdImageCreator)]
[InlineData("xbc", InternalProgram.XboxBackupCreator)]
public void ToInternalProgramTest(string? internalProgram, InternalProgram expected)
{
InternalProgram actual = internalProgram.ToInternalProgram();
Assert.Equal(expected, actual);
}
// TODO: Write remaining from-string tests
#endregion
#region Functionality Support
private static readonly RedumpSystem?[] _antiModchipSystems =
[
RedumpSystem.SonyPlayStation,
];
private static readonly RedumpSystem?[] _copyProtectionSystems =
[
RedumpSystem.AppleMacintosh,
RedumpSystem.EnhancedCD ,
RedumpSystem.IBMPCcompatible,
RedumpSystem.PalmOS,
RedumpSystem.PocketPC,
RedumpSystem.RainbowDisc,
RedumpSystem.SonyElectronicBook,
];
[Theory]
[MemberData(nameof(GenerateSupportsAntiModchipScansData))]
public void SupportsAntiModchipScansTest(RedumpSystem? redumpSystem, bool expected)
{
bool actual = redumpSystem.SupportsAntiModchipScans();
Assert.Equal(expected, actual);
}
[Theory]
[MemberData(nameof(GenerateSupportsCopyProtectionScansData))]
public void SupportsCopyProtectionScansTest(RedumpSystem? redumpSystem, bool expected)
{
bool actual = redumpSystem.SupportsCopyProtectionScans();
Assert.Equal(expected, actual);
}
public static List<object?[]> GenerateSupportsAntiModchipScansData()
{
var testData = new List<object?[]>() { new object?[] { null, false } };
foreach (RedumpSystem redumpSystem in Enum.GetValues(typeof(RedumpSystem)))
{
if (_antiModchipSystems.Contains(redumpSystem))
testData.Add([redumpSystem, true]);
else
testData.Add([redumpSystem, false]);
}
return testData;
}
public static List<object?[]> GenerateSupportsCopyProtectionScansData()
{
var testData = new List<object?[]>() { new object?[] { null, false } };
foreach (RedumpSystem redumpSystem in Enum.GetValues(typeof(RedumpSystem)))
{
if (_copyProtectionSystems.Contains(redumpSystem))
testData.Add([redumpSystem, true]);
else
testData.Add([redumpSystem, false]);
}
return testData;
}
#endregion
}
}

View File

@@ -1,15 +1,18 @@
using MPF.Frontend;
using SabreTools.RedumpLib.Data;
using SabreTools.RedumpLib.Data;
using Xunit;
namespace MPF.Test.Frontend
namespace MPF.Frontend.Test
{
public class UIElementsTest
public class InterfaceConstantsTests
{
[Theory]
[InlineData(MediaType.CDROM, 72)]
[InlineData(MediaType.DVD, 24)]
[InlineData(MediaType.NintendoGameCubeGameDisc, 24)]
[InlineData(MediaType.NintendoWiiOpticalDisc, 24)]
[InlineData(MediaType.HDDVD, 24)]
[InlineData(MediaType.BluRay, 16)]
[InlineData(MediaType.NintendoWiiUOpticalDisc, 16)]
[InlineData(MediaType.LaserDisc, 1)]
[InlineData(null, 1)]
public void GetAllowedDriveSpeedForMediaTypeTest(MediaType? mediaType, int maxExpected)

View File

@@ -0,0 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0;net9.0</TargetFrameworks>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MPF.Frontend\MPF.Frontend.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeCoverage" Version="17.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.4" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
<PackageReference Include="xunit.analyzers" Version="1.18.0" />
<PackageReference Include="xunit.assert" Version="2.9.2" />
<PackageReference Include="xunit.core" Version="2.9.2" />
<PackageReference Include="xunit.extensibility.core" Version="2.9.2" />
<PackageReference Include="xunit.extensibility.execution" Version="2.9.2" />
<PackageReference Include="xunit.runner.console" Version="2.9.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,47 @@
using System.Collections.Generic;
using Xunit;
namespace MPF.Frontend.Test
{
public class OptionsTests
{
[Theory]
[InlineData("key2", null, "key", false, false)]
[InlineData("key", null, "key", false, false)]
[InlineData("key", "", "key", false, false)]
[InlineData("key", "INVALID", "key", false, false)]
[InlineData("key", "true", "key", false, true)]
public void GetBooleanSettingTest(string key, string? value, string expectedKey, bool defaultValue, bool expectedValue)
{
Dictionary<string, string?> settings = new() { [key] = value };
bool actual = Options.GetBooleanSetting(settings, expectedKey, defaultValue);
Assert.Equal(expectedValue, actual);
}
[Theory]
[InlineData("key2", null, "key", -1, -1)]
[InlineData("key", null, "key", -1, -1)]
[InlineData("key", "", "key", -1, -1)]
[InlineData("key", "INVALID", "key", -1, -1)]
[InlineData("key", "12345", "key", -1, 12345)]
public void GetInt32SettingTest(string key, string? value, string expectedKey, int defaultValue, int expectedValue)
{
Dictionary<string, string?> settings = new() { [key] = value };
int actual = Options.GetInt32Setting(settings, expectedKey, defaultValue);
Assert.Equal(expectedValue, actual);
}
[Theory]
[InlineData("key2", null, "key", null, null)]
[InlineData("key", null, "key", null, null)]
[InlineData("key", "", "key", null, "")]
[InlineData("key", "INVALID", "key", null, "INVALID")]
[InlineData("key", "String", "key", null, "String")]
public void GetStringSettingTest(string key, string? value, string expectedKey, string? defaultValue, string? expectedValue)
{
Dictionary<string, string?> settings = new() { [key] = value };
string? actual = Options.GetStringSetting(settings, expectedKey, defaultValue);
Assert.Equal(expectedValue, actual);
}
}
}

View File

@@ -1,7 +1,6 @@
using MPF.Frontend;
using Xunit;
using Xunit;
namespace MPF.Test.Frontend
namespace MPF.Frontend.Test
{
public class ResultEventArgsTests
{

View File

@@ -0,0 +1,98 @@
using System.IO;
using MPF.Frontend.Tools;
using SabreTools.RedumpLib.Data;
using Xunit;
namespace MPF.Frontend.Test.Tools
{
public class FrontendToolTests
{
#region GetDefaultSpeedForMediaType
[Theory]
[InlineData(null, 72)]
[InlineData(MediaType.CDROM, 72)]
[InlineData(MediaType.GDROM, 72)]
[InlineData(MediaType.DVD, 24)]
[InlineData(MediaType.NintendoGameCubeGameDisc, 24)]
[InlineData(MediaType.NintendoWiiOpticalDisc, 24)]
[InlineData(MediaType.HDDVD, 24)]
[InlineData(MediaType.BluRay, 16)]
[InlineData(MediaType.NintendoWiiUOpticalDisc, 16)]
public void GetDefaultSpeedForMediaTypeTest(MediaType? mediaType, int expected)
{
Options options = new Options
{
PreferredDumpSpeedCD = 72,
PreferredDumpSpeedDVD = 24,
PreferredDumpSpeedHDDVD = 24,
PreferredDumpSpeedBD = 16,
};
int actual = FrontendTool.GetDefaultSpeedForMediaType(mediaType, options);
Assert.Equal(expected, actual);
}
#endregion
#region GetRedumpSystemFromVolumeLabel
[Theory]
[InlineData(null, null)]
[InlineData("", null)]
[InlineData("Audio CD", RedumpSystem.AudioCD)]
[InlineData("SEP13011042", RedumpSystem.MicrosoftXbox)]
[InlineData("SEP13011042072", RedumpSystem.MicrosoftXbox)]
[InlineData("XBOX360", RedumpSystem.MicrosoftXbox360)]
[InlineData("XGD2DVD_NTSC", RedumpSystem.MicrosoftXbox360)]
[InlineData("Sega_CD", RedumpSystem.SegaMegaCDSegaCD)]
[InlineData("PS3VOLUME", RedumpSystem.SonyPlayStation3)]
[InlineData("PS4VOLUME", RedumpSystem.SonyPlayStation4)]
[InlineData("PS5VOLUME", RedumpSystem.SonyPlayStation5)]
public void GetRedumpSystemFromVolumeLabelTest(string? volumeLabel, RedumpSystem? expected)
{
RedumpSystem? actual = FrontendTool.GetRedumpSystemFromVolumeLabel(volumeLabel);
Assert.Equal(expected, actual);
}
#endregion
#region NormalizeDiscTitle
// TODO: Write NormalizeDiscTitle(string?, Language?[]?) test
// TODO: Write NormalizeDiscTitle(string?, Language?) test
#endregion
#region NormalizeOutputPaths
[Theory]
[InlineData(null, false, "")]
[InlineData(null, true, "")]
[InlineData("", false, "")]
[InlineData("", true, "")]
[InlineData("filename.bin", false, "filename.bin")]
[InlineData("filename.bin", true, "filename.bin")]
[InlineData("\"filename.bin\"", false, "filename.bin")]
[InlineData("\"filename.bin\"", true, "filename.bin")]
[InlineData("<filename.bin>", false, "filename.bin")]
[InlineData("<filename.bin>", true, "filename.bin")]
[InlineData("1.2.3.4..bin", false, "1.2.3.4..bin")]
[InlineData("1.2.3.4..bin", true, "1.2.3.4..bin")]
[InlineData("dir/filename.bin", false, "dir/filename.bin")]
[InlineData("dir/filename.bin", true, "dir/filename.bin")]
[InlineData("\0dir/\0filename.bin", false, "_dir/_filename.bin")]
[InlineData("\0dir/\0filename.bin", true, "_dir/_filename.bin")]
public void NormalizeOutputPathsTest(string? path, bool getFullPath, string expected)
{
// Modify expected to account for test data if necessary
if (getFullPath && !string.IsNullOrEmpty(expected))
expected = Path.GetFullPath(expected);
string actual = FrontendTool.NormalizeOutputPaths(path, getFullPath);
Assert.Equal(expected, actual);
}
#endregion
}
}

View File

@@ -5,7 +5,7 @@ using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;
using Xunit;
namespace MPF.Test.Frontend.Tools
namespace MPF.Frontend.Test.Tools
{
public class InfoToolTests
{
@@ -64,7 +64,7 @@ namespace MPF.Test.Frontend.Tools
// Validate the lines
Assert.Equal(3, splitComments.Length);
Assert.Equal(5, splitContents.Length);
Assert.Equal(4, splitContents.Length);
}
[Fact]

View File

@@ -0,0 +1,673 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MPF.Frontend.Tools;
using Xunit;
namespace MPF.Frontend.Test.Tools
{
public class ProtectionToolTests
{
[Fact]
public void SanitizeFoundProtections_Exception()
{
List<string> protections =
[
"Anything Else Protection",
"[Exception opening file",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Equal("Anything Else Protection, Exception occurred while scanning [RESCAN NEEDED]", sanitized);
}
#region Game Engine
[Fact]
public void SanitizeFoundProtections_RenderWare()
{
List<string> protections =
[
"RenderWare",
"RenderWare ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
#endregion
#region Packers
[Fact]
public void SanitizeFoundProtections_dotNetReactor()
{
List<string> protections =
[
".NET Reactor",
".NET Reactor ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_SevenZipSFX()
{
List<string> protections =
[
"7-Zip SFX",
"7-Zip SFX ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_ASPack()
{
List<string> protections =
[
"ASPack",
"ASPack ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_AutoPlayMediaStudio()
{
List<string> protections =
[
"AutoPlay Media Studio",
"AutoPlay Media Studio ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_CaphyonAdvancedInstaller()
{
List<string> protections =
[
"Caphyon Advanced Installer",
"Caphyon Advanced Installer ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_CExe()
{
List<string> protections =
[
"CExe",
"CExe ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_dotFuscator()
{
List<string> protections =
[
"dotFuscator",
"dotFuscator ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_EmbeddedArchive()
{
List<string> protections =
[
"Embedded 7-zip Archive",
"Embedded PKZIP Archive",
"Embedded RAR Archive",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_EmbeddedExecutable()
{
List<string> protections =
[
"Embedded Executable",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_EXEStealth()
{
List<string> protections =
[
"EXE Stealth",
"EXE Stealth ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_GenteeInstaller()
{
List<string> protections =
[
"Gentee Installer",
"Gentee Installer ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_HyperTechCrackProof()
{
List<string> protections =
[
"HyperTech CrackProof",
"HyperTech CrackProof ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_InnoSetup()
{
List<string> protections =
[
"Inno Setup",
"Inno Setup ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_InstallAnywhere()
{
List<string> protections =
[
"InstallAnywhere",
"InstallAnywhere ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_InstallerVISE()
{
List<string> protections =
[
"Installer VISE",
"Installer VISE ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_IntelInstallationFramework()
{
List<string> protections =
[
"Intel Installation Framework",
"Intel Installation Framework ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_MicrosoftCABSFX()
{
List<string> protections =
[
"Microsoft CAB SFX",
"Microsoft CAB SFX ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_NeoLite()
{
List<string> protections =
[
"NeoLite",
"NeoLite ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_NSIS()
{
List<string> protections =
[
"NSIS",
"NSIS ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_PECompact()
{
List<string> protections =
[
"PE Compact",
"PE Compact ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_PEtite()
{
List<string> protections =
[
"PEtite",
"PEtite ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_SetupFactory()
{
List<string> protections =
[
"Setup Factory",
"Setup Factory ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_Shrinker()
{
List<string> protections =
[
"Shrinker",
"Shrinker ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_UPX()
{
List<string> protections =
[
"UPX",
"UPX ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_WinRARSFX()
{
List<string> protections =
[
"WinRAR SFX",
"WinRAR SFX ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_WinZipSFX()
{
List<string> protections =
[
"WinZip SFX",
"WinZip SFX ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_WiseInstaller()
{
List<string> protections =
[
"Wise Installation",
"Wise Installation ANYTHING",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
#endregion
#region Protections
[Fact]
public void SanitizeFoundProtections_ActiveMARK()
{
List<string> protections =
[
"ActiveMARK",
"ActiveMARK 5",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Equal("ActiveMARK 5", sanitized);
}
[Fact]
public void SanitizeFoundProtections_CactusDataShield()
{
List<string> protections =
[
"Cactus Data Shield 200",
"Cactus Data Shield 200 (Build 3.0.100a)",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Equal("Cactus Data Shield 200 (Build 3.0.100a)", sanitized);
}
[Fact]
public void SanitizeFoundProtections_CactusDataShieldMacrovision()
{
List<string> protections =
[
"Anything Else Protection",
"Cactus Data Shield 300 (Confirm presence of other CDS-300 files)",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Equal("Anything Else Protection, Cactus Data Shield 300", sanitized);
}
[Fact]
public void SanitizeFoundProtections_CDCheck()
{
List<string> protections =
[
"Anything Else Protection",
"Executable-Based CD Check",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Equal("Anything Else Protection", sanitized);
}
[Fact]
public void SanitizeFoundProtections_CDCops()
{
List<string> protections =
[
"CD-Cops",
"CD-Cops v1.2.0",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Equal("CD-Cops v1.2.0", sanitized);
}
[Fact]
public void SanitizeFoundProtections_CDKey()
{
List<string> protections =
[
"Anything Else Protection",
"CD-Key / Serial",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Equal("Anything Else Protection", sanitized);
}
[Fact]
public void SanitizeFoundProtections_EACdKey()
{
List<string> protections =
[
"EA CdKey Registration Module",
"EA CdKey Registration Module v1.2.0",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Empty(sanitized);
}
[Fact]
public void SanitizeFoundProtections_EADRM()
{
List<string> protections =
[
"EA DRM Protection",
"EA DRM Protection v1.2.0",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Equal("EA DRM Protection v1.2.0", sanitized);
}
[Fact]
public void SanitizeFoundProtections_GFWL()
{
List<string> protections =
[
"Games for Windows LIVE",
"Games for Windows LIVE v1.2.0",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Equal("Games for Windows LIVE v1.2.0", sanitized);
}
[Fact]
public void SanitizeFoundProtections_GFWLZDPP()
{
List<string> protections =
[
"Games for Windows LIVE",
"Games for Windows LIVE Zero Day Piracy Protection",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Equal("Games for Windows LIVE, Games for Windows LIVE Zero Day Piracy Protection", sanitized);
}
[Fact]
public void SanitizeFoundProtections_ImpulseReactor()
{
List<string> protections =
[
"Impulse Reactor",
"Impulse Reactor Core Module v1.2.0",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Equal("Impulse Reactor Core Module v1.2.0", sanitized);
}
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
public void SanitizeFoundProtections_JoWoodXProtTest(int skip)
{
List<string> protections =
[
"JoWood X-Prot 1.2.0.00",
"JoWood X-Prot v2",
"JoWood X-Prot v1.4+",
"JoWood X-Prot v1.0-v1.3",
"JoWood X-Prot",
];
// Safeguard for the future
if (skip >= protections.Count)
throw new ArgumentException("Invalid skip value", nameof(skip));
// The list is in order of preference
protections = protections.Skip(skip).ToList();
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Equal(protections[0], sanitized);
}
[Fact]
public void SanitizeFoundProtections_OnlineRegistration()
{
List<string> protections =
[
"Anything Else Protection",
"Executable-Based Online Registration",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Equal("Anything Else Protection", sanitized);
}
[Theory]
[InlineData(0, "Macrovision Protected Application [SafeDisc 0.00.000], SafeDisc 0.00.000, SafeDisc Lite")]
[InlineData(1, "Macrovision Protected Application [SafeDisc 0.00.000 / SRV Tool APP], SafeDisc 0.00.000, SafeDisc Lite")]
[InlineData(2, "Macrovision Security Driver, Macrovision Security Driver [SafeDisc 1.11.111], SafeDisc 0.00.000, SafeDisc 0.00.000-1.11.111, SafeDisc Lite")]
[InlineData(3, "Macrovision Security Driver, Macrovision Security Driver [SafeDisc 1.11.111], SafeDisc 0.00.000, SafeDisc Lite")]
[InlineData(4, "Macrovision Security Driver, Macrovision Security Driver [SafeDisc 1.11.111], SafeDisc Lite")]
[InlineData(5, "Macrovision Security Driver, SafeDisc Lite")]
[InlineData(6, "Macrovision Protection File, SafeDisc 2+, SafeDisc 3+ (DVD), SafeDisc Lite")]
[InlineData(7, "SafeDisc 3+ (DVD)")]
[InlineData(8, "SafeDisc 2+")]
public void SanitizeFoundProtections_SafeDisc(int skip, string expected)
{
List<string> protections =
[
"Macrovision Protected Application [SafeDisc 0.00.000]",
"Macrovision Protected Application [SafeDisc 0.00.000 / SRV Tool APP]",
"SafeDisc 0.00.000-1.11.111",
"SafeDisc 0.00.000",
"Macrovision Security Driver [SafeDisc 1.11.111]",
"Macrovision Security Driver",
"SafeDisc Lite",
"SafeDisc 3+ (DVD)",
"SafeDisc 2+",
"Macrovision Protection File",
];
// Safeguard for the future
if (skip >= protections.Count)
throw new ArgumentException("Invalid skip value", nameof(skip));
// The list is in order of preference
protections = protections.Skip(skip).ToList();
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Equal(expected, sanitized);
}
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
public void SanitizeFoundProtections_StarForce(int skip)
{
List<string> protections =
[
"StarForce 1.20.000.000",
"StarForce 5 [Protected Module]",
"StarForce 5",
"StarForce 3-5",
"StarForce",
];
// Safeguard for the future
if (skip >= protections.Count)
throw new ArgumentException("Invalid skip value", nameof(skip));
// The list is in order of preference
protections = protections.Skip(skip).ToList();
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Equal(protections[0], sanitized);
}
[Fact]
public void SanitizeFoundProtections_Sysiphus()
{
List<string> protections =
[
"Sysiphus",
"Sysiphus v1.2.0",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Equal("Sysiphus v1.2.0", sanitized);
}
[Fact]
public void SanitizeFoundProtections_XCP()
{
List<string> protections =
[
"XCP",
"XCP v1.2.0",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Equal("XCP v1.2.0", sanitized);
}
#endregion
}
}

View File

@@ -1,8 +1,7 @@
using System;
using BinaryObjectScanner;
using MPF.Frontend;
namespace MPF.CLI
namespace MPF.Frontend
{
public static class ConsoleLogger
{

View File

@@ -3,9 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Text;
#if NET40
using System.Threading;
#endif
using System.Threading.Tasks;
using BinaryObjectScanner;
using MPF.ExecutionContexts;
@@ -52,7 +49,7 @@ namespace MPF.Frontend
/// <summary>
/// Options object representing user-defined options
/// </summary>
private readonly Frontend.Options _options;
private readonly Options _options;
/// <summary>
/// Processor object representing how to process the outputs
@@ -120,7 +117,7 @@ namespace MPF.Frontend
/// <param name="type"></param>
/// <param name="internalProgram"></param>
/// <param name="parameters"></param>
public DumpEnvironment(Frontend.Options options,
public DumpEnvironment(Options options,
string? outputPath,
Drive? drive,
RedumpSystem? system,
@@ -154,12 +151,12 @@ namespace MPF.Frontend
{
// If a complete dump exists from a different program
InternalProgram? programFound = null;
if (programFound == null && _internalProgram != InternalProgram.Aaru)
if (programFound == null && _internalProgram != InternalProgram.Redumper)
{
var processor = new Processors.Aaru(_system, _type);
var processor = new Processors.Redumper(_system, _type);
var missingFiles = processor.FoundAllFiles(outputDirectory, outputFilename);
if (missingFiles.Count == 0)
programFound = InternalProgram.Aaru;
programFound = InternalProgram.Redumper;
}
if (programFound == null && _internalProgram != InternalProgram.DiscImageCreator)
{
@@ -168,13 +165,42 @@ namespace MPF.Frontend
if (missingFiles.Count == 0)
programFound = InternalProgram.DiscImageCreator;
}
if (programFound == null && _internalProgram != InternalProgram.Aaru)
{
var processor = new Processors.Aaru(_system, _type);
var missingFiles = processor.FoundAllFiles(outputDirectory, outputFilename);
if (missingFiles.Count == 0)
programFound = InternalProgram.Aaru;
}
return programFound;
}
/// <summary>
/// Check output path for partial logs from all dumping programs
/// </summary>
public InternalProgram? CheckForPartialProgram(string? outputDirectory, string outputFilename)
{
// If a complete dump exists from a different program
InternalProgram? programFound = null;
if (programFound == null && _internalProgram != InternalProgram.Redumper)
{
var processor = new Processors.Redumper(_system, _type);
var missingFiles = processor.FoundAllFiles(outputDirectory, outputFilename);
if (missingFiles.Count == 0)
if (processor.FoundAnyFiles(outputDirectory, outputFilename))
programFound = InternalProgram.Redumper;
}
if (programFound == null && _internalProgram != InternalProgram.DiscImageCreator)
{
var processor = new Processors.DiscImageCreator(_system, _type);
if (processor.FoundAnyFiles(outputDirectory, outputFilename))
programFound = InternalProgram.DiscImageCreator;
}
if (programFound == null && _internalProgram != InternalProgram.Aaru)
{
var processor = new Processors.Aaru(_system, _type);
if (processor.FoundAnyFiles(outputDirectory, outputFilename))
programFound = InternalProgram.Aaru;
}
return programFound;
}
@@ -288,7 +314,8 @@ namespace MPF.Frontend
or MediaType.HDDVD
or MediaType.BluRay
or MediaType.NintendoGameCubeGameDisc
or MediaType.NintendoWiiOpticalDisc => true,
or MediaType.NintendoWiiOpticalDisc
or MediaType.NintendoWiiUOpticalDisc => true,
_ => false,
};
}
@@ -302,6 +329,15 @@ namespace MPF.Frontend
return _processor.FoundAllFiles(outputDirectory, outputFilename).Count == 0;
}
/// <inheritdoc cref="BaseProcessor.FoundAnyFiles(string?, string)"/>
public bool FoundAnyFiles(string? outputDirectory, string outputFilename)
{
if (_processor == null)
return false;
return _processor.FoundAnyFiles(outputDirectory, outputFilename);
}
/// <inheritdoc cref="BaseExecutionContext.GetDefaultExtension(MediaType?)"/>
public string? GetDefaultExtension(MediaType? mediaType)
{
@@ -346,7 +382,8 @@ namespace MPF.Frontend
// Partially supported types
MediaType.GDROM
or MediaType.NintendoGameCubeGameDisc
or MediaType.NintendoWiiOpticalDisc => ResultEventArgs.Success($"{_type.LongName()} partially supported for dumping"),
or MediaType.NintendoWiiOpticalDisc
or MediaType.NintendoWiiUOpticalDisc => ResultEventArgs.Success($"{_type.LongName()} partially supported for dumping"),
// Special case for other supported tools
MediaType.UMD => ResultEventArgs.Failure($"{_type.LongName()} supported for submission info parsing"),
@@ -390,6 +427,14 @@ namespace MPF.Frontend
if (_executionContext == null)
return ResultEventArgs.Failure("Error! Current configuration is not supported!");
// Build default console progress indicators if none exist
if (progress == null)
{
var temp = new Progress<ResultEventArgs>();
temp.ProgressChanged += ConsoleLogger.ProgressUpdated;
progress = temp;
}
// Check that we have the basics for dumping
ResultEventArgs result = IsValidForDump();
if (!result)
@@ -429,7 +474,21 @@ namespace MPF.Frontend
if (_processor == null)
return ResultEventArgs.Failure("Error! Current configuration is not supported!");
resultProgress?.Report(ResultEventArgs.Success("Gathering submission information... please wait!"));
// Build default console progress indicators if none exist
if (resultProgress == null)
{
var temp = new Progress<ResultEventArgs>();
temp.ProgressChanged += ConsoleLogger.ProgressUpdated;
resultProgress = temp;
}
if (protectionProgress == null)
{
var temp = new Progress<ProtectionProgress>();
temp.ProgressChanged += ConsoleLogger.ProgressUpdated;
protectionProgress = temp;
}
resultProgress.Report(ResultEventArgs.Success("Gathering submission information... please wait!"));
// Get the output directory and filename separately
var outputDirectory = Path.GetDirectoryName(OutputPath);
@@ -439,12 +498,12 @@ namespace MPF.Frontend
List<string> missingFiles = _processor.FoundAllFiles(outputDirectory, outputFilename);
if (missingFiles.Count > 0)
{
resultProgress?.Report(ResultEventArgs.Failure($"There were files missing from the output:\n{string.Join("\n", [.. missingFiles])}"));
resultProgress.Report(ResultEventArgs.Failure($"There were files missing from the output:\n{string.Join("\n", [.. missingFiles])}"));
return ResultEventArgs.Failure("Error! Please check output directory as dump may be incomplete!");
}
// Extract the information from the output files
resultProgress?.Report(ResultEventArgs.Success("Extracting output information from output files..."));
resultProgress.Report(ResultEventArgs.Success("Extracting output information from output files..."));
var submissionInfo = await SubmissionGenerator.ExtractOutputInformation(
OutputPath,
_drive,
@@ -454,126 +513,119 @@ namespace MPF.Frontend
_processor,
resultProgress,
protectionProgress);
resultProgress?.Report(ResultEventArgs.Success("Extracting information complete!"));
resultProgress.Report(ResultEventArgs.Success("Extracting information complete!"));
// Inject seed submission info data, if necessary
if (seedInfo != null)
{
resultProgress?.Report(ResultEventArgs.Success("Injecting user-supplied information..."));
Builder.InjectSubmissionInformation(submissionInfo, seedInfo);
resultProgress?.Report(ResultEventArgs.Success("Information injection complete!"));
resultProgress.Report(ResultEventArgs.Success("Injecting user-supplied information..."));
submissionInfo = Builder.InjectSubmissionInformation(submissionInfo, seedInfo);
resultProgress.Report(ResultEventArgs.Success("Information injection complete!"));
}
// Get user-modifiable information if confugured to
// Get user-modifiable information if configured to
if (_options.PromptForDiscInformation && processUserInfo != null)
{
resultProgress?.Report(ResultEventArgs.Success("Waiting for additional disc information..."));
bool? filledInfo = processUserInfo(ref submissionInfo);
resultProgress.Report(ResultEventArgs.Success("Waiting for additional disc information..."));
bool? filledInfo = processUserInfo.Invoke(_options, ref submissionInfo);
if (filledInfo == true)
resultProgress?.Report(ResultEventArgs.Success("Additional disc information added!"));
resultProgress.Report(ResultEventArgs.Success("Additional disc information added!"));
else
resultProgress?.Report(ResultEventArgs.Success("Disc information skipped!"));
resultProgress.Report(ResultEventArgs.Success("Disc information skipped!"));
}
// Process special fields for site codes
resultProgress?.Report(ResultEventArgs.Success("Processing site codes..."));
Formatter.ProcessSpecialFields(submissionInfo);
resultProgress?.Report(ResultEventArgs.Success("Processing complete!"));
resultProgress.Report(ResultEventArgs.Success("Processing site codes..."));
Formatter.ProcessSpecialFields(submissionInfo!);
resultProgress.Report(ResultEventArgs.Success("Processing complete!"));
// Format the information for the text output
resultProgress?.Report(ResultEventArgs.Success("Formatting information..."));
resultProgress.Report(ResultEventArgs.Success("Formatting information..."));
var formattedValues = Formatter.FormatOutputData(submissionInfo, _options.EnableRedumpCompatibility, out string? formatResult);
if (formattedValues == null)
resultProgress?.Report(ResultEventArgs.Failure(formatResult));
resultProgress.Report(ResultEventArgs.Failure(formatResult));
else
resultProgress?.Report(ResultEventArgs.Success(formatResult));
resultProgress.Report(ResultEventArgs.Success(formatResult));
// Get the filename suffix for auto-generated files
var filenameSuffix = _options.AddFilenameSuffix ? Path.GetFileNameWithoutExtension(outputFilename) : null;
// Write the text output
resultProgress?.Report(ResultEventArgs.Success("Writing submission information file..."));
resultProgress.Report(ResultEventArgs.Success("Writing submission information file..."));
bool txtSuccess = WriteOutputData(outputDirectory, filenameSuffix, formattedValues, out string txtResult);
if (txtSuccess)
resultProgress?.Report(ResultEventArgs.Success(txtResult));
resultProgress.Report(ResultEventArgs.Success(txtResult));
else
resultProgress?.Report(ResultEventArgs.Failure(txtResult));
resultProgress.Report(ResultEventArgs.Failure(txtResult));
// Write the copy protection output
if (submissionInfo?.CopyProtection?.FullProtections != null && submissionInfo.CopyProtection.FullProtections.Count > 0)
{
if (_options.ScanForProtection)
{
resultProgress?.Report(ResultEventArgs.Success("Writing protection information file..."));
resultProgress.Report(ResultEventArgs.Success("Writing protection information file..."));
bool scanSuccess = WriteProtectionData(outputDirectory, filenameSuffix, submissionInfo, _options.HideDriveLetters);
if (scanSuccess)
resultProgress?.Report(ResultEventArgs.Success("Writing complete!"));
resultProgress.Report(ResultEventArgs.Success("Writing complete!"));
else
resultProgress?.Report(ResultEventArgs.Failure("Writing could not complete!"));
resultProgress.Report(ResultEventArgs.Failure("Writing could not complete!"));
}
}
// Write the JSON output, if required
if (_options.OutputSubmissionJSON)
{
resultProgress?.Report(ResultEventArgs.Success($"Writing submission information JSON file{(_options.IncludeArtifacts ? " with artifacts" : string.Empty)}..."));
resultProgress.Report(ResultEventArgs.Success($"Writing submission information JSON file{(_options.IncludeArtifacts ? " with artifacts" : string.Empty)}..."));
bool jsonSuccess = WriteOutputData(outputDirectory, filenameSuffix, submissionInfo, _options.IncludeArtifacts);
if (jsonSuccess)
resultProgress?.Report(ResultEventArgs.Success("Writing complete!"));
resultProgress.Report(ResultEventArgs.Success("Writing complete!"));
else
resultProgress?.Report(ResultEventArgs.Failure("Writing could not complete!"));
resultProgress.Report(ResultEventArgs.Failure("Writing could not complete!"));
}
// Compress the logs, if required
if (_options.CompressLogFiles)
{
resultProgress?.Report(ResultEventArgs.Success("Compressing log files..."));
if (_processor == null)
resultProgress.Report(ResultEventArgs.Success("Compressing log files..."));
#if NET40
await Task.Factory.StartNew(() =>
#else
await Task.Run(() =>
#endif
{
resultProgress?.Report(ResultEventArgs.Failure("No processor provided!"));
}
else
{
bool compressSuccess = _processor.CompressLogFiles(outputDirectory, filenameSuffix, outputFilename, out string compressResult);
bool compressSuccess = _processor.CompressLogFiles(outputDirectory, outputFilename, filenameSuffix, out string compressResult);
if (compressSuccess)
resultProgress?.Report(ResultEventArgs.Success(compressResult));
resultProgress.Report(ResultEventArgs.Success(compressResult));
else
resultProgress?.Report(ResultEventArgs.Failure(compressResult));
}
resultProgress.Report(ResultEventArgs.Failure(compressResult));
return compressSuccess;
});
}
// Delete unnecessary files, if required
if (_options.DeleteUnnecessaryFiles)
{
resultProgress?.Report(ResultEventArgs.Success("Deleting unnecessary files..."));
if (_processor == null)
{
resultProgress?.Report(ResultEventArgs.Failure("No processor provided!"));
}
resultProgress.Report(ResultEventArgs.Success("Deleting unnecessary files..."));
bool deleteSuccess = _processor.DeleteUnnecessaryFiles(outputDirectory, outputFilename, out string deleteResult);
if (deleteSuccess)
resultProgress.Report(ResultEventArgs.Success(deleteResult));
else
{
bool deleteSuccess = _processor.DeleteUnnecessaryFiles(outputDirectory, outputFilename, out string deleteResult);
if (deleteSuccess)
resultProgress?.Report(ResultEventArgs.Success(deleteResult));
else
resultProgress?.Report(ResultEventArgs.Failure(deleteResult));
}
resultProgress.Report(ResultEventArgs.Failure(deleteResult));
}
// Create PS3 IRD, if required
if (_options.CreateIRDAfterDumping && _system == RedumpSystem.SonyPlayStation3 && _type == MediaType.BluRay)
{
resultProgress?.Report(ResultEventArgs.Success("Creating IRD... please wait!"));
resultProgress.Report(ResultEventArgs.Success("Creating IRD... please wait!"));
bool deleteSuccess = await WriteIRD(OutputPath, submissionInfo?.Extras?.DiscKey, submissionInfo?.Extras?.DiscID, submissionInfo?.Extras?.PIC, submissionInfo?.SizeAndChecksums?.Layerbreak, submissionInfo?.SizeAndChecksums?.CRC32);
if (deleteSuccess)
resultProgress?.Report(ResultEventArgs.Success("IRD created!"));
resultProgress.Report(ResultEventArgs.Success("IRD created!"));
else
resultProgress?.Report(ResultEventArgs.Failure("Failed to create IRD"));
resultProgress.Report(ResultEventArgs.Failure("Failed to create IRD"));
}
resultProgress?.Report(ResultEventArgs.Success("Submission information process complete!"));
resultProgress.Report(ResultEventArgs.Success("Submission information process complete!"));
return ResultEventArgs.Success();
}
@@ -634,11 +686,11 @@ namespace MPF.Frontend
/// <summary>
/// Write the data to the output folder
/// </summary>
/// <param name="outputDirectory">Output folder to write to</param>
/// <param name="outputDirectory">Output folder to use as the base path</param>
/// <param name="filenameSuffix">Optional suffix to append to the filename</param>
/// <param name="lines">Preformatted list of lines to write out to the file</param>
/// <param name="lines">Preformatted string of lines to write out to the file</param>
/// <returns>True on success, false on error</returns>
private static bool WriteOutputData(string? outputDirectory, string? filenameSuffix, List<string>? lines, out string status)
private static bool WriteOutputData(string? outputDirectory, string? filenameSuffix, string? lines, out string status)
{
// Check to see if the inputs are valid
if (lines == null)
@@ -662,10 +714,7 @@ namespace MPF.Frontend
path = Path.Combine(outputDirectory, $"!submissionInfo_{filenameSuffix}.txt");
using var sw = new StreamWriter(File.Open(path, FileMode.Create, FileAccess.Write), Encoding.UTF8);
foreach (string line in lines)
{
sw.WriteLine(line);
}
sw.Write(lines);
}
catch (Exception ex)
{
@@ -681,7 +730,7 @@ namespace MPF.Frontend
/// <summary>
/// Write the data to the output folder
/// </summary>
/// <param name="outputDirectory">Output folder to write to</param>
/// <param name="outputDirectory">Output folder to use as the base path</param>
/// <param name="filenameSuffix">Optional suffix to append to the filename</param>
/// <param name="info">SubmissionInfo object representing the JSON to write out to the file</param>
/// <param name="includedArtifacts">True if artifacts were included, false otherwise</param>
@@ -735,7 +784,7 @@ namespace MPF.Frontend
}
catch
{
// We don't care what the error is right now
// We don't care what the error is
return false;
}
@@ -746,7 +795,7 @@ namespace MPF.Frontend
/// <summary>
/// Write the protection data to the output folder
/// </summary>
/// <param name="outputDirectory">Output folder to write to</param>
/// <param name="outputDirectory">Output folder to use as the base path</param>
/// <param name="filenameSuffix">Optional suffix to append to the filename</param>
/// <param name="info">SubmissionInfo object containing the protection information</param>
/// <param name="hideDriveLetters">True if drive letters are to be removed from output, false otherwise</param>
@@ -791,7 +840,7 @@ namespace MPF.Frontend
}
catch
{
// We don't care what the error is right now
// We don't care what the error is
return false;
}
@@ -801,7 +850,7 @@ namespace MPF.Frontend
/// <summary>
/// Create an IRD and write it to the specified output directory with optional filename suffix
/// </summary>
/// <param name="outputDirectory">Output folder to write to</param>
/// <param name="outputDirectory">Output folder to use as the base path</param>
/// <param name="filenameSuffix">Optional suffix to append to the filename</param>
/// <param name="outputFilename">Output filename to use as the base path</param>
/// <returns>True on success, false on error</returns>

View File

@@ -49,7 +49,7 @@ namespace MPF.Frontend
}
if (method != null)
return method.Invoke(null, new[] { value }) as string ?? string.Empty;
return method.Invoke(null, [value]) as string ?? string.Empty;
else
return string.Empty;
}
@@ -67,7 +67,7 @@ namespace MPF.Frontend
/// <returns>String representing the value, if possible</returns>
public static string LongName(this InternalProgram? prog)
{
return (prog) switch
return prog switch
{
#region Dumping support
@@ -98,7 +98,7 @@ namespace MPF.Frontend
/// <returns>String representing the value, if possible</returns>
public static string LongName(this RedumperReadMethod? method)
{
return (method) switch
return method switch
{
RedumperReadMethod.D8 => "D8",
RedumperReadMethod.BE => "BE",
@@ -116,7 +116,7 @@ namespace MPF.Frontend
/// <returns>String representing the value, if possible</returns>
public static string LongName(this RedumperSectorOrder? order)
{
return (order) switch
return order switch
{
RedumperSectorOrder.DATA_C2_SUB => "DATA_C2_SUB",
RedumperSectorOrder.DATA_SUB_C2 => "DATA_SUB_C2",
@@ -130,8 +130,86 @@ namespace MPF.Frontend
#endregion
#region Convert to Short Name
/// <summary>
/// Get the short 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 ShortName(this InternalProgram? prog)
{
return prog switch
{
#region Dumping support
InternalProgram.Aaru => "aaru",
InternalProgram.DiscImageCreator => "dic",
InternalProgram.Redumper => "redumper",
#endregion
#region Verification support only
InternalProgram.CleanRip => "cleanrip",
InternalProgram.PS3CFW => "ps3cfw",
InternalProgram.UmdImageCreator => "uic",
InternalProgram.XboxBackupCreator => "xbc",
#endregion
InternalProgram.NONE => "Unknown",
_ => "Unknown",
};
}
#endregion
#region Convert from String
/// <summary>
/// Get the InternalProgram enum value for a given string
/// </summary>
/// <param name="internalProgram">String value to convert</param>
/// <returns>InternalProgram represented by the string, if possible</returns>
public static InternalProgram ToInternalProgram(this string? internalProgram)
{
return (internalProgram?.ToLowerInvariant()) switch
{
// Dumping support
"aaru"
or "chef"
or "dichef"
or "discimagechef" => InternalProgram.Aaru,
"creator"
or "dic"
or "dicreator"
or "discimagecreator" => InternalProgram.DiscImageCreator,
"rd"
or "redumper" => InternalProgram.Redumper,
// Verification support only
"cleanrip"
or "cr" => InternalProgram.CleanRip,
"ps3cfw"
or "ps3"
or "getkey"
or "managunz"
or "multiman" => InternalProgram.PS3CFW,
"uic"
or "umd"
or "umdcreator"
or "umdimagecreator" => InternalProgram.UmdImageCreator,
"xbc"
or "xbox"
or "xbox360"
or "xboxcreator"
or "xboxbackupcreator" => InternalProgram.XboxBackupCreator,
_ => InternalProgram.NONE,
};
}
/// <summary>
/// Get the RedumperReadMethod enum value for a given string
/// </summary>

View File

@@ -53,7 +53,8 @@ namespace MPF.Frontend
or MediaType.NintendoGameCubeGameDisc
or MediaType.NintendoWiiOpticalDisc => DVD,
MediaType.HDDVD => HDDVD,
MediaType.BluRay => BD,
MediaType.BluRay
or MediaType.NintendoWiiUOpticalDisc => BD,
_ => Unknown,
};
}

View File

@@ -10,19 +10,19 @@
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<VersionPrefix>3.2.4</VersionPrefix>
<VersionPrefix>3.3.0</VersionPrefix>
<!-- Package Properties -->
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Description>Common code for all MPF frontend implementations</Description>
<Copyright>Copyright (c) Matt Nadareski 2019-2024</Copyright>
<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>
<InternalsVisibleTo Include="MPF.Test" />
<InternalsVisibleTo Include="MPF.Frontend.Test" />
</ItemGroup>
<ItemGroup>
@@ -40,12 +40,10 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="BinaryObjectScanner" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="3.2.3" GeneratePathProperty="true">
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="BinaryObjectScanner" Version="3.3.4" />
<PackageReference Include="LibIRD" Version="0.9.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.5.2" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.4" />
</ItemGroup>
</Project>

45
MPF.Frontend/OldDotNet.cs Normal file
View File

@@ -0,0 +1,45 @@
#if NET20 || NET35
using System.Collections;
using System.Collections.Generic;
namespace MPF.Frontend
{
internal interface IReadOnlyCollection<T> : IEnumerable<T>
{
int Count { get; }
}
internal sealed class ConcurrentQueue<T> : IReadOnlyCollection<T>
{
private Queue<T> _queue = new Queue<T>();
private object _lock = new object();
public int Count => _queue.Count;
public void Enqueue(T item)
{
lock (_lock)
{
_queue.Enqueue(item);
}
}
public bool TryDequeue(out T item)
{
lock (_lock)
{
item = default(T)!;
if (_queue.Count == 0)
return false;
item = _queue.Dequeue();
return true;
}
}
IEnumerator<T> IEnumerable<T>.GetEnumerator() => _queue.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _queue.GetEnumerator();
}
}
#endif

View File

@@ -61,7 +61,7 @@ namespace MPF.Frontend
get
{
var valueString = GetStringSetting(Settings, "InternalProgram", InternalProgram.Redumper.ToString());
var valueEnum = ToInternalProgram(valueString);
var valueEnum = valueString.ToInternalProgram();
return valueEnum == InternalProgram.NONE ? InternalProgram.Redumper : valueEnum;
}
set
@@ -144,7 +144,7 @@ namespace MPF.Frontend
{
get
{
var valueString = GetStringSetting(Settings, "DefaultSystem", null);
var valueString = GetStringSetting(Settings, "DefaultSystem", RedumpSystem.IBMPCcompatible.LongName());
var valueEnum = Extensions.ToRedumpSystem(valueString ?? string.Empty);
return valueEnum;
}
@@ -469,7 +469,7 @@ namespace MPF.Frontend
/// </summary>
public bool EnableTabsInInputFields
{
get { return GetBooleanSetting(Settings, "EnableTabsInInputFields", false); }
get { return GetBooleanSetting(Settings, "EnableTabsInInputFields", true); }
set { Settings["EnableTabsInInputFields"] = value.ToString(); }
}
@@ -589,15 +589,6 @@ namespace MPF.Frontend
set { Settings["ScanArchivesForProtection"] = value.ToString(); }
}
/// <summary>
/// Scan for executable packers during protection scanning
/// </summary>
public bool ScanPackersForProtection
{
get { return GetBooleanSetting(Settings, "ScanPackersForProtection", false); }
set { Settings["ScanPackersForProtection"] = value.ToString(); }
}
/// <summary>
/// Include debug information with scan results
/// </summary>
@@ -694,49 +685,6 @@ namespace MPF.Frontend
#region Helpers
/// <summary>
/// Get the InternalProgram enum value for a given string
/// </summary>
/// <param name="internalProgram">String value to convert</param>
/// <returns>InternalProgram represented by the string, if possible</returns>
public static InternalProgram ToInternalProgram(string? internalProgram)
{
return (internalProgram?.ToLowerInvariant()) switch
{
// Dumping support
"aaru"
or "chef"
or "dichef"
or "discimagechef" => InternalProgram.Aaru,
"creator"
or "dic"
or "dicreator"
or "discimagecreator" => InternalProgram.DiscImageCreator,
"rd"
or "redumper" => InternalProgram.Redumper,
// Verification support only
"cleanrip"
or "cr" => InternalProgram.CleanRip,
"ps3cfw"
or "ps3"
or "getkey"
or "managunz"
or "multiman" => InternalProgram.PS3CFW,
"uic"
or "umd"
or "umdcreator"
or "umdimagecreator" => InternalProgram.UmdImageCreator,
"xbc"
or "xbox"
or "xbox360"
or "xboxcreator"
or "xboxbackupcreator" => InternalProgram.XboxBackupCreator,
_ => InternalProgram.NONE,
};
}
/// <summary>
/// Get a Boolean setting from a settings, dictionary
/// </summary>
@@ -744,7 +692,7 @@ namespace MPF.Frontend
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
private static bool GetBooleanSetting(Dictionary<string, string?> settings, string key, bool defaultValue)
internal static bool GetBooleanSetting(Dictionary<string, string?> settings, string key, bool defaultValue)
{
if (settings.ContainsKey(key))
{
@@ -766,7 +714,7 @@ namespace MPF.Frontend
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
private static int GetInt32Setting(Dictionary<string, string?> settings, string key, int defaultValue)
internal static int GetInt32Setting(Dictionary<string, string?> settings, string key, int defaultValue)
{
if (settings.ContainsKey(key))
{
@@ -788,7 +736,7 @@ namespace MPF.Frontend
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
private static string? GetStringSetting(Dictionary<string, string?> settings, string key, string? defaultValue)
internal static string? GetStringSetting(Dictionary<string, string?> settings, string key, string? defaultValue)
{
if (settings.ContainsKey(key))
return settings[key];

View File

@@ -5,7 +5,8 @@ namespace MPF.Frontend
/// <summary>
/// Determines how user information is processed, if at all
/// </summary>
/// <param name="options">Options set that may impact processing</params>
/// <param name="info">Submission info that may be overwritten</param>
/// <returns>True for successful updating, false or null otherwise</returns>
public delegate bool? ProcessUserInfoDelegate(ref SubmissionInfo? info);
public delegate bool? ProcessUserInfoDelegate(Options? options, ref SubmissionInfo? info);
}

View File

@@ -1,94 +0,0 @@
using System;
#if NET20 || NET35
using System.Collections.Generic;
#else
using System.Collections.Concurrent;
#endif
using System.Threading;
using System.Threading.Tasks;
namespace MPF.Frontend
{
public sealed class ProcessingQueue<T> : IDisposable
{
/// <summary>
/// Internal queue to hold data to process
/// </summary>
#if NET20 || NET35
private readonly Queue<T> _internalQueue;
#else
private readonly ConcurrentQueue<T> _internalQueue;
#endif
/// <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)
{
_internalQueue = [];
_customProcessing = customProcessing;
_tokenSource = new CancellationTokenSource();
#if NET20 || NET35
Task.Run(() => ProcessQueue());
#elif NET40
Task.Factory.StartNew(() => ProcessQueue());
#else
Task.Run(() => ProcessQueue(), _tokenSource.Token);
#endif
}
/// <summary>
/// Dispose the current instance
/// </summary>
public void Dispose() => _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 && !_tokenSource.IsCancellationRequested)
_internalQueue.Enqueue(item);
}
/// <summary>
/// Process
/// </summary>
private void ProcessQueue()
{
while (true)
{
// Nothing in the queue means we get to idle
if (_internalQueue.Count == 0)
{
if (_tokenSource.IsCancellationRequested)
break;
Thread.Sleep(1);
continue;
}
#if NET20 || NET35
// Get the next item from the queue and invoke the lambda, if possible
_customProcessing?.Invoke(_internalQueue.Dequeue());
#else
// Get the next item from the queue
if (!_internalQueue.TryDequeue(out var nextItem))
continue;
// Invoke the lambda, if possible
_customProcessing?.Invoke(nextItem);
#endif
}
}
}
}

View File

@@ -31,6 +31,7 @@ namespace MPF.Frontend.Tools
// BD dump speed
MediaType.BluRay => options.PreferredDumpSpeedBD,
MediaType.NintendoWiiUOpticalDisc => options.PreferredDumpSpeedBD,
// Default
_ => options.PreferredDumpSpeedCD,
@@ -58,15 +59,26 @@ namespace MPF.Frontend.Tools
return RedumpSystem.MicrosoftXbox;
// Microsoft Xbox 360
if (volumeLabel.Equals("XBOX360", StringComparison.OrdinalIgnoreCase))
if (volumeLabel.Equals("XBOX360"))
return RedumpSystem.MicrosoftXbox360;
else if (volumeLabel.Equals("XGD2DVD_NTSC", StringComparison.OrdinalIgnoreCase))
else if (volumeLabel.Equals("XGD2DVD_NTSC"))
return RedumpSystem.MicrosoftXbox360;
// Microsoft Xbox 360 - Too overly broad even if a lot of discs use this
//if (volumeLabel.Equals("CD_ROM", StringComparison.OrdinalIgnoreCase))
// return RedumpSystem.MicrosoftXbox360; // Also for Xbox One?
//if (volumeLabel.Equals("DVD_ROM", StringComparison.OrdinalIgnoreCase))
else if (volumeLabel.Equals("XBOX_TINYTEST"))
return RedumpSystem.MicrosoftXbox360;
else if (volumeLabel.Equals("13599"))
return RedumpSystem.MicrosoftXbox360;
else if (volumeLabel.Equals("14719"))
return RedumpSystem.MicrosoftXbox360;
else if (volumeLabel.Equals("15574"))
return RedumpSystem.MicrosoftXbox360;
else if (volumeLabel.Equals("16197"))
return RedumpSystem.MicrosoftXbox360;
else if (volumeLabel.Equals("16197"))
return RedumpSystem.MicrosoftXbox360;
else if (volumeLabel.Equals("17349"))
return RedumpSystem.MicrosoftXbox360;
// DVD_ROM and CD_ROM have too many false positives
//else if (volumeLabel.Equals("DVD_ROM"))
// return RedumpSystem.MicrosoftXbox360;
// Sega Mega-CD / Sega-CD
@@ -518,22 +530,19 @@ namespace MPF.Frontend.Tools
return string.Empty;
// Remove quotes and angle brackets from path
path = path!.Replace("\"", string.Empty);
path = path!.Replace("<", string.Empty);
path = path!.Replace(">", string.Empty);
path = path!.Trim('\"');
path = path!.Trim('<');
path = path!.Trim('>');
// Remove invalid path characters
foreach (char c in Path.GetInvalidPathChars())
path = path.Replace(c, '_');
// Try getting the combined path and returning that directly
string fullPath = getFullPath ? Path.GetFullPath(path) : path;
var fullDirectory = Path.GetDirectoryName(fullPath);
string fullFile = Path.GetFileName(fullPath);
// Remove invalid path characters
if (fullDirectory != null)
{
foreach (char c in Path.GetInvalidPathChars())
fullDirectory = fullDirectory.Replace(c, '_');
}
// Remove invalid filename characters
foreach (char c in Path.GetInvalidFileNameChars())
fullFile = fullFile.Replace(c, '_');

View File

@@ -9,14 +9,26 @@ namespace MPF.Frontend.Tools
{
public static class OptionsLoader
{
/// <summary>
/// Configuration file name
/// </summary>
private const string ConfigurationFileName = "config.json";
/// <summary>
/// Full path to the configuration file used by the program
/// </summary>
#if NET20 || NET35 || NET40 || NET452
private static string ConfigurationPath => Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "config.json");
#else
private static string ConfigurationPath => Path.Combine(AppContext.BaseDirectory, "config.json");
#endif
private static string ConfigurationPath
{
get
{
if (_configPath != null)
return _configPath;
_configPath = GetConfigurationPath();
return _configPath;
}
}
private static string? _configPath = null;
#region Arguments
@@ -123,7 +135,7 @@ namespace MPF.Frontend.Tools
if (((InternalProgram)val!) == InternalProgram.NONE)
continue;
programs.Add($"{((InternalProgram?)val).LongName()}");
programs.Add($"{((InternalProgram?)val).ShortName()} - {((InternalProgram?)val).LongName()}");
}
return programs;
@@ -281,7 +293,12 @@ namespace MPF.Frontend.Tools
/// </summary>
public static Options LoadFromConfig()
{
if (!File.Exists(ConfigurationPath))
// If no options path can be found
if (string.IsNullOrEmpty(ConfigurationPath))
return new Options();
// Ensure the file exists
if (!File.Exists(ConfigurationPath) || new FileInfo(ConfigurationPath).Length == 0)
{
File.Create(ConfigurationPath).Dispose();
return new Options();
@@ -300,6 +317,10 @@ namespace MPF.Frontend.Tools
/// </summary>
public static void SaveToConfig(Options options, bool saveDefault = false)
{
// If no options path can be found
if (string.IsNullOrEmpty(ConfigurationPath))
return;
// If default values should be saved as well
if (saveDefault)
{
@@ -329,6 +350,53 @@ namespace MPF.Frontend.Tools
serializer.Serialize(writer, options.Settings, typeof(Dictionary<string, string>));
}
/// <summary>
/// Attempt to determine the configuration path
/// </summary>
private static string GetConfigurationPath()
{
// User home directory
#if NET20 || NET35
string homeDir = Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%");
homeDir = Path.Combine(Path.Combine(homeDir, ".config"), "mpf");
#else
string homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
homeDir = Path.Combine(homeDir, ".config", "mpf");
#endif
if (File.Exists(Path.Combine(homeDir, ConfigurationFileName)))
return Path.Combine(homeDir, ConfigurationFileName);
// Local folder
#if NET20 || NET35 || NET40 || NET452
string runtimeDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
#else
string runtimeDir = AppContext.BaseDirectory;
#endif
if (File.Exists(Path.Combine(runtimeDir, ConfigurationFileName)))
return Path.Combine(runtimeDir, ConfigurationFileName);
// Attempt to use local folder
try
{
Directory.CreateDirectory(runtimeDir);
File.Create(Path.Combine(runtimeDir, ConfigurationFileName)).Dispose();
return Path.Combine(runtimeDir, ConfigurationFileName);
}
catch { }
// Attempt to use home directory
try
{
Directory.CreateDirectory(homeDir);
File.Create(Path.Combine(homeDir, ConfigurationFileName)).Dispose();
return Path.Combine(homeDir, ConfigurationFileName);
}
catch { }
// This should not happen
return string.Empty;
}
#endregion
}
}

View File

@@ -5,6 +5,7 @@ using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SabreTools.IO;
using SabreTools.RedumpLib.Data;
namespace MPF.Frontend.Tools
{
@@ -12,7 +13,7 @@ namespace MPF.Frontend.Tools
{
#region Generic
/// <summary>s
/// <summary>
/// Get the last modified date for a file from a physical disc, if possible
/// </summary>
/// <param name="drive">Drive to extract information from</param>
@@ -37,20 +38,66 @@ namespace MPF.Frontend.Tools
if (!File.Exists(exePath))
return null;
// Get the last modified time
var fi = new FileInfo(exePath);
var lastModified = fi.LastWriteTimeUtc;
int year = lastModified.Year;
int month = lastModified.Month;
int day = lastModified.Day;
try
{
// Get the last modified time
var fi = new FileInfo(exePath);
var lastModified = fi.LastWriteTimeUtc;
int year = lastModified.Year;
int month = lastModified.Month;
int day = lastModified.Day;
// Fix the Y2K timestamp issue, if required
if (fixTwoDigitYear)
year = year >= 1900 && year < 1920 ? 2000 + year % 100 : year;
// Fix the Y2K timestamp issue, if required
if (fixTwoDigitYear)
year = year >= 1900 && year < 1920 ? 2000 + year % 100 : year;
// Format and return the string
var dt = new DateTime(year, month, day);
return dt.ToString("yyyy-MM-dd");
// Format and return the string
var dt = new DateTime(year, month, day);
return dt.ToString("yyyy-MM-dd");
}
catch
{
// We don't care what the error is
return null;
}
}
/// <summary>
/// Get the first numBytes bytes from a disc drive
/// </summary>
/// <param name="drive">Drive to get sector from</param>
/// <param name="numBytes">Number of bytes to read from drive, maximum of one sector (2048 bytes)</param>
/// <returns>Byte array of first sector of data, null on error</returns>
public static byte[]? GetFirstBytes(Drive? drive, int numBytes)
{
if (drive == null || drive.Letter == null || drive.Letter == '\0')
return null;
// Must read between 1 and 2048 bytes
if (numBytes < 1)
return null;
else if (numBytes > 2048)
numBytes = 2048;
string drivePath = $"\\\\.\\{drive.Letter}:";
var firstSector = new byte[numBytes];
try
{
// Open the drive as a raw device
using var driveStream = new FileStream(drivePath, FileMode.Open, FileAccess.Read);
// Read the first sector
int bytesRead = driveStream.Read(firstSector, 0, numBytes);
if (bytesRead < numBytes)
return null;
}
catch
{
// We don't care what the error is
return null;
}
return firstSector;
}
#endregion
@@ -102,7 +149,7 @@ namespace MPF.Frontend.Tools
}
catch
{
// We don't care what the error is right now
// We don't care what the error is
return false;
}
}
@@ -130,32 +177,36 @@ namespace MPF.Frontend.Tools
string psxExePath = Path.Combine(drive.Name, "PSX.EXE");
string systemCnfPath = Path.Combine(drive.Name, "SYSTEM.CNF");
// Read the CNF file as an INI file
var systemCnf = new IniFile(systemCnfPath);
string? bootValue = string.Empty;
// PlayStation uses "BOOT" as the key
if (systemCnf.ContainsKey("BOOT"))
bootValue = systemCnf["BOOT"];
// PlayStation 2 uses "BOOT2" as the key
if (systemCnf.ContainsKey("BOOT2"))
bootValue = systemCnf["BOOT2"];
// If we had any boot value, parse it and get the executable name
if (!string.IsNullOrEmpty(bootValue))
try
{
var match = Regex.Match(bootValue, @"cdrom.?:\\?(.*)", RegexOptions.Compiled);
if (match.Groups.Count > 1)
// Read the CNF file as an INI file
var systemCnf = new IniFile(systemCnfPath);
string? bootValue = string.Empty;
// PlayStation uses "BOOT" as the key
if (systemCnf.ContainsKey("BOOT"))
bootValue = systemCnf["BOOT"];
// PlayStation 2 uses "BOOT2" as the key
if (systemCnf.ContainsKey("BOOT2"))
bootValue = systemCnf["BOOT2"];
// If we had any boot value, parse it and get the executable name
if (!string.IsNullOrEmpty(bootValue))
{
string? serial = match.Groups[1].Value;
// Some games may have the EXE in a subfolder
serial = Path.GetFileName(serial);
return serial;
var match = Regex.Match(bootValue, @"cdrom.?:\\?(.*)", RegexOptions.Compiled);
if (match.Groups.Count > 1)
{
// Some games may have the EXE in a subfolder
string? serial = match.Groups[1].Value;
return Path.GetFileName(serial);
}
}
}
catch
{
// We don't care what the error is, assume SYSTEM.CNF doesn't exist
}
// If the SYSTEM.CNF value can't be found, try PSX.EXE
if (File.Exists(psxExePath))
@@ -211,13 +262,21 @@ namespace MPF.Frontend.Tools
// Get the SYSTEM.CNF path to check
string systemCnfPath = Path.Combine(drive.Name, "SYSTEM.CNF");
// Try to parse the SYSTEM.CNF file
var systemCnf = new IniFile(systemCnfPath);
if (systemCnf.ContainsKey("VER"))
return systemCnf["VER"];
try
{
// Try to parse the SYSTEM.CNF file
var systemCnf = new IniFile(systemCnfPath);
if (systemCnf.ContainsKey("VER"))
return systemCnf["VER"];
// If "VER" can't be found, we can't do much
return null;
// If "VER" can't be found, we can't do much
return null;
}
catch
{
// We don't care what the error is
return null;
}
}
/// <summary>
@@ -452,6 +511,59 @@ namespace MPF.Frontend.Tools
}
}
/// <summary>
/// Get the app.pkg info from a PlayStation 4 disc, if possible
/// </summary>
/// <param name="drive">Drive to extract information from</param>
/// <returns>PKG info if possible, null on error</returns>
public static string? GetPlayStation4PkgInfo(Drive? drive)
{
// If there's no drive path, we can't do this part
if (string.IsNullOrEmpty(drive?.Name))
return null;
// If the folder no longer exists, we can't do this part
if (!Directory.Exists(drive!.Name))
return null;
// Try parse the app.pkg (multiple if they exist)
try
{
string? pkgInfo = "";
string[] appDirs = Directory.GetDirectories(Path.Combine(drive.Name, "app"), "?????????", SearchOption.TopDirectoryOnly);
foreach (string dir in appDirs)
{
string appPkgPath = Path.Combine(dir, "app.pkg");
if (!File.Exists(appPkgPath))
continue;
long appPkgSize = new FileInfo(appPkgPath).Length;
if (appPkgSize < 4096)
continue;
// Read the app.pkg header
using var fileStream = new FileStream(appPkgPath, FileMode.Open, FileAccess.Read);
var appPkgHeaderDeserializer = new SabreTools.Serialization.Deserializers.AppPkgHeader();
var appPkgHeader = appPkgHeaderDeserializer.Deserialize(fileStream);
if (appPkgHeader != null)
pkgInfo += $"{appPkgHeader.ContentID}";
}
if (pkgInfo == "")
return null;
else
return pkgInfo;
}
catch
{
// We don't care what the error was
return null;
}
}
/// <summary>
/// Get the internal serial from a PlayStation 5 disc, if possible
/// </summary>
@@ -530,7 +642,9 @@ namespace MPF.Frontend.Tools
private static JObject? GetPlayStation5ParamsJsonFromFile(string? filename)
{
// If the file doesn't exist
if (string.IsNullOrEmpty(filename) || !File.Exists(filename))
if (string.IsNullOrEmpty(filename))
return null;
if (!File.Exists(filename))
return null;
// Let's try reading param.json to find the version in the unencrypted JSON
@@ -548,6 +662,59 @@ namespace MPF.Frontend.Tools
}
}
/// <summary>
/// Get the app.pkg info from a PlayStation 5 disc, if possible
/// </summary>
/// <param name="drive">Drive to extract information from</param>
/// <returns>PKG info if possible, null on error</returns>
public static string? GetPlayStation5PkgInfo(Drive? drive)
{
// If there's no drive path, we can't do this part
if (string.IsNullOrEmpty(drive?.Name))
return null;
// If the folder no longer exists, we can't do this part
if (!Directory.Exists(drive!.Name))
return null;
// Try parse the app_sc.pkg (multiple if they exist)
try
{
string? pkgInfo = "";
string[] appDirs = Directory.GetDirectories(Path.Combine(drive.Name, "app"), "?????????", SearchOption.TopDirectoryOnly);
foreach (string dir in appDirs)
{
string appPkgPath = Path.Combine(dir, "app_sc.pkg");
if (!File.Exists(appPkgPath))
continue;
long appPkgSize = new FileInfo(appPkgPath).Length;
if (appPkgSize < 4096)
continue;
// Read the app_sc.pkg header
using var fileStream = new FileStream(appPkgPath, FileMode.Open, FileAccess.Read);
var appPkgHeaderDeserializer = new SabreTools.Serialization.Deserializers.AppPkgHeader();
var appPkgHeader = appPkgHeaderDeserializer.Deserialize(fileStream);
if (appPkgHeader != null)
pkgInfo += $"{appPkgHeader.ContentID}";
}
if (pkgInfo == "")
return null;
else
return pkgInfo;
}
catch
{
// We don't care what the error was
return null;
}
}
#endregion
#region Xbox
@@ -580,11 +747,72 @@ namespace MPF.Frontend.Tools
}
catch
{
// We don't care what the error is right now
// We don't care what the error is
return null;
}
}
#endregion
#region Sega
/// <summary>
/// Detect the Sega system based on the CD ROM header
/// </summary>
/// <param name="drive">Drive to detect system from</param>
/// <returns>Detected RedumpSystem if detected, null otherwise</returns>
public static RedumpSystem? DetectSegaSystem(Drive? drive)
{
if (drive == null)
return null;
byte[]? firstSector = GetFirstBytes(drive, 0x10);
if (firstSector == null || firstSector.Length < 0x10)
return null;
string systemType = Encoding.ASCII.GetString(firstSector, 0x00, 0x10);
if (systemType.Equals("SEGA SEGASATURN ", StringComparison.Ordinal))
return RedumpSystem.SegaSaturn;
else if (systemType.Equals("SEGA SEGAKATANA ", StringComparison.Ordinal))
return RedumpSystem.SegaDreamcast;
else if (systemType.Equals("SEGADISCSYSTEM ", StringComparison.Ordinal))
return RedumpSystem.SegaMegaCDSegaCD;
else if (systemType.Equals("SEGA MEGA DRIVE ", StringComparison.Ordinal))
return RedumpSystem.SegaMegaCDSegaCD;
else if (systemType.Equals("SEGA GENESIS ", StringComparison.Ordinal))
return RedumpSystem.SegaMegaCDSegaCD;
return null;
}
#endregion
#region Other
/// <summary>
/// Detect a 3DO disc based on the CD ROM header
/// </summary>
/// <param name="drive">Drive to detect 3DO disc from</param>
/// <returns>RedumpSystem.Panasonic3DOInteractiveMultiplayer if detected, null otherwise</returns>
public static RedumpSystem? Detect3DOSystem(Drive? drive)
{
if (drive == null)
return null;
byte[]? firstSector = GetFirstBytes(drive, 0xC0);
if (firstSector == null || firstSector.Length < 0xC0)
return null;
string systemType = Encoding.ASCII.GetString(firstSector, 0xB0, 0x10);
if (systemType.Equals("iamaduckiamaduck", StringComparison.Ordinal))
return RedumpSystem.Panasonic3DOInteractiveMultiplayer;
return null;
}
#endregion
}
}

View File

@@ -13,6 +13,58 @@ namespace MPF.Frontend.Tools
{
public static class ProtectionTool
{
/// <summary>
/// Set of protection prefixes to filter on
/// </summary>
/// <remarks>Based on Redump requirements</remarks>
private static readonly string[] FilterPrefixes = [
#region Game Engine
"RenderWare",
#endregion
#region Packers
".NET Reactor",
"7-Zip SFX",
"ASPack",
"AutoPlay Media Studio",
"Caphyon Advanced Installer",
"CExe",
"dotFuscator",
"Embedded",
"EXE Stealth",
"Gentee Installer",
"HyperTech CrackProof",
"Inno Setup",
"InstallAnywhere",
"Installer VISE",
"Intel Installation Framework",
"Microsoft CAB SFX",
"NeoLite",
"NSIS",
"PE Compact",
"PEtite",
"Setup Factory",
"Shrinker",
"UPX",
"WinRAR SFX",
"WinZip SFX",
"Wise Installation",
#endregion
#region Protections
"CD-Key / Serial",
"EA CdKey",
"Executable-Based CD Check",
"Executable-Based Online Registration",
#endregion
];
/// <summary>
/// Run protection scan on a given path
/// </summary>
@@ -21,7 +73,7 @@ namespace MPF.Frontend.Tools
/// <param name="progress">Optional progress callback</param>
/// <returns>Set of all detected copy protections with an optional error string</returns>
public static async Task<ProtectionDictionary> RunProtectionScanOnPath(string path,
Frontend.Options options,
Options options,
IProgress<ProtectionProgress>? progress = null)
{
#if NET40
@@ -33,9 +85,8 @@ namespace MPF.Frontend.Tools
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
scanSubdirectories: true, // Hardcoded value to avoid issues
options.IncludeDebugProtectionInformation,
progress);
@@ -137,6 +188,13 @@ namespace MPF.Frontend.Tools
/// Sanitize unnecessary protection duplication from output
/// </summary>
/// <param name="foundProtections">Enumerable of found protections</param>
/// <remarks>
/// This filtering only impacts the information that goes into the single-line
/// protection field in the output submission info. The filtering performed by
/// this method applies to the needs of Redump and not necessarily any other
/// application. The full protection list should be used as a reference in all
/// other cases.
/// </remarks>
public static string SanitizeFoundProtections(List<string> foundProtections)
{
// EXCEPTIONS
@@ -146,6 +204,12 @@ namespace MPF.Frontend.Tools
foundProtections.Add("Exception occurred while scanning [RESCAN NEEDED]");
}
// Filtered prefixes
foreach (string prefix in FilterPrefixes)
{
foundProtections = foundProtections.FindAll(p => !p.StartsWith(prefix));
}
// ActiveMARK
if (foundProtections.Exists(p => p == "ActiveMARK 5")
&& foundProtections.Exists(p => p == "ActiveMARK"))
@@ -160,23 +224,25 @@ namespace MPF.Frontend.Tools
foundProtections = foundProtections.FindAll(p => p != "Cactus Data Shield 200");
}
// CD-Check
foundProtections = foundProtections.FindAll(p => p != "Executable-Based CD Check");
// Cactus Data Shield / SafeDisc
if (foundProtections.Exists(p => p == "Cactus Data Shield 300 (Confirm presence of other CDS-300 files)"))
{
foundProtections = foundProtections
.FindAll(p => p != "Cactus Data Shield 300 (Confirm presence of other CDS-300 files)");
if (foundProtections.Exists(p => !p.StartsWith("SafeDisc")))
foundProtections.Add("Cactus Data Shield 300");
}
// CD-Cops
if (foundProtections.Exists(p => p == "CD-Cops") && foundProtections.Exists(p => p.StartsWith("CD-Cops") && p.Length > "CD-Cops".Length))
if (foundProtections.Exists(p => p == "CD-Cops")
&& foundProtections.Exists(p => p.StartsWith("CD-Cops")
&& p.Length > "CD-Cops".Length))
{
foundProtections = foundProtections.FindAll(p => p != "CD-Cops");
// CD-Key / Serial
foundProtections = foundProtections.FindAll(p => p != "CD-Key / Serial");
}
// Electronic Arts
if (foundProtections.Exists(p => p == "EA CdKey Registration Module")
&& foundProtections.Exists(p => p.StartsWith("EA CdKey Registration Module")
&& p.Length > "EA CdKey Registration Module".Length))
{
foundProtections = foundProtections.FindAll(p => p != "EA CdKey Registration Module");
}
if (foundProtections.Exists(p => p == "EA DRM Protection")
&& foundProtections.Exists(p => p.StartsWith("EA DRM Protection")
&& p.Length > "EA DRM Protection".Length))
@@ -230,82 +296,78 @@ namespace MPF.Frontend.Tools
// LaserLok
// TODO: Figure this one out
// Online Registration
foundProtections = foundProtections.FindAll(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.Exists(p => p == "Cactus Data Shield 300 (Confirm presence of other CDS-300 files)"))
{
foundProtections = foundProtections
.FindAll(p => p != "Cactus Data Shield 300 (Confirm presence of other CDS-300 files)");
if (foundProtections.Exists(p => !p.StartsWith("SafeDisc")))
foundProtections.Add("Cactus Data Shield 300");
}
// SafeDisc
if (foundProtections.Exists(p => p.StartsWith("SafeDisc")))
{
// Confirmed this set of checks works with Redump entries 10430, 11347, 13230, 18614, 28257, 31149, 31824, 52606, 57721, 58455, 58573, 62935, 63941, 64255, 65569, 66005, 70504, 73502, 74520, 78048, 79729, 83468, 98589, and 101261.
// Confirmed this set of checks works with Redump entries 10430, 11347, 13230, 18614, 28257, 31149, 31824, 52606, 57721, 58455,
// 58573, 62935, 63941, 64255, 65569, 66005, 70504, 73502, 74520, 78048, 79729, 83468, 98589, and 101261.
// Best case scenario for SafeDisc 2+: A full SafeDisc version is found in a line starting with "Macrovision Protected Application". All other SafeDisc detections can be safely scrubbed.
// Best case scenario for SafeDisc 2+: A full SafeDisc version is found in a line starting with "Macrovision Protected Application".
// All other SafeDisc detections can be safely scrubbed.
// TODO: Scrub "Macrovision Protected Application, " from before the SafeDisc version.
if (foundProtections.Exists(p => Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled) && p.StartsWith("Macrovision Protected Application") && !p.Contains("SRV Tool APP")))
if (foundProtections.Exists(p => Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled)
&& p.StartsWith("Macrovision Protected Application")
&& !p.Contains("SRV Tool APP")))
{
foundProtections = foundProtections.FindAll(p => !p.StartsWith("Macrovision Protection File"))
.FindAll(p => !p.StartsWith("Macrovision Security Driver"))
.FindAll(p => !p.Contains("SRV Tool APP"))
.FindAll(p => p != "SafeDisc")
.FindAll(p => !p.StartsWith("Macrovision Protected Application [Version Expunged]"))
.FindAll(p => !(Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}-[0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled)))
.FindAll(p => !(Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}\+", RegexOptions.Compiled)))
.FindAll(p => !(Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}\/4\+", RegexOptions.Compiled)))
.FindAll(p => !Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}-[0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled))
.FindAll(p => !Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}\+", RegexOptions.Compiled))
.FindAll(p => !Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}\/4\+", RegexOptions.Compiled))
.FindAll(p => p != "SafeDisc 1/Lite")
.FindAll(p => p != "SafeDisc 2+")
.FindAll(p => p != "SafeDisc 3+ (DVD)");
}
// Next best case for SafeDisc 2+: A full SafeDisc version is found from the "SafeDisc SRV Tool APP".
else if (foundProtections.Exists(p => Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled) && p.StartsWith("Macrovision Protected Application") && p.Contains("SRV Tool APP")))
else if (foundProtections.Exists(p => Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled)
&& p.StartsWith("Macrovision Protected Application")
&& p.Contains("SRV Tool APP")))
{
foundProtections = foundProtections.FindAll(p => !p.StartsWith("Macrovision Protection File"))
.FindAll(p => !p.StartsWith("Macrovision Security Driver"))
.FindAll(p => p != "SafeDisc")
.FindAll(p => !p.StartsWith("Macrovision Protected Application [Version Expunged]"))
.FindAll(p => !(Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}-[0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled)))
.FindAll(p => !(Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}\+", RegexOptions.Compiled)))
.FindAll(p => !(Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}\/4\+", RegexOptions.Compiled)))
.FindAll(p => !Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}-[0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled))
.FindAll(p => !Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}\+", RegexOptions.Compiled))
.FindAll(p => !Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}\/4\+", RegexOptions.Compiled))
.FindAll(p => p != "SafeDisc 1/Lite")
.FindAll(p => p != "SafeDisc 2+")
.FindAll(p => p != "SafeDisc 3+ (DVD)");
}
// Covers specific edge cases where older drivers are erroneously placed in discs with a newer version of SafeDisc, and the specific SafeDisc version is expunged.
else if (foundProtections.Exists(p => Regex.IsMatch(p, @"SafeDisc [1-2]\.[0-9]{2}\.[0-9]{3}-[1-2]\.[0-9]{2}\.[0-9]{3}$", RegexOptions.Compiled) || Regex.IsMatch(p, @"SafeDisc [1-2]\.[0-9]{2}\.[0-9]{3}$", RegexOptions.Compiled)) && foundProtections.Exists(p => p == "SafeDisc 3+ (DVD)"))
else if (foundProtections.Exists(p => Regex.IsMatch(p, @"SafeDisc [1-2]\.[0-9]{2}\.[0-9]{3}-[1-2]\.[0-9]{2}\.[0-9]{3}$", RegexOptions.Compiled)
|| Regex.IsMatch(p, @"SafeDisc [1-2]\.[0-9]{2}\.[0-9]{3}$", RegexOptions.Compiled))
&& foundProtections.Exists(p => p == "SafeDisc 3+ (DVD)"))
{
foundProtections = foundProtections.FindAll(p => !p.StartsWith("Macrovision Protection File"))
.FindAll(p => !p.StartsWith("Macrovision Protected Application [Version Expunged]"))
.FindAll(p => !p.StartsWith("Macrovision Security Driver"))
.FindAll(p => !(Regex.IsMatch(p, @"SafeDisc [1-2]\.[0-9]{2}\.[0-9]{3}\+", RegexOptions.Compiled)))
.FindAll(p => !(Regex.IsMatch(p, @"SafeDisc [1-2]\.[0-9]{2}\.[0-9]{3}-[1-2]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled)))
.FindAll(p => !Regex.IsMatch(p, @"SafeDisc [1-2]\.[0-9]{2}\.[0-9]{3}\+", RegexOptions.Compiled))
.FindAll(p => !Regex.IsMatch(p, @"SafeDisc [1-2]\.[0-9]{2}\.[0-9]{3}-[1-2]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled))
.FindAll(p => p != "SafeDisc")
.FindAll(p => p != "SafeDisc 1/Lite")
.FindAll(p => p != "SafeDisc 2+");
}
// Best case for SafeDisc 1.X: A full SafeDisc version is found that isn't part of a version range.
else if (foundProtections.Exists(p => Regex.IsMatch(p, @"SafeDisc 1\.[0-9]{2}\.[0-9]{3}$", RegexOptions.Compiled) && !(Regex.IsMatch(p, @"SafeDisc 1\.[0-9]{2}\.[0-9]{3}-[0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled))))
else if (foundProtections.Exists(p => Regex.IsMatch(p, @"SafeDisc 1\.[0-9]{2}\.[0-9]{3}$", RegexOptions.Compiled)
&& !Regex.IsMatch(p, @"SafeDisc 1\.[0-9]{2}\.[0-9]{3}-[0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled)))
{
foundProtections = foundProtections.FindAll(p => !p.StartsWith("Macrovision Protection File"))
.FindAll(p => !p.StartsWith("Macrovision Security Driver"))
.FindAll(p => !(Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}-[0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled)))
.FindAll(p => !(Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}\+", RegexOptions.Compiled)))
.FindAll(p => !Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}-[0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled))
.FindAll(p => !Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}\+", RegexOptions.Compiled))
.FindAll(p => p != "SafeDisc")
.FindAll(p => p != "SafeDisc 1")
.FindAll(p => p != "SafeDisc 1/Lite");
@@ -313,12 +375,14 @@ namespace MPF.Frontend.Tools
// Next best case for SafeDisc 1: A SafeDisc version range is found from "SECDRV.SYS".
// TODO: Scrub "Macrovision Security Driver {Version}" from before the SafeDisc version.
else if (foundProtections.Exists(p => p.StartsWith("Macrovision Security Driver") && Regex.IsMatch(p, @"SafeDisc 1\.[0-9]{2}\.[0-9]{3}-[1-2]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled) || Regex.IsMatch(p, @"SafeDisc 1\.[0-9]{2}\.[0-9]{3}$")))
else if (foundProtections.Exists(p => p.StartsWith("Macrovision Security Driver")
&& Regex.IsMatch(p, @"SafeDisc 1\.[0-9]{2}\.[0-9]{3}-[1-2]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled)
|| Regex.IsMatch(p, @"SafeDisc 1\.[0-9]{2}\.[0-9]{3}$")))
{
foundProtections = foundProtections.FindAll(p => !p.StartsWith("Macrovision Protection File"))
.FindAll(p => !p.StartsWith("Macrovision Protected Application [Version Expunged]"))
.FindAll(p => !(Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}\+", RegexOptions.Compiled)))
.FindAll(p => !(Regex.IsMatch(p, @"SafeDisc 1\.[0-9]{2}\.[0-9]{3}-[0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled)))
.FindAll(p => !Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}\+", RegexOptions.Compiled))
.FindAll(p => !Regex.IsMatch(p, @"SafeDisc 1\.[0-9]{2}\.[0-9]{3}-[0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled))
.FindAll(p => p != "SafeDisc")
.FindAll(p => p != "SafeDisc 1")
.FindAll(p => p != "SafeDisc 1/Lite");
@@ -330,8 +394,8 @@ namespace MPF.Frontend.Tools
{
foundProtections = foundProtections.FindAll(p => !p.StartsWith("Macrovision Protection File"))
.FindAll(p => !p.StartsWith("Macrovision Protected Application [Version Expunged]"))
.FindAll(p => !(Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}\+", RegexOptions.Compiled)))
.FindAll(p => !(Regex.IsMatch(p, @"SafeDisc 1\.[0-9]{2}\.[0-9]{3}-[0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled)))
.FindAll(p => !Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}\+", RegexOptions.Compiled))
.FindAll(p => !Regex.IsMatch(p, @"SafeDisc 1\.[0-9]{2}\.[0-9]{3}-[0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled))
.FindAll(p => p != "SafeDisc")
.FindAll(p => p != "SafeDisc 1")
.FindAll(p => p != "SafeDisc 1/Lite")
@@ -343,7 +407,7 @@ namespace MPF.Frontend.Tools
else if (foundProtections.Exists(p => p == "SafeDisc Lite"))
{
foundProtections = foundProtections.FindAll(p => p != "SafeDisc")
.FindAll(p => !(Regex.IsMatch(p, @"SafeDisc 1\.[0-9]{2}\.[0-9]{3}-1\.[0-9]{2}\.[0-9]{3}\/Lite", RegexOptions.Compiled)));
.FindAll(p => !Regex.IsMatch(p, @"SafeDisc 1\.[0-9]{2}\.[0-9]{3}-1\.[0-9]{2}\.[0-9]{3}\/Lite", RegexOptions.Compiled));
}
// Only SafeDisc 3+ is found.
@@ -352,7 +416,7 @@ namespace MPF.Frontend.Tools
foundProtections = foundProtections.FindAll(p => p != "SafeDisc")
.FindAll(p => p != "SafeDisc 2+")
.FindAll(p => !p.StartsWith("Macrovision Protection File"))
.FindAll(p => !(Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}\+", RegexOptions.Compiled)));
.FindAll(p => !Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}\+", RegexOptions.Compiled));
}
// Only SafeDisc 2+ is found.
@@ -360,7 +424,7 @@ namespace MPF.Frontend.Tools
{
foundProtections = foundProtections.FindAll(p => p != "SafeDisc")
.FindAll(p => !p.StartsWith("Macrovision Protection File"))
.FindAll(p => !(Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}\+", RegexOptions.Compiled)));
.FindAll(p => !Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}\+", RegexOptions.Compiled));
}
}

View File

@@ -4,6 +4,7 @@ using System.IO;
#if NET35_OR_GREATER || NETCOREAPP
using System.Linq;
#endif
using System.Text;
using System.Threading.Tasks;
using BinaryObjectScanner;
using MPF.Processors;
@@ -45,7 +46,7 @@ namespace MPF.Frontend.Tools
Drive? drive,
RedumpSystem? system,
MediaType? mediaType,
Frontend.Options options,
Options options,
BaseProcessor processor,
IProgress<ResultEventArgs>? resultProgress = null,
IProgress<ProtectionProgress>? protectionProgress = null)
@@ -67,23 +68,18 @@ namespace MPF.Frontend.Tools
return null;
}
// Sanitize the output filename to strip off any potential extension
outputFilename = Path.GetFileNameWithoutExtension(outputFilename);
// Create the SubmissionInfo object with all user-inputted values by default
string combinedBase;
if (string.IsNullOrEmpty(outputDirectory))
combinedBase = outputFilename;
else
combinedBase = Path.Combine(outputDirectory, outputFilename);
// Assemble a base path
string basePath = Path.GetFileNameWithoutExtension(outputFilename);
if (!string.IsNullOrEmpty(outputDirectory))
basePath = Path.Combine(outputDirectory, basePath);
// Create the default submission info
SubmissionInfo info = CreateDefaultSubmissionInfo(processor, system, mediaType, options.AddPlaceholders);
// Get specific tool output handling
processor?.GenerateSubmissionInfo(info, combinedBase, options.EnableRedumpCompatibility);
processor?.GenerateSubmissionInfo(info, basePath, options.EnableRedumpCompatibility);
if (options.IncludeArtifacts)
info.Artifacts = processor?.GenerateArtifacts(combinedBase);
info.Artifacts = processor?.GenerateArtifacts(outputDirectory, outputFilename);
// Get a list of matching IDs for each line in the DAT
if (!string.IsNullOrEmpty(info.TracksAndWriteOffsets!.ClrMameProData) && options.HasRedumpLogin)
@@ -102,7 +98,7 @@ namespace MPF.Frontend.Tools
ProcessMediaType(info, mediaType, options.AddPlaceholders);
// Extract info based specifically on RedumpSystem
ProcessSystem(info, system, drive, options.AddPlaceholders, processor is DiscImageCreator, combinedBase);
ProcessSystem(info, system, drive, options.AddPlaceholders, processor is DiscImageCreator, basePath);
// Run anti-modchip check, if necessary
if (drive != null && system.SupportsAntiModchipScans() && info.CopyProtection!.AntiModchip == YesNo.NULL)
@@ -157,7 +153,7 @@ namespace MPF.Frontend.Tools
/// <param name="options">Options object representing user-defined options</param>
/// <param name="info">Existing SubmissionInfo object to fill</param>
/// <param name="resultProgress">Optional result progress callback</param>
public async static Task<bool> FillFromRedump(Frontend.Options options,
public async static Task<bool> FillFromRedump(Options options,
SubmissionInfo info,
IProgress<ResultEventArgs>? resultProgress = null)
{
@@ -396,6 +392,37 @@ namespace MPF.Frontend.Tools
return internalProgram.LongName();
}
/// <summary>
/// Simplifies a volume label into uppercase alphanumeric only string
/// </summary>
/// <param name="labels">Volume label to simplify</param>
/// <returns>Simplified volume label, null if empty or invalid</returns>
private static string? SimplifyVolumeLabel(string? label)
{
// Ignore empty labels
if (label == null || label.Length == 0)
return null;
// Take only ASCII alphanumeric characters
var labelBuilder = new StringBuilder();
foreach (char c in label)
{
if (c >= '0' && c <= '9')
labelBuilder.Append(c);
else if (c >= 'A' && c <= 'Z')
labelBuilder.Append(c);
else if (c >= 'a' && c <= 'z')
labelBuilder.Append(char.ToUpper(c));
}
// Ignore non-ASCII labels
string? simpleLabel = labelBuilder.ToString();
if (simpleLabel == null || simpleLabel.Length == 0)
return null;
return simpleLabel;
}
/// <summary>
/// Formats a list of volume labels and their corresponding filesystems
/// </summary>
@@ -403,6 +430,10 @@ namespace MPF.Frontend.Tools
/// <returns>Formatted string of volume labels and their filesystems</returns>
private static string? FormatVolumeLabels(string? driveLabel, Dictionary<string, List<string>>? labels)
{
// Treat empty label as null
if (driveLabel != null && driveLabel.Length == 0)
driveLabel = null;
// Must have at least one label to format
if (driveLabel == null && (labels == null || labels.Count == 0))
return null;
@@ -417,10 +448,60 @@ namespace MPF.Frontend.Tools
return driveLabel;
}
// If only one label, don't mention fs
// Get the default label to compare against
// TODO: Full pairwise comparison of all labels, not just comparing against drive/UDF label.
string? defaultLabel = null;
if (driveLabel != null && driveLabel.Length != 0)
{
defaultLabel = SimplifyVolumeLabel(driveLabel);
}
#if NET35_OR_GREATER || NETCOREAPP
else
{
defaultLabel = labels
.Where(label => label.Value.Contains("UDF"))
.Select(label => label.Key)
.FirstOrDefault();
}
#endif
// Remove duplicate/useless volume labels
if (defaultLabel != null && defaultLabel.Length != 0)
{
List<string> keys = [.. labels.Keys];
foreach (var label in keys)
{
// Always remove "DVD_ROM" / "CD_ROM" labels
if (label == "DVD_ROM" || label == "CD_ROM")
{
labels.Remove(label);
continue;
}
// Get upper-case ASCII variant of the label
string? tempLabel = SimplifyVolumeLabel(label);
if (tempLabel == null)
continue;
// Remove duplicate volume labels
if (defaultLabel == tempLabel)
labels.Remove(label);
}
}
// If no labels are left, use drive label
if (labels == null || labels.Count == 0)
{
// Ignore common volume labels
if (FrontendTool.GetRedumpSystemFromVolumeLabel(driveLabel) != null)
return null;
return driveLabel;
}
// If only one unique label left, don't mention fs
#if NET20
string[] keyArr = new string[labels.Count];
labels.Keys.CopyTo(keyArr, 0);
string[] keyArr = [.. labels.Keys];
string firstLabel = keyArr[0];
#else
string firstLabel = labels.First().Key;
@@ -442,15 +523,15 @@ namespace MPF.Frontend.Tools
volLabels.Add(driveLabel);
// Add remaining labels with their corresponding filesystems
foreach (KeyValuePair<string, List<string>> label in labels)
foreach (var kvp in labels)
{
// Ignore common volume labels
if (FrontendTool.GetRedumpSystemFromVolumeLabel(label.Key) == null)
volLabels.Add($"{label.Key} ({string.Join(", ", [.. label.Value])})");
if (FrontendTool.GetRedumpSystemFromVolumeLabel(kvp.Key) == null)
volLabels.Add($"{kvp.Key} ({string.Join(", ", [.. kvp.Value])})");
}
// Ensure that no labels are empty
volLabels = volLabels.FindAll(l => !string.IsNullOrEmpty(l?.Trim()));
volLabels = volLabels.FindAll(label => !string.IsNullOrEmpty(label?.Trim()));
// Print each label separated by a comma and a space
if (volLabels.Count == 0)
@@ -558,6 +639,7 @@ namespace MPF.Frontend.Tools
break;
case MediaType.NintendoWiiOpticalDisc:
case MediaType.NintendoWiiUOpticalDisc:
// If we have a single-layer disc
if (info.SizeAndChecksums!.Layerbreak == default)
@@ -834,11 +916,13 @@ namespace MPF.Frontend.Tools
case RedumpSystem.SonyPlayStation4:
SetCommentFieldIfNotExists(info, SiteCode.InternalSerialName, drive, PhysicalTool.GetPlayStation4Serial);
SetVersionIfNotExists(info, drive, PhysicalTool.GetPlayStation4Version);
SetContentFieldIfNotExists(info, SiteCode.Games, drive, PhysicalTool.GetPlayStation4PkgInfo);
break;
case RedumpSystem.SonyPlayStation5:
SetCommentFieldIfNotExists(info, SiteCode.InternalSerialName, drive, PhysicalTool.GetPlayStation5Serial);
SetVersionIfNotExists(info, drive, PhysicalTool.GetPlayStation5Version);
SetContentFieldIfNotExists(info, SiteCode.Games, drive, PhysicalTool.GetPlayStation5PkgInfo);
break;
case RedumpSystem.TomyKissSite:
@@ -895,7 +979,9 @@ namespace MPF.Frontend.Tools
return;
// Set the value
info.CommonDiscInfo!.CommentsSpecialFields![key] = valueFunc(drive) ?? string.Empty;
string? value = valueFunc(drive);
if (value != null)
info.CommonDiscInfo!.CommentsSpecialFields![key] = value;
}
/// <summary>
@@ -927,7 +1013,9 @@ namespace MPF.Frontend.Tools
return;
// Set the value
info.CommonDiscInfo!.ContentsSpecialFields![key] = valueFunc(drive) ?? string.Empty;
string? value = valueFunc(drive);
if (value != null)
info.CommonDiscInfo!.ContentsSpecialFields![key] = value;
}
/// <summary>

View File

@@ -1,9 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Threading.Tasks;
using BinaryObjectScanner;
using MPF.Frontend.ComboBoxItems;
using MPF.Frontend.Tools;
using SabreTools.RedumpLib.Data;
@@ -20,11 +18,11 @@ namespace MPF.Frontend.ViewModels
/// <summary>
/// Access to the current options
/// </summary>
public Frontend.Options Options
public Options Options
{
get => _options;
}
private readonly Frontend.Options _options;
private readonly Options _options;
/// <summary>
/// Indicates if SelectionChanged events can be executed
@@ -458,14 +456,16 @@ namespace MPF.Frontend.ViewModels
DisableEventHandlers();
// Populate an environment
var env = new DumpEnvironment(Options, Path.GetFullPath(InputPath.Trim('"')), null, CurrentSystem, CurrentMediaType, CurrentProgram, parameters: null);
// Make new Progress objects
var resultProgress = new Progress<ResultEventArgs>();
var protectionProgress = new Progress<ProtectionProgress>();
var env = new DumpEnvironment(Options,
Path.GetFullPath(InputPath.Trim('"')),
null,
CurrentSystem,
CurrentMediaType,
CurrentProgram,
parameters: null);
// Finally, attempt to do the output dance
var result = await env.VerifyAndSaveDumpOutput(resultProgress, protectionProgress, processUserInfo);
var result = await env.VerifyAndSaveDumpOutput(processUserInfo: processUserInfo);
// Reenable UI and event handlers, if necessary
EnableUIElements();

View File

@@ -19,7 +19,7 @@ namespace MPF.Frontend.ViewModels
/// <summary>
/// Access to the current options
/// </summary>
public Frontend.Options Options
public Options Options
{
get => _options;
set
@@ -28,7 +28,7 @@ namespace MPF.Frontend.ViewModels
OptionsLoader.SaveToConfig(_options);
}
}
private Frontend.Options _options;
private Options _options;
/// <summary>
/// Indicates if SelectionChanged events can be executed
@@ -316,6 +316,20 @@ namespace MPF.Frontend.ViewModels
/// <summary>
/// Indicates the status of the parameters text box
/// </summary>
public bool ParametersTextBoxEnabled
{
get => _parametersTextBoxEnabled;
set
{
_parametersTextBoxEnabled = value;
TriggerPropertyChanged(nameof(ParametersTextBoxEnabled));
}
}
private bool _parametersTextBoxEnabled;
/// <summary>
/// Indicates the status of the parameters check box
/// </summary>
public bool ParametersCheckBoxEnabled
{
get => _parametersCheckBoxEnabled;
@@ -552,6 +566,7 @@ namespace MPF.Frontend.ViewModels
StartStopButtonEnabled = true;
StartStopButtonText = StartDumpingValue;
MediaScanButtonEnabled = true;
ParametersCheckBoxEnabled = true;
EnableParametersCheckBoxEnabled = true;
LogPanelExpanded = _options.OpenLogWindowAtStartup;
@@ -574,7 +589,7 @@ namespace MPF.Frontend.ViewModels
_processUserInfo = processUserInfo;
// Finish initializing the rest of the values
InitializeUIValues(removeEventHandlers: false, rescanDrives: true);
InitializeUIValues(removeEventHandlers: false, rebuildPrograms: true, rescanDrives: true);
}
#region Property Updates
@@ -648,8 +663,7 @@ namespace MPF.Frontend.ViewModels
CopyProtectScanButtonEnabled = true;
// Get the current system type
if (index != -1)
DetermineSystemType();
DetermineSystemType();
// Only enable the start/stop if we don't have the default selected
StartStopButtonEnabled = ShouldEnableDumpingButton();
@@ -853,6 +867,8 @@ namespace MPF.Frontend.ViewModels
CommentsSpecialFields = new Dictionary<SiteCode, string>()
{
[SiteCode.ISBN] = "ISBN",
[SiteCode.RingNonZeroDataStart] = "+123",
[SiteCode.RingPerfectAudioOffset] = "+0"
},
Contents = "Special contents 1\r\nSpecial contents 2",
ContentsSpecialFields = new Dictionary<SiteCode, string>()
@@ -882,10 +898,10 @@ namespace MPF.Frontend.ViewModels
Extras = new ExtrasSection()
{
PVD = "PVD with a stupidly long line and nothing else but a little more\nPVD with a stupidly long line and nothing else but a little more\nPVD with a stupidly long line and nothing else but a little more\nPVD with a stupidly long line and nothing else but a little more\nPVD with a stupidly long line and nothing else but a little more\nPVD with a stupidly long line and nothing else but a little more\n",
PVD = "0320 : 20 20 20 20 20 20 20 20 20 20 20 20 20 32 30 31 201\n0330 : 30 31 30 32 35 31 36 31 39 30 30 30 00 04 32 30 010251619000 .20\n0340 : 31 30 31 30 32 35 31 36 31 39 30 30 30 00 04 30 1010251619000 .0\n0350 : 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 00 000000000000000 \n0360 : 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 0000000000000000\n0370 : 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 . ",
DiscKey = "Disc key",
DiscID = "Disc ID",
PIC = "PIC",
PIC = "10020000444901080000200042444F01\n1101010001000000004F947F00100000\n004F947E000000000000000000000000\n00000000000000000000000000000000\n00000000000000000000000000000000\n00000000000000000000000000000000\n00000000000000000000000000000000\n00000000000000000000000000000000\n00000000",
Header = "Header",
BCA = "BCA",
SecuritySectorRanges = "SSv1 Ranges",
@@ -966,18 +982,18 @@ namespace MPF.Frontend.ViewModels
/// </summary>
/// <param name="savedSettings">Indicates if the settings were saved or not</param>
/// <param name="newOptions">Options representing the new, saved values</param>
public void UpdateOptions(bool savedSettings, Frontend.Options? newOptions)
public void UpdateOptions(bool savedSettings, Options? newOptions)
{
// Get which options to save
var optionsToSave = savedSettings ? newOptions : Options;
// Ensure the first run flag is unset
var continuingOptions = new Frontend.Options(optionsToSave) { FirstRun = false };
var continuingOptions = new Options(optionsToSave) { FirstRun = false };
Options = continuingOptions;
// If settings were changed, reinitialize the UI
if (savedSettings)
InitializeUIValues(removeEventHandlers: true, rescanDrives: true);
InitializeUIValues(removeEventHandlers: true, rebuildPrograms: true, rescanDrives: true);
}
#endregion
@@ -988,18 +1004,19 @@ namespace MPF.Frontend.ViewModels
/// Performs UI value setup end to end
/// </summary>
/// <param name="removeEventHandlers">Whether event handlers need to be removed first</param>
/// <param name="rebuildPrograms">Whether the available program list should be rebuilt</param>
/// <param name="rescanDrives">Whether drives should be rescanned or not</param>
public void InitializeUIValues(bool removeEventHandlers, bool rescanDrives)
public void InitializeUIValues(bool removeEventHandlers, bool rebuildPrograms, bool rescanDrives)
{
// Disable the dumping button
StartStopButtonEnabled = false;
// Safely uncheck the parameters box, just in case
if (ParametersCheckBoxEnabled == true)
// Safely check the parameters box, just in case
if (ParametersCheckBoxEnabled == false)
{
bool cachedCanExecuteSelectionChanged = CanExecuteSelectionChanged;
DisableEventHandlers();
ParametersCheckBoxEnabled = false;
ParametersCheckBoxEnabled = true;
if (cachedCanExecuteSelectionChanged) EnableEventHandlers();
}
@@ -1024,7 +1041,8 @@ namespace MPF.Frontend.ViewModels
SetCurrentDiscType();
// Set the dumping program
PopulateInternalPrograms();
if (rebuildPrograms)
PopulateInternalPrograms();
// Set the initial environment and UI values
SetSupportedDriveSpeed();
@@ -1048,12 +1066,12 @@ namespace MPF.Frontend.ViewModels
// Disable the dumping button
StartStopButtonEnabled = false;
// Safely uncheck the parameters box, just in case
if (ParametersCheckBoxEnabled == true)
// Safely check the parameters box, just in case
if (ParametersCheckBoxEnabled == false)
{
bool cachedCanExecuteSelectionChanged = CanExecuteSelectionChanged;
DisableEventHandlers();
ParametersCheckBoxEnabled = false;
ParametersCheckBoxEnabled = true;
if (cachedCanExecuteSelectionChanged) EnableEventHandlers();
}
@@ -1239,15 +1257,34 @@ namespace MPF.Frontend.ViewModels
{
VerboseLogLn("Skipping system type detection because no valid drives found!");
}
else if (CurrentDrive?.MarkedActive != true)
{
VerboseLogLn("Skipping system type detection because drive not marked as active!");
}
else if (!Options.SkipSystemDetection)
{
VerboseLog($"Trying to detect system for drive {CurrentDrive.Name}.. ");
var currentSystem = GetRedumpSystem(CurrentDrive, Options.DefaultSystem) ?? Options.DefaultSystem;
VerboseLogLn(currentSystem == null ? "unable to detect." : ($"detected {currentSystem.LongName()}."));
var currentSystem = GetRedumpSystem(CurrentDrive);
if (currentSystem != null)
VerboseLogLn($"detected {currentSystem.LongName()}.");
// If undetected system on inactive drive, and PC is the default system, check for potential Mac disc
if (currentSystem == null && CurrentDrive.MarkedActive == false && Options.DefaultSystem == RedumpSystem.IBMPCcompatible)
{
try
{
// If disc is readable on inactive drive, assume it is a Mac disc
if (PhysicalTool.GetFirstBytes(CurrentDrive, 1) != null)
{
currentSystem = RedumpSystem.AppleMacintosh;
VerboseLogLn($"unable to detect, defaulting to {currentSystem.LongName()}.");
}
}
catch { }
}
// Fallback to default system only if drive is active
if (currentSystem == null && CurrentDrive.MarkedActive)
{
currentSystem = Options.DefaultSystem;
VerboseLogLn($"unable to detect, defaulting to {currentSystem.LongName()}.");
}
if (currentSystem != null)
{
@@ -1258,7 +1295,7 @@ namespace MPF.Frontend.ViewModels
else if (Options.SkipSystemDetection && Options.DefaultSystem != null)
{
var currentSystem = Options.DefaultSystem;
VerboseLogLn($"System detection disabled, setting to default of {currentSystem.LongName()}.");
VerboseLogLn($"System detection disabled, defaulting to {currentSystem.LongName()}.");
int sysIndex = Systems.FindIndex(s => s == currentSystem);
CurrentSystem = Systems[sysIndex];
}
@@ -1329,8 +1366,8 @@ namespace MPF.Frontend.ViewModels
// If we're in a type that doesn't support drive speeds
DriveSpeedComboBoxEnabled = _environment.DoesSupportDriveSpeed();
// If input params are not enabled, generate the full parameters from the environment
if (!ParametersCheckBoxEnabled)
// If input params are enabled, generate the full parameters from the environment
if (ParametersCheckBoxEnabled)
{
var generated = _environment.GetFullParameters(DriveSpeed);
if (generated != null)
@@ -1394,86 +1431,87 @@ namespace MPF.Frontend.ViewModels
return;
}
// Get the extension for the file for the next two statements
var extension = _environment?.GetDefaultExtension(CurrentMediaType);
// Get path pieces that are used in all branches
string defaultOutputPath = Options.DefaultOutputPath ?? "ISO";
string extension = _environment?.GetDefaultExtension(CurrentMediaType) ?? ".bin";
string label = GetFormattedVolumeLabel(CurrentDrive) ?? CurrentSystem.LongName() ?? "track";
string defaultFilename = $"{label}{extension}";
// Set the output filename, if it's not already
// If no path exists, set one using default values
if (string.IsNullOrEmpty(OutputPath))
{
var label = GetFormattedVolumeLabel(CurrentDrive) ?? CurrentSystem.LongName();
var directory = Options.DefaultOutputPath;
string filename = $"{label}{extension ?? ".bin"}";
// If the path ends with the label already
if (directory != null && label != null && directory.EndsWith(label, StringComparison.OrdinalIgnoreCase))
directory = Path.GetDirectoryName(directory);
if (directory != null && label != null)
#if NET20 || NET35
OutputPath = Path.Combine(Path.Combine(directory, label), filename);
OutputPath = Path.Combine(Path.Combine(defaultOutputPath, label), defaultFilename);
#else
OutputPath = Path.Combine(directory, label, filename);
OutputPath = Path.Combine(defaultOutputPath, label, defaultFilename);
#endif
else
OutputPath = filename;
return;
}
// For all other cases, separate the last path
string lastPath = FrontendTool.NormalizeOutputPaths(OutputPath, false);
string lastDirectory = Path.GetDirectoryName(lastPath) ?? string.Empty;
string lastFilename = Path.GetFileNameWithoutExtension(lastPath);
// Set the output filename, if we changed drives
else if (driveChanged)
if (driveChanged)
{
var label = GetFormattedVolumeLabel(CurrentDrive) ?? CurrentSystem.LongName();
string oldPath = FrontendTool.NormalizeOutputPaths(OutputPath, false);
string oldFilename = Path.GetFileNameWithoutExtension(oldPath);
var directory = Path.GetDirectoryName(oldPath);
string filename = $"{label}{extension ?? ".bin"}";
// If the previous path is exactly the default path and last filename
if (lastDirectory.EndsWith(Path.Combine(defaultOutputPath, lastFilename)))
lastDirectory = Path.GetDirectoryName(lastDirectory) ?? string.Empty;
// If the previous path included the label
if (directory != null && directory.EndsWith(oldFilename, StringComparison.OrdinalIgnoreCase))
directory = Path.GetDirectoryName(directory);
// If the path ends with the label already
if (directory != null && label != null && directory.EndsWith(label, StringComparison.OrdinalIgnoreCase))
directory = Path.GetDirectoryName(directory);
if (directory != null && label != null)
// Create the output path
if (lastDirectory == defaultOutputPath)
#if NET20 || NET35
OutputPath = Path.Combine(Path.Combine(directory, label), filename);
OutputPath = Path.Combine(Path.Combine(lastDirectory, label), defaultFilename);
#else
OutputPath = Path.Combine(directory, label, filename);
OutputPath = Path.Combine(lastDirectory, label, defaultFilename);
#endif
else
OutputPath = filename;
OutputPath = Path.Combine(lastDirectory, defaultFilename);
}
// Otherwise, reset the extension of the currently set path
else
{
string oldPath = FrontendTool.NormalizeOutputPaths(OutputPath, false);
string filename = Path.GetFileNameWithoutExtension(oldPath);
var directory = Path.GetDirectoryName(oldPath);
filename = $"{filename}{extension ?? ".bin"}";
if (directory != null)
OutputPath = Path.Combine(directory, filename);
else
OutputPath = filename;
lastFilename = $"{lastFilename}{extension}";
OutputPath = Path.Combine(lastDirectory, lastFilename);
}
}
/// <summary>
/// Get the current system from drive
/// </summary>
/// <param name="defaultValue"></param>
/// <returns></returns>
private static RedumpSystem? GetRedumpSystem(Drive? drive, RedumpSystem? defaultValue)
private static RedumpSystem? GetRedumpSystem(Drive? drive)
{
// If the drive does not exist, we can't do anything
if (drive == null)
return defaultValue;
if (drive == null || string.IsNullOrEmpty(drive.Name))
return null;
// If we can't read the media in that drive, we can't do anything
if (string.IsNullOrEmpty(drive.Name) || !Directory.Exists(drive.Name))
return defaultValue;
// If we can't read the files in the drive, we can only perform physical checks
if (drive.MarkedActive == false || !Directory.Exists(drive.Name))
{
try
{
// Check for Panasonic 3DO - filesystem not readable on Windows
RedumpSystem? detected3DOSystem = PhysicalTool.Detect3DOSystem(drive);
if (detected3DOSystem != null)
{
return detected3DOSystem;
}
// Sega Saturn / Sega Dreamcast / Sega Mega-CD / Sega-CD
RedumpSystem? detectedSegaSystem = PhysicalTool.DetectSegaSystem(drive);
if (detectedSegaSystem != null)
{
return detectedSegaSystem;
}
}
catch { }
// Otherwise, return null
return null;
}
// We're going to assume for floppies, HDDs, and removable drives
if (drive.InternalDriveType != InternalDriveType.Optical)
@@ -1552,6 +1590,12 @@ namespace MPF.Frontend.ViewModels
return RedumpSystem.MattelFisherPriceiXL;
}
// Memorex - Visual Information System
if (File.Exists(Path.Combine(drive.Name, "CONTROL.TAT")))
{
return RedumpSystem.MemorexVisualInformationSystem;
}
// Microsoft Xbox 360
try
{
@@ -1605,6 +1649,17 @@ namespace MPF.Frontend.ViewModels
}
catch { }
try
{
// Sega Saturn / Sega Dreamcast / Sega Mega-CD / Sega-CD
RedumpSystem? segaSystem = PhysicalTool.DetectSegaSystem(drive);
if (segaSystem != null)
{
return segaSystem;
}
}
catch { }
// Sega Dreamcast
if (File.Exists(Path.Combine(drive.Name, "IP.BIN")))
{
@@ -1627,6 +1682,19 @@ namespace MPF.Frontend.ViewModels
return RedumpSystem.SegaMegaCDSegaCD;
}
// SNK Neo-Geo CD
try
{
if (File.Exists(Path.Combine(drive.Name, "ABS.TXT"))
|| File.Exists(Path.Combine(drive.Name, "BIB.TXT"))
|| File.Exists(Path.Combine(drive.Name, "CPY.TXT"))
|| File.Exists(Path.Combine(drive.Name, "IPL.TXT")))
{
return RedumpSystem.SNKNeoGeoCD;
}
}
catch { }
// Sony PlayStation and Sony PlayStation 2
string psxExePath = Path.Combine(drive.Name, "PSX.EXE");
string systemCnfPath = Path.Combine(drive.Name, "SYSTEM.CNF");
@@ -1657,17 +1725,6 @@ namespace MPF.Frontend.ViewModels
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 NET20 || NET35
if (File.Exists(Path.Combine(Path.Combine(Path.Combine(drive.Name, "PS4"), "UPDATE"), "PS4UPDATE.PUP")))
#else
@@ -1677,16 +1734,60 @@ namespace MPF.Frontend.ViewModels
return RedumpSystem.SonyPlayStation4;
}
// Sony PlayStation 5
#if NET20 || NET35
if (File.Exists(Path.Combine(Path.Combine(Path.Combine(drive.Name, "PS5"), "UPDATE"), "PS5UPDATE.PUP")))
#else
if (File.Exists(Path.Combine(drive.Name, "PS5", "UPDATE", "PS5UPDATE.PUP")))
#endif
{
return RedumpSystem.SonyPlayStation5;
}
// V.Tech V.Flash / V.Smile Pro
if (File.Exists(Path.Combine(drive.Name, "0SYSTEM")))
{
return RedumpSystem.VTechVFlashVSmilePro;
}
// VM Labs NUON
#if NET20 || NET35
if (File.Exists(Path.Combine(Path.Combine(drive.Name, "NUON"), "nuon.run")))
#else
if (File.Exists(Path.Combine(drive.Name, "NUON", "nuon.run")))
#endif
{
return RedumpSystem.VMLabsNUON;
}
// ZAPit Games - GameWave
if (File.Exists(Path.Combine(drive.Name, "gamewave.diz")))
{
return RedumpSystem.ZAPiTGamesGameWaveFamilyEntertainmentSystem;
}
#endregion
#region Computers
// Amiga CD (Do this check AFTER CD32/CDTV)
if (File.Exists(Path.Combine(drive.Name, "Disk.info")))
{
return RedumpSystem.CommodoreAmigaCD;
}
// Fujitsu FM Towns
try
{
if (File.Exists(Path.Combine(drive.Name, "TMENU.EXP"))
|| File.Exists(Path.Combine(drive.Name, "TBIOS.SYS"))
|| File.Exists(Path.Combine(drive.Name, "TBIOS.BIN")))
{
return RedumpSystem.FujitsuFMTownsseries;
}
}
catch { }
// Sharp X68000
if (File.Exists(Path.Combine(drive.Name, "COMMAND.X")))
{
@@ -1757,7 +1858,7 @@ namespace MPF.Frontend.ViewModels
#endregion
// Default return
return defaultValue;
return null;
}
/// <summary>
@@ -1824,6 +1925,20 @@ namespace MPF.Frontend.ViewModels
var tempContent = Status;
Status = "Scanning for copy protection... this might take a while!";
// Disable UI elements
OptionsMenuItemEnabled = false;
SystemTypeComboBoxEnabled = false;
MediaTypeComboBoxEnabled = false;
OutputPathTextBoxEnabled = false;
OutputPathBrowseButtonEnabled = false;
DriveLetterComboBoxEnabled = false;
DriveSpeedComboBoxEnabled = false;
DumpingProgramComboBoxEnabled = false;
EnableParametersCheckBoxEnabled = false;
StartStopButtonEnabled = false;
MediaScanButtonEnabled = false;
UpdateVolumeLabelEnabled = false;
@@ -1836,14 +1951,8 @@ namespace MPF.Frontend.ViewModels
{
var protections = await ProtectionTool.RunProtectionScanOnPath(CurrentDrive.Name, Options, progress);
var output = ProtectionTool.FormatProtections(protections);
LogLn($"Detected the following protections in {CurrentDrive.Name}:\r\n\r\n{output}");
Status = tempContent;
StartStopButtonEnabled = ShouldEnableDumpingButton();
MediaScanButtonEnabled = true;
UpdateVolumeLabelEnabled = true;
CopyProtectScanButtonEnabled = true;
return output;
}
catch (Exception ex)
@@ -1851,6 +1960,29 @@ namespace MPF.Frontend.ViewModels
ErrorLogLn($"Path could not be scanned! Exception information:\r\n\r\n{ex}");
return null;
}
finally
{
// Reset the status
Status = tempContent;
// Enable UI elements
OptionsMenuItemEnabled = true;
SystemTypeComboBoxEnabled = true;
MediaTypeComboBoxEnabled = true;
OutputPathTextBoxEnabled = true;
OutputPathBrowseButtonEnabled = true;
DriveLetterComboBoxEnabled = true;
DriveSpeedComboBoxEnabled = true;
DumpingProgramComboBoxEnabled = true;
EnableParametersCheckBoxEnabled = true;
StartStopButtonEnabled = ShouldEnableDumpingButton();
MediaScanButtonEnabled = true;
UpdateVolumeLabelEnabled = true;
CopyProtectScanButtonEnabled = true;
}
}
/// <summary>
@@ -1874,7 +2006,7 @@ namespace MPF.Frontend.ViewModels
else
{
// No Volume Label found, fallback to something sensible
switch (GetRedumpSystem(drive, null))
switch (GetRedumpSystem(drive))
{
case RedumpSystem.SonyPlayStation:
case RedumpSystem.SonyPlayStation2:
@@ -1889,7 +2021,9 @@ namespace MPF.Frontend.ViewModels
}
foreach (char c in Path.GetInvalidFileNameChars())
{
volumeLabel = volumeLabel?.Replace(c, '_');
}
return volumeLabel;
}
@@ -1932,14 +2066,11 @@ namespace MPF.Frontend.ViewModels
public void SetSupportedDriveSpeed()
{
// Set the drive speed list that's appropriate
DriveSpeeds = (List<int>)InterfaceConstants.GetSpeedsForMediaType(CurrentMediaType);
DriveSpeeds = InterfaceConstants.GetSpeedsForMediaType(CurrentMediaType);
VerboseLogLn($"Supported media speeds: {string.Join(", ", [.. DriveSpeeds.ConvertAll(ds => ds.ToString())])}");
// Set the selected speed
int speed = FrontendTool.GetDefaultSpeedForMediaType(CurrentMediaType, Options);
VerboseLogLn($"Setting drive speed to: {speed}");
DriveSpeed = speed;
DriveSpeed = FrontendTool.GetDefaultSpeedForMediaType(CurrentMediaType, Options);
}
/// <summary>
@@ -1963,7 +2094,7 @@ namespace MPF.Frontend.ViewModels
if (CurrentMediaType == null || CurrentMediaType == MediaType.NONE)
return false;
return (CurrentProgram) switch
return CurrentProgram switch
{
// Aaru
InternalProgram.Aaru when CurrentMediaType == MediaType.BluRay => true,
@@ -1977,6 +2108,7 @@ namespace MPF.Frontend.ViewModels
InternalProgram.Aaru when CurrentMediaType == MediaType.HDDVD => true,
InternalProgram.Aaru when CurrentMediaType == MediaType.NintendoGameCubeGameDisc => true,
InternalProgram.Aaru when CurrentMediaType == MediaType.NintendoWiiOpticalDisc => true,
InternalProgram.Aaru when CurrentMediaType == MediaType.NintendoWiiUOpticalDisc => true,
InternalProgram.Aaru when CurrentMediaType == MediaType.SDCard => true,
// DiscImageCreator
@@ -1991,6 +2123,7 @@ namespace MPF.Frontend.ViewModels
InternalProgram.DiscImageCreator when CurrentMediaType == MediaType.HDDVD => true,
InternalProgram.DiscImageCreator when CurrentMediaType == MediaType.NintendoGameCubeGameDisc => true,
InternalProgram.DiscImageCreator when CurrentMediaType == MediaType.NintendoWiiOpticalDisc => true,
InternalProgram.DiscImageCreator when CurrentMediaType == MediaType.NintendoWiiUOpticalDisc => true,
InternalProgram.DiscImageCreator when CurrentMediaType == MediaType.SDCard => true,
// Redumper
@@ -1999,6 +2132,9 @@ namespace MPF.Frontend.ViewModels
InternalProgram.Redumper when CurrentMediaType == MediaType.DVD => true,
InternalProgram.Redumper when CurrentMediaType == MediaType.GDROM => true,
InternalProgram.Redumper when CurrentMediaType == MediaType.HDDVD => true,
InternalProgram.Redumper when CurrentMediaType == MediaType.NintendoGameCubeGameDisc => true,
InternalProgram.Redumper when CurrentMediaType == MediaType.NintendoWiiOpticalDisc => true,
InternalProgram.Redumper when CurrentMediaType == MediaType.NintendoWiiUOpticalDisc => true,
// Default
_ => false,
@@ -2017,12 +2153,12 @@ namespace MPF.Frontend.ViewModels
_environment.RefreshDrive();
// If still in custom parameter mode, check that users meant to continue or not
if (ParametersCheckBoxEnabled == true && _displayUserMessage != null)
if (ParametersCheckBoxEnabled == false && _displayUserMessage != null)
{
bool? result = _displayUserMessage("Custom Changes", "It looks like you have custom parameters that have not been saved. Would you like to apply those changes before starting to dump?", 3, true);
if (result == true)
{
ParametersCheckBoxEnabled = false;
ParametersCheckBoxEnabled = true;
ProcessCustomParameters();
}
else if (result == null)
@@ -2032,9 +2168,6 @@ namespace MPF.Frontend.ViewModels
// If false, then we continue with the current known environment
}
// Run path adjustments for DiscImageCreator -- Disabled until further notice
//Env.AdjustPathsForDiscImageCreator();
try
{
// Run pre-dumping validation checks
@@ -2076,7 +2209,10 @@ namespace MPF.Frontend.ViewModels
// Verify dump output and save it
if (result)
{
result = await _environment.VerifyAndSaveDumpOutput(resultProgress, protectionProgress, _processUserInfo);
result = await _environment.VerifyAndSaveDumpOutput(
resultProgress,
protectionProgress,
_processUserInfo);
}
else
{
@@ -2101,13 +2237,19 @@ namespace MPF.Frontend.ViewModels
/// </summary>
public void ToggleParameters()
{
if (ParametersCheckBoxEnabled == true)
if (ParametersCheckBoxEnabled == false)
{
OptionsMenuItemEnabled = false;
SystemTypeComboBoxEnabled = false;
MediaTypeComboBoxEnabled = false;
OutputPathTextBoxEnabled = false;
OutputPathBrowseButtonEnabled = false;
DriveLetterComboBoxEnabled = false;
DriveSpeedComboBoxEnabled = false;
DumpingProgramComboBoxEnabled = false;
ParametersTextBoxEnabled = true;
MediaScanButtonEnabled = false;
UpdateVolumeLabelEnabled = false;
@@ -2117,11 +2259,17 @@ namespace MPF.Frontend.ViewModels
{
ProcessCustomParameters();
OptionsMenuItemEnabled = true;
SystemTypeComboBoxEnabled = true;
MediaTypeComboBoxEnabled = true;
OutputPathTextBoxEnabled = true;
OutputPathBrowseButtonEnabled = true;
DriveLetterComboBoxEnabled = true;
DriveSpeedComboBoxEnabled = true;
DumpingProgramComboBoxEnabled = true;
ParametersTextBoxEnabled = false;
MediaScanButtonEnabled = true;
UpdateVolumeLabelEnabled = true;
@@ -2166,9 +2314,9 @@ namespace MPF.Frontend.ViewModels
var outputDirectory = Path.GetDirectoryName(_environment!.OutputPath);
string outputFilename = Path.GetFileName(_environment.OutputPath);
// If a complete dump already exists
bool foundFiles = _environment.FoundAllFiles(outputDirectory, outputFilename);
if (foundFiles && _displayUserMessage != null)
// If a complete or partial dump already exists
bool foundAllFiles = _environment.FoundAllFiles(outputDirectory, outputFilename);
if (foundAllFiles && _displayUserMessage != null)
{
bool? mbresult = _displayUserMessage("Overwrite?", "A complete dump already exists! Are you sure you want to overwrite?", 2, true);
if (mbresult != true)
@@ -2179,17 +2327,45 @@ namespace MPF.Frontend.ViewModels
}
else
{
// If a complete dump exists from a different program
InternalProgram? programFound = _environment.CheckForMatchingProgram(outputDirectory, outputFilename);
if (programFound != null && _displayUserMessage != null)
// If a partial dump exists
bool foundAnyFiles = _environment.FoundAnyFiles(outputDirectory, outputFilename);
if (foundAnyFiles && _displayUserMessage != null)
{
bool? mbresult = _displayUserMessage("Overwrite?", $"A complete dump from {programFound} already exists! Dumping here may cause issues. Are you sure you want to overwrite?", 2, true);
bool? mbresult = _displayUserMessage("Overwrite?", $"A partial dump already exists! Dumping here may cause issues. Are you sure you want to overwrite?", 2, true);
if (mbresult != true)
{
LogLn("Dumping aborted!");
return false;
}
}
else
{
// If a complete dump exists from a different program
InternalProgram? completeProgramFound = _environment.CheckForMatchingProgram(outputDirectory, outputFilename);
if (completeProgramFound != null && _displayUserMessage != null)
{
bool? mbresult = _displayUserMessage("Overwrite?", $"A complete dump from {completeProgramFound} already exists! Dumping here may cause issues. Are you sure you want to overwrite?", 2, true);
if (mbresult != true)
{
LogLn("Dumping aborted!");
return false;
}
}
else
{
// If a partial dump exists from a different program
InternalProgram? partialProgramFound = _environment.CheckForPartialProgram(outputDirectory, outputFilename);
if (partialProgramFound != null && _displayUserMessage != null)
{
bool? mbresult = _displayUserMessage("Overwrite?", $"A partial dump from {partialProgramFound} already exists! Dumping here may cause issues. Are you sure you want to overwrite?", 2, true);
if (mbresult != true)
{
LogLn("Dumping aborted!");
return false;
}
}
}
}
}
// Validate that at least some space exists
@@ -2263,9 +2439,9 @@ namespace MPF.Frontend.ViewModels
// Update the label with only the first line of output
if (message != null && message.Contains("\n"))
Status = value?.Message?.Split('\n')[0] + " (See log output)";
Status = message.Split('\n')[0] + " (See log output)";
else
Status = value?.Message ?? string.Empty;
Status = message ?? string.Empty;
// Log based on success or failure
if (value != null && value)

View File

@@ -0,0 +1,379 @@
using System;
using System.IO;
using SabreTools.RedumpLib.Data;
using Schemas;
using Xunit;
#pragma warning disable CS0618 // Ignore "Type or member is obsolete"
namespace MPF.Processors.Test
{
// TODO: Add tests around remaining helper methods
public class AaruTests
{
#region GetOutputFiles
[Fact]
public void GetOutputFiles_Null_Empty()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, null);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Empty(actual);
}
[Fact]
public void GetOutputFiles_CDROM_Populated()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Equal(8, actual.Count);
}
[Fact]
public void GetOutputFiles_DVD_Populated()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.DVD);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Equal(7, actual.Count);
}
[Fact]
public void GetOutputFiles_HDDVD_Populated()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.HDDVD);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Equal(7, actual.Count);
}
[Fact]
public void GetOutputFiles_BluRay_Populated()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.BluRay);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Equal(7, actual.Count);
}
[Fact]
public void GetOutputFiles_Other_Empty()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.ApertureCard);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Empty(actual);
}
#endregion
#region FoundAllFiles
[Fact]
public void FoundAllFiles_Invalid_Filled()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
Assert.Equal(7, actual.Count);
}
[Fact]
public void FoundAllFiles_Valid_Empty()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Aaru", "CDROM");
string outputFilename = "test.aaruf";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
Assert.Empty(actual);
}
#endregion
#region FoundAnyFiles
[Fact]
public void FoundAnyFiles_Invalid_Filled()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
Assert.False(actual);
}
[Fact]
public void FoundAnyFiles_Valid_Empty()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Aaru", "CDROM");
string outputFilename = "test.aaruf";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
Assert.True(actual);
}
#endregion
#region GenerateArtifacts
[Fact]
public void GenerateArtifacts_Invalid_Empty()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
Assert.Empty(actual);
}
[Fact]
public void GenerateArtifacts_Valid_Filled()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Aaru", "CDROM");
string outputFilename = "test.aaruf";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
Assert.Equal(7, actual.Count);
}
#endregion
#region GetDeleteableFilePaths
[Fact]
public void GetDeleteableFilePaths_Invalid_Empty()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
Assert.Empty(actual);
}
[Fact]
public void GetDeleteableFilePaths_Valid_Empty()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Aaru", "CDROM");
string outputFilename = "test.aaruf";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
Assert.Empty(actual);
}
#endregion
#region GetZippableFilePaths
[Fact]
public void GetZippableFilePaths_Invalid_Empty()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
Assert.Empty(actual);
}
[Fact]
public void GetZippableFilePaths_Valid_Filled()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Aaru", "CDROM");
string outputFilename = "test.aaruf";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
Assert.Equal(7, actual.Count);
}
#endregion
#region GenerateCuesheet
[Fact]
public void GenerateCuesheet_Null_Null()
{
CICMMetadataType? cicmSidecar = null;
string basePath = "test";
string? actual = Aaru.GenerateCuesheet(cicmSidecar, basePath);
Assert.Null(actual);
}
[Fact]
public void GenerateCuesheet_Empty_Null()
{
CICMMetadataType? cicmSidecar = new CICMMetadataType();
string basePath = "test";
string? actual = Aaru.GenerateCuesheet(cicmSidecar, basePath);
Assert.Null(actual);
}
[Fact]
public void GenerateCuesheet_Valid_Filled()
{
TrackType trackType = new TrackType
{
BytesPerSector = 2352,
Flags = new TrackFlagsType { Quadraphonic = true },
Indexes = [new TrackIndexType { index = 1, Value = 0 }],
ISRC = "isrc",
Sequence = new TrackSequenceType { TrackNumber = 1 },
TrackType1 = TrackTypeTrackType.mode1,
};
OpticalDiscType opticalDiscType = new OpticalDiscType
{
DiscType = "CD-ROM",
MediaCatalogueNumber = "mcn",
Track = [trackType],
Tracks = [1],
};
CICMMetadataType? cicmSidecar = new CICMMetadataType
{
OpticalDisc = [opticalDiscType],
Performer = ["performer"],
};
string basePath = "test";
string? actual = Aaru.GenerateCuesheet(cicmSidecar, basePath);
// TODO: Unexpected outcome -- Non-null but empty cuesheet generated
// TODO: Add structure validation
Assert.NotNull(actual);
}
#endregion
#region GenerateDatafile
[Fact]
public void GenerateDatafile_Null_Null()
{
CICMMetadataType? cicmSidecar = null;
string basePath = "test";
var actual = Aaru.GenerateDatafile(cicmSidecar, basePath);
Assert.Null(actual);
}
[Fact]
public void GenerateDatafile_Empty_Null()
{
CICMMetadataType? cicmSidecar = new CICMMetadataType();
string basePath = "test";
var actual = Aaru.GenerateDatafile(cicmSidecar, basePath);
Assert.Null(actual);
}
[Fact]
public void GenerateDatafile_Valid_Filled()
{
TrackType trackType = new TrackType
{
Checksums =
[
new ChecksumType { type = ChecksumTypeType.crc32, Value = "00000000" },
new ChecksumType { type = ChecksumTypeType.md5, Value = "d41d8cd98f00b204e9800998ecf8427e" },
new ChecksumType { type = ChecksumTypeType.sha1, Value = "da39a3ee5e6b4b0d3255bfef95601890afd80709" },
],
Sequence = new TrackSequenceType { TrackNumber = 1 },
Size = 12345,
};
OpticalDiscType opticalDiscType = new OpticalDiscType
{
DiscType = "CD-ROM",
MediaCatalogueNumber = "mcn",
Track = [trackType],
Tracks = [1],
};
CICMMetadataType? cicmSidecar = new CICMMetadataType
{
OpticalDisc = [opticalDiscType],
};
string basePath = "test";
var actual = Aaru.GenerateDatafile(cicmSidecar, basePath);
// TODO: Add structure validation
Assert.NotNull(actual);
}
#endregion
#region GeneratePVD
[Fact]
public void GeneratePVD_Null_Null()
{
CICMMetadataType? cicmSidecar = null;
var actual = Aaru.GeneratePVD(cicmSidecar);
Assert.Null(actual);
}
[Fact]
public void GeneratePVD_Empty_Null()
{
CICMMetadataType? cicmSidecar = new CICMMetadataType();
var actual = Aaru.GeneratePVD(cicmSidecar);
Assert.Null(actual);
}
[Fact]
public void GeneratePVD_Valid_Filled()
{
FileSystemType fileSystemType = new FileSystemType
{
CreationDate = DateTime.UtcNow,
CreationDateSpecified = true,
ModificationDate = DateTime.UtcNow,
ModificationDateSpecified = true,
ExpirationDate = DateTime.UtcNow,
ExpirationDateSpecified = true,
EffectiveDate = DateTime.UtcNow,
EffectiveDateSpecified = true,
};
PartitionType partitionType = new PartitionType
{
FileSystems = [fileSystemType],
};
TrackType trackType = new TrackType
{
FileSystemInformation = [partitionType],
};
OpticalDiscType opticalDiscType = new OpticalDiscType
{
Track = [trackType],
};
CICMMetadataType? cicmSidecar = new CICMMetadataType
{
OpticalDisc = [opticalDiscType],
};
string? actual = Aaru.GeneratePVD(cicmSidecar);
// TODO: Add structure validation
Assert.NotNull(actual);
}
#endregion
}
}

View File

@@ -0,0 +1,205 @@
using System;
using System.IO;
using Xunit;
namespace MPF.Processors.Test
{
public class BaseProcessorTests
{
#region GetGeneratedFilenames
[Fact]
public void GetGeneratedFilenames_NullSuffix_Standard()
{
string? filenameSuffix = null;
var actual = BaseProcessor.GetGeneratedFilenames(filenameSuffix);
Assert.Equal(4, actual.Count);
Assert.Equal("!protectionInfo.txt", actual[0]);
Assert.Equal("!submissionInfo.json", actual[1]);
Assert.Equal("!submissionInfo.json.gz", actual[2]);
Assert.Equal("!submissionInfo.txt", actual[3]);
}
[Fact]
public void GetGeneratedFilenames_EmptySuffix_Standard()
{
string? filenameSuffix = string.Empty;
var actual = BaseProcessor.GetGeneratedFilenames(filenameSuffix);
Assert.Equal(4, actual.Count);
Assert.Equal("!protectionInfo.txt", actual[0]);
Assert.Equal("!submissionInfo.json", actual[1]);
Assert.Equal("!submissionInfo.json.gz", actual[2]);
Assert.Equal("!submissionInfo.txt", actual[3]);
}
[Fact]
public void GetGeneratedFilenames_ValidSuffix_Modified()
{
string? filenameSuffix = "suffix";
var actual = BaseProcessor.GetGeneratedFilenames(filenameSuffix);
Assert.Equal(4, actual.Count);
Assert.Equal("!protectionInfo_suffix.txt", actual[0]);
Assert.Equal("!submissionInfo_suffix.json", actual[1]);
Assert.Equal("!submissionInfo_suffix.json.gz", actual[2]);
Assert.Equal("!submissionInfo_suffix.txt", actual[3]);
}
#endregion
#region GetGeneratedFilePaths
[Fact]
public void GetGeneratedFilePaths_NulloutputDirectory_Empty()
{
string? outputDirectory = null;
var actual = BaseProcessor.GetGeneratedFilePaths(outputDirectory, filenameSuffix: null);
Assert.Empty(actual);
}
[Fact]
public void GetGeneratedFilePaths_EmptyoutputDirectory_Empty()
{
string? outputDirectory = string.Empty;
var actual = BaseProcessor.GetGeneratedFilePaths(outputDirectory, filenameSuffix: null);
Assert.Empty(actual);
}
[Fact]
public void GetGeneratedFilePaths_InvalidoutputDirectory_Empty()
{
string? outputDirectory = "INVALID";
var actual = BaseProcessor.GetGeneratedFilePaths(outputDirectory, filenameSuffix: null);
Assert.Empty(actual);
}
[Fact]
public void GetGeneratedFilePaths_ValidoutputDirectory_Empty()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "BaseProcessor");
var actual = BaseProcessor.GetGeneratedFilePaths(outputDirectory, filenameSuffix: null);
Assert.Equal(4, actual.Count);
}
#endregion
#region GetPIC
[Fact]
public void GetPIC_InvalidPath_Null()
{
string picPath = "INVALID";
int trimLength = -1;
string? actual = BaseProcessor.GetPIC(picPath, trimLength);
Assert.Null(actual);
}
[Fact]
public void GetPIC_ValidPathZeroTrim_Empty()
{
string picPath = Path.Combine(Environment.CurrentDirectory, "TestData", "BaseProcessor", "pic.bin");
int trimLength = 0;
string? actual = BaseProcessor.GetPIC(picPath, trimLength);
Assert.NotNull(actual);
Assert.Empty(actual);
}
[Fact]
public void GetPIC_ValidPathDefaultTrim_Formatted()
{
string expected = "000102030405060708090A0B0C0D0E0F\n000102030405060708090A0B0C0D0E0F\n000102030405060708090A0B0C0D0E0F\n000102030405060708090A0B0C0D0E0F\n000102030405060708090A0B0C0D0E0F\n000102030405060708090A0B0C0D0E0F\n000102030405060708090A0B0C0D0E0F\n000102030405060708090A0B0C0D0E0F\n000102030405060708090A0B0C0D0E0F\n000102030405060708090A0B0C0D0E0F\n";
string picPath = Path.Combine(Environment.CurrentDirectory, "TestData", "BaseProcessor", "pic.bin");
int trimLength = -1;
string? actual = BaseProcessor.GetPIC(picPath, trimLength);
Assert.NotNull(actual);
Assert.Equal(expected, actual);
}
[Fact]
public void GetPIC_ValidPathCustomTrim_Formatted()
{
string expected = "000102030405060708090A0B0C0D0E0F\n";
string picPath = Path.Combine(Environment.CurrentDirectory, "TestData", "BaseProcessor", "pic.bin");
int trimLength = 32;
string? actual = BaseProcessor.GetPIC(picPath, trimLength);
Assert.NotNull(actual);
Assert.Equal(expected, actual);
}
#endregion
#region GetPVD
// TODO: Create fake, 00-filled ISO for tests and implement
#endregion
#region SplitString
[Fact]
public void SplitString_NullString_Empty()
{
string? str = null;
int count = 0;
bool trim = false;
string actual = BaseProcessor.SplitString(str, count, trim);
Assert.Empty(actual);
}
[Fact]
public void SplitString_EmptyString_Empty()
{
string? str = string.Empty;
int count = 0;
bool trim = false;
string actual = BaseProcessor.SplitString(str, count, trim);
Assert.Empty(actual);
}
[Fact]
public void SplitString_ValidStringInvalidCount_Original()
{
string expected = "VALID\n";
string? str = "VALID";
int count = 0;
bool trim = false;
string actual = BaseProcessor.SplitString(str, count, trim);
Assert.Equal(expected, actual);
}
[Fact]
public void SplitString_ValidStringLessThanCount_Original()
{
string expected = "VALID\n";
string? str = "VALID";
int count = 10;
bool trim = false;
string actual = BaseProcessor.SplitString(str, count, trim);
Assert.Equal(expected, actual);
}
[Fact]
public void SplitString_ValidStringGreaterThanCount_Split()
{
string expected = "VA\nLI\nD\n";
string? str = "VALID";
int count = 2;
bool trim = false;
string actual = BaseProcessor.SplitString(str, count, trim);
Assert.Equal(expected, actual);
}
#endregion
}
}

View File

@@ -0,0 +1,321 @@
using System;
using System.IO;
using SabreTools.RedumpLib.Data;
using Xunit;
namespace MPF.Processors.Test
{
public class CleanRipTests
{
#region GetOutputFiles
[Fact]
public void GetOutputFiles_Null_Empty()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, null);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Empty(actual);
}
[Fact]
public void GetOutputFiles_DVD_Populated()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Equal(3, actual.Count);
}
[Fact]
public void GetOutputFiles_NintendoGameCubeGameDisc_Populated()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Equal(3, actual.Count);
}
[Fact]
public void GetOutputFiles_NintendoWiiOpticalDisc_Populated()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.NintendoWiiOpticalDisc);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Equal(3, actual.Count);
}
[Fact]
public void GetOutputFiles_Other_Empty()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.ApertureCard);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Empty(actual);
}
#endregion
#region FoundAllFiles
[Fact]
public void FoundAllFiles_Invalid_Filled()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
Assert.Equal(3, actual.Count);
}
[Fact]
public void FoundAllFiles_Valid_Empty()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD");
string outputFilename = "test.iso";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
Assert.Empty(actual);
}
#endregion
#region FoundAnyFiles
[Fact]
public void FoundAnyFiles_Invalid_Filled()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
Assert.False(actual);
}
[Fact]
public void FoundAnyFiles_Valid_Empty()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD");
string outputFilename = "test.iso";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
Assert.True(actual);
}
#endregion
#region GenerateArtifacts
[Fact]
public void GenerateArtifacts_Invalid_Empty()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
Assert.Empty(actual);
}
[Fact]
public void GenerateArtifacts_Valid_Filled()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD");
string outputFilename = "test.iso";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
Assert.Equal(2, actual.Count);
}
#endregion
#region GetDeleteableFilePaths
[Fact]
public void GetDeleteableFilePaths_Invalid_Empty()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
Assert.Empty(actual);
}
[Fact]
public void GetDeleteableFilePaths_Valid_Empty()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD");
string outputFilename = "test.iso";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
Assert.Empty(actual);
}
#endregion
#region GetZippableFilePaths
[Fact]
public void GetZippableFilePaths_Invalid_Empty()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
Assert.Empty(actual);
}
[Fact]
public void GetZippableFilePaths_Valid_Filled()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD");
string outputFilename = "test.iso";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
Assert.Equal(2, actual.Count);
}
#endregion
#region GenerateCleanripDatafile
[Fact]
public void GenerateCleanripDatafile_NoIsoNoDumpinfo_Null()
{
string iso = "INVALID";
string dumpinfo = "INVALID";
var actual = CleanRip.GenerateCleanripDatafile(iso, dumpinfo);
Assert.Null(actual);
}
[Fact]
public void GenerateCleanripDatafile_IsoOnly_Filled()
{
string iso = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD", "test.iso");
string dumpinfo = "INVALID";
var actual = CleanRip.GenerateCleanripDatafile(iso, dumpinfo);
Assert.NotNull(actual);
Assert.NotNull(actual.Game);
var game = Assert.Single(actual.Game);
Assert.NotNull(game.Rom);
var rom = Assert.Single(game.Rom);
Assert.Equal("9", rom.Size);
Assert.Equal("560b9f59", rom.CRC);
Assert.Equal("edbb6676247e65c2245dd4883ed9fc24", rom.MD5);
Assert.Equal("1b33ad54d78085be5ecb1cf1b3e9da821e708075", rom.SHA1);
}
[Fact]
public void GenerateCleanripDatafile_DumpinfoOnly_Filled()
{
string iso = "INVALID";
string dumpinfo = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD", "test-dumpinfo.txt");
var actual = CleanRip.GenerateCleanripDatafile(iso, dumpinfo);
Assert.NotNull(actual);
Assert.NotNull(actual.Game);
var game = Assert.Single(actual.Game);
Assert.NotNull(game.Rom);
var rom = Assert.Single(game.Rom);
Assert.Equal("-1", rom.Size);
Assert.Equal("00000000", rom.CRC);
Assert.Equal("d41d8cd98f00b204e9800998ecf8427e", rom.MD5);
Assert.Equal("da39a3ee5e6b4b0d3255bfef95601890afd80709", rom.SHA1);
}
[Fact]
public void GenerateCleanripDatafile_BothValid_Filled()
{
string iso = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD", "test.iso");
string dumpinfo = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD", "test-dumpinfo.txt");
var actual = CleanRip.GenerateCleanripDatafile(iso, dumpinfo);
Assert.NotNull(actual);
Assert.NotNull(actual.Game);
var game = Assert.Single(actual.Game);
Assert.NotNull(game.Rom);
var rom = Assert.Single(game.Rom);
Assert.Equal("9", rom.Size);
Assert.Equal("00000000", rom.CRC);
Assert.Equal("d41d8cd98f00b204e9800998ecf8427e", rom.MD5);
Assert.Equal("da39a3ee5e6b4b0d3255bfef95601890afd80709", rom.SHA1);
}
#endregion
#region GetBCA
[Fact]
public void GetBCA_InvalidPath_Null()
{
string bcaPath = "INVALID";
string? actual = CleanRip.GetBCA(bcaPath);
Assert.Null(actual);
}
[Fact]
public void GetBCA_ValidPath_Formatted()
{
string expected = "0001 0203 0405 0607 0809 0A0B 0C0D 0E0F\n0001 0203 0405 0607 0809 0A0B 0C0D 0E0F\n0001 0203 0405 0607 0809 0A0B 0C0D 0E0F\n0001 0203 0405 0607 0809 0A0B 0C0D 0E0F\n0001 0203 0405 0607 0809 0A0B 0C0D 0E0F\n0001 0203 0405 0607 0809 0A0B 0C0D 0E0F\n0001 0203 0405 0607 0809 0A0B 0C0D 0E0F\n0001 0203 0405 0607 0809 0A0B 0C0D 0E0F\n0001 0203 0405 0607 0809 0A0B 0C0D 0E0F\n0001 0203 0405 0607 0809 0A0B 0C0D 0E0F\n";
string bcaPath = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD", "test.bca");
string? actual = CleanRip.GetBCA(bcaPath);
Assert.NotNull(actual);
Assert.Equal(expected, actual);
}
#endregion
#region GetGameCubeWiiInformation
[Fact]
public void GetGameCubeWiiInformation_NoFile_False()
{
string dumpinfo = string.Empty;
bool actual = CleanRip.GetGameCubeWiiInformation(dumpinfo, out Region? region, out string? version, out string? name, out string? serial);
Assert.False(actual);
Assert.Null(region);
Assert.Null(version);
Assert.Null(name);
Assert.Null(serial);
}
[Fact]
public void GetGameCubeWiiInformation_Filled_True()
{
Region? expectedRegion = Region.World;
string? expectedVersion = "version";
string? expectedName = "name";
string? expectedSerial = "000A00";
string dumpinfo = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD", "test-dumpinfo.txt");
bool actual = CleanRip.GetGameCubeWiiInformation(dumpinfo, out Region? region, out string? version, out string? name, out string? serial);
Assert.True(actual);
Assert.Equal(expectedRegion, region);
Assert.Equal(expectedVersion, version);
Assert.Equal(expectedName, name);
Assert.Equal(expectedSerial, serial);
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0;net9.0</TargetFrameworks>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<None Remove="TestData\*" />
</ItemGroup>
<ItemGroup>
<Content Include="TestData\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MPF.Processors\MPF.Processors.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeCoverage" Version="17.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.4" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
<PackageReference Include="xunit.analyzers" Version="1.18.0" />
<PackageReference Include="xunit.assert" Version="2.9.2" />
<PackageReference Include="xunit.core" Version="2.9.2" />
<PackageReference Include="xunit.extensibility.core" Version="2.9.2" />
<PackageReference Include="xunit.extensibility.execution" Version="2.9.2" />
<PackageReference Include="xunit.runner.console" Version="2.9.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,213 @@
using System;
using System.IO;
using Xunit;
namespace MPF.Processors.Test
{
public class OutputFileTests
{
#region Properties
[Theory]
[InlineData(OutputFileFlags.None, false)]
[InlineData(OutputFileFlags.Required, true)]
[InlineData(OutputFileFlags.Artifact, false)]
[InlineData(OutputFileFlags.Binary, false)]
[InlineData(OutputFileFlags.Deleteable, false)]
[InlineData(OutputFileFlags.Zippable, false)]
public void IsRequiredTest(OutputFileFlags flags, bool expected)
{
var of = new OutputFile("file", flags, "key");
var cof = new CustomOutputFile("file", flags, "key", File.Exists);
var rof = new RegexOutputFile("file", flags, "key");
Assert.Equal(expected, of.IsRequired);
Assert.Equal(expected, cof.IsRequired);
Assert.Equal(expected, rof.IsRequired);
}
[Theory]
[InlineData(OutputFileFlags.None, false)]
[InlineData(OutputFileFlags.Required, false)]
[InlineData(OutputFileFlags.Artifact, true)]
[InlineData(OutputFileFlags.Binary, true)]
[InlineData(OutputFileFlags.Deleteable, false)]
[InlineData(OutputFileFlags.Zippable, false)]
public void IsArtifactTest(OutputFileFlags flags, bool expected)
{
var of = new OutputFile("file", flags, "key");
var cof = new CustomOutputFile("file", flags, "key", File.Exists);
var rof = new RegexOutputFile("file", flags, "key");
Assert.Equal(expected, of.IsArtifact);
Assert.Equal(expected, cof.IsArtifact);
Assert.Equal(expected, rof.IsArtifact);
}
[Theory]
[InlineData(OutputFileFlags.None, false)]
[InlineData(OutputFileFlags.Required, false)]
[InlineData(OutputFileFlags.Artifact, false)]
[InlineData(OutputFileFlags.Binary, true)]
[InlineData(OutputFileFlags.Deleteable, false)]
[InlineData(OutputFileFlags.Zippable, false)]
public void IsBinaryArtifactTest(OutputFileFlags flags, bool expected)
{
var of = new OutputFile("file", flags, "key");
var cof = new CustomOutputFile("file", flags, "key", File.Exists);
var rof = new RegexOutputFile("file", flags, "key");
Assert.Equal(expected, of.IsBinaryArtifact);
Assert.Equal(expected, cof.IsBinaryArtifact);
Assert.Equal(expected, rof.IsBinaryArtifact);
}
[Theory]
[InlineData(OutputFileFlags.None, false)]
[InlineData(OutputFileFlags.Required, false)]
[InlineData(OutputFileFlags.Artifact, false)]
[InlineData(OutputFileFlags.Binary, false)]
[InlineData(OutputFileFlags.Deleteable, true)]
[InlineData(OutputFileFlags.Zippable, false)]
public void IsDeleteableTest(OutputFileFlags flags, bool expected)
{
var of = new OutputFile("file", flags, "key");
var cof = new CustomOutputFile("file", flags, "key", File.Exists);
var rof = new RegexOutputFile("file", flags, "key");
Assert.Equal(expected, of.IsDeleteable);
Assert.Equal(expected, cof.IsDeleteable);
Assert.Equal(expected, rof.IsDeleteable);
}
[Theory]
[InlineData(OutputFileFlags.None, false)]
[InlineData(OutputFileFlags.Required, false)]
[InlineData(OutputFileFlags.Artifact, false)]
[InlineData(OutputFileFlags.Binary, false)]
[InlineData(OutputFileFlags.Deleteable, false)]
[InlineData(OutputFileFlags.Zippable, true)]
public void IsZippableTest(OutputFileFlags flags, bool expected)
{
var of = new OutputFile("file", flags, "key");
var cof = new CustomOutputFile("file", flags, "key", File.Exists);
var rof = new RegexOutputFile("file", flags, "key");
Assert.Equal(expected, of.IsZippable);
Assert.Equal(expected, cof.IsZippable);
Assert.Equal(expected, rof.IsZippable);
}
#endregion
#region Exists
[Fact]
public void Exists_Empty_False()
{
string outputDirectory = string.Empty;
var of = new OutputFile("pic.bin", OutputFileFlags.None, "key");
var cof = new CustomOutputFile("pic.bin", OutputFileFlags.None, "key", File.Exists);
var rof = new RegexOutputFile("pic.bin", OutputFileFlags.None, "key");
bool ofActual = of.Exists(outputDirectory);
bool cofActual = cof.Exists(outputDirectory);
bool rofActual = rof.Exists(outputDirectory);
Assert.False(ofActual);
Assert.False(cofActual);
Assert.False(rofActual);
}
[Fact]
public void Exists_Invalid_False()
{
string outputDirectory = "INVALID";
var of = new OutputFile("pic.bin", OutputFileFlags.None, "key");
var cof = new CustomOutputFile("pic.bin", OutputFileFlags.None, "key", File.Exists);
var rof = new RegexOutputFile("pic.bin", OutputFileFlags.None, "key");
bool ofActual = of.Exists(outputDirectory);
bool cofActual = cof.Exists(outputDirectory);
bool rofActual = rof.Exists(outputDirectory);
Assert.False(ofActual);
Assert.False(cofActual);
Assert.False(rofActual);
}
[Fact]
public void Exists_Valid_True()
{
string outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "BaseProcessor");
var of = new OutputFile("pic.bin", OutputFileFlags.None, "key");
var cof = new CustomOutputFile("pic.bin", OutputFileFlags.None, "key", File.Exists);
var rof = new RegexOutputFile("pic.bin", OutputFileFlags.None, "key");
bool ofActual = of.Exists(outputDirectory);
bool cofActual = cof.Exists(outputDirectory);
bool rofActual = rof.Exists(outputDirectory);
Assert.True(ofActual);
Assert.True(cofActual);
Assert.True(rofActual);
}
#endregion
#region GetPaths
[Fact]
public void GetPaths_Empty_Empty()
{
string outputDirectory = string.Empty;
var of = new OutputFile("pic.bin", OutputFileFlags.None, "key");
var cof = new CustomOutputFile("pic.bin", OutputFileFlags.None, "key", File.Exists);
var rof = new RegexOutputFile("pic.bin", OutputFileFlags.None, "key");
var ofActual = of.GetPaths(outputDirectory);
var cofActual = cof.GetPaths(outputDirectory);
var rofActual = rof.GetPaths(outputDirectory);
Assert.Empty(ofActual);
Assert.Empty(cofActual);
Assert.Empty(rofActual);
}
[Fact]
public void GetPaths_Invalid_Empty()
{
string outputDirectory = "INVALID";
var of = new OutputFile("pic.bin", OutputFileFlags.None, "key");
var cof = new CustomOutputFile("pic.bin", OutputFileFlags.None, "key", File.Exists);
var rof = new RegexOutputFile("pic.bin", OutputFileFlags.None, "key");
var ofActual = of.GetPaths(outputDirectory);
var cofActual = cof.GetPaths(outputDirectory);
var rofActual = rof.GetPaths(outputDirectory);
Assert.Empty(ofActual);
Assert.Empty(cofActual);
Assert.Empty(rofActual);
}
[Fact]
public void GetPaths_Valid_Filled()
{
string outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "BaseProcessor");
var of = new OutputFile("pic.bin", OutputFileFlags.None, "key");
var cof = new CustomOutputFile("pic.bin", OutputFileFlags.None, "key", File.Exists);
var rof = new RegexOutputFile("pic.bin", OutputFileFlags.None, "key");
var ofActual = of.GetPaths(outputDirectory);
var cofActual = cof.GetPaths(outputDirectory);
var rofActual = rof.GetPaths(outputDirectory);
Assert.Single(ofActual);
Assert.Single(cofActual);
Assert.Single(rofActual);
}
#endregion
}
}

View File

@@ -0,0 +1,205 @@
using System;
using System.IO;
using SabreTools.Models.Logiqx;
using SabreTools.RedumpLib.Data;
using Xunit;
namespace MPF.Processors.Test
{
public class PS3CFWTests
{
#region GetOutputFiles
[Fact]
public void GetOutputFiles_Null_Empty()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, null);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Empty(actual);
}
[Fact]
public void GetOutputFiles_BluRay_Populated()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Equal(4, actual.Count);
}
[Fact]
public void GetOutputFiles_Other_Empty()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.ApertureCard);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Empty(actual);
}
#endregion
#region FoundAllFiles
[Fact]
public void FoundAllFiles_Invalid_Filled()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
Assert.Equal(3, actual.Count);
}
[Fact]
public void FoundAllFiles_Valid_Empty()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "PS3CFW", "BluRay");
string outputFilename = "test.iso";
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
Assert.Empty(actual);
}
#endregion
#region FoundAnyFiles
[Fact]
public void FoundAnyFiles_Invalid_Filled()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
Assert.False(actual);
}
[Fact]
public void FoundAnyFiles_Valid_Empty()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "PS3CFW", "BluRay");
string outputFilename = "test.iso";
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
Assert.True(actual);
}
#endregion
#region GenerateArtifacts
[Fact]
public void GenerateArtifacts_Invalid_Empty()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
Assert.Empty(actual);
}
[Fact]
public void GenerateArtifacts_Valid_Filled()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "PS3CFW", "BluRay");
string outputFilename = "test.iso";
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
Assert.Equal(2, actual.Count);
}
#endregion
#region GetDeleteableFilePaths
[Fact]
public void GetDeleteableFilePaths_Invalid_Empty()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
Assert.Empty(actual);
}
[Fact]
public void GetDeleteableFilePaths_Valid_Empty()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "PS3CFW", "BluRay");
string outputFilename = "test.iso";
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
Assert.Empty(actual);
}
#endregion
#region GetZippableFilePaths
[Fact]
public void GetZippableFilePaths_Invalid_Empty()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
Assert.Empty(actual);
}
[Fact]
public void GetZippableFilePaths_Valid_Filled()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "PS3CFW", "BluRay");
string outputFilename = "test.iso";
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
Assert.Equal(2, actual.Count);
}
#endregion
#region GeneratePS3CFWDatafile
[Fact]
public void GeneratePS3CFWDatafile_Empty_Null()
{
string iso = string.Empty;
Datafile? actual = PS3CFW.GeneratePS3CFWDatafile(iso);
Assert.Null(actual);
}
[Fact]
public void GeneratePS3CFWDatafile_Invalid_Null()
{
string iso = "INVALID";
Datafile? actual = PS3CFW.GeneratePS3CFWDatafile(iso);
Assert.Null(actual);
}
[Fact]
public void GeneratePS3CFWDatafile_Valid_Filled()
{
string iso = Path.Combine(Environment.CurrentDirectory, "TestData", "PS3CFW", "BluRay", "test.iso");
var actual = PS3CFW.GeneratePS3CFWDatafile(iso);
Assert.NotNull(actual);
Assert.NotNull(actual.Game);
var game = Assert.Single(actual.Game);
Assert.NotNull(game.Rom);
var rom = Assert.Single(game.Rom);
Assert.Equal("9", rom.Size);
Assert.Equal("560b9f59", rom.CRC);
Assert.Equal("edbb6676247e65c2245dd4883ed9fc24", rom.MD5);
Assert.Equal("1b33ad54d78085be5ecb1cf1b3e9da821e708075", rom.SHA1);
}
#endregion
}
}

View File

@@ -0,0 +1,506 @@
using System;
using System.IO;
using SabreTools.Models.Logiqx;
using SabreTools.Models.PIC;
using SabreTools.RedumpLib.Data;
using Xunit;
namespace MPF.Processors.Test
{
// TODO: Write tests for PlayStation 3 specific tools
// TODO: Write tests for Xbox and Xbox 360
public class ProcessingToolTests
{
#region GenerateDatfile
[Fact]
public void GenerateDatfile_Null_Null()
{
Datafile? datafile = null;
string? actual = ProcessingTool.GenerateDatfile(datafile);
Assert.Null(actual);
}
[Fact]
public void GenerateDatfile_Invalid_Null()
{
Datafile? datafile = new Datafile();
string? actual = ProcessingTool.GenerateDatfile(datafile);
Assert.Null(actual);
}
[Fact]
public void GenerateDatfile_Valid_Filled()
{
string? expected = "<rom name=\"test\" size=\"12345\" crc=\"00000000\" md5=\"d41d8cd98f00b204e9800998ecf8427e\" sha1=\"da39a3ee5e6b4b0d3255bfef95601890afd80709\" />";
Rom rom = new Rom
{
Name = "test",
Size = "12345",
CRC = "00000000",
MD5 = "d41d8cd98f00b204e9800998ecf8427e",
SHA1 = "da39a3ee5e6b4b0d3255bfef95601890afd80709",
};
Game game = new Game { Rom = [rom] };
Datafile? datafile = new Datafile { Game = [game] };
string? actual = ProcessingTool.GenerateDatfile(datafile);
Assert.Equal(expected, actual);
}
#endregion
#region GetBase64
[Fact]
public void GetBase64_Null_Null()
{
string? content = null;
string? actual = ProcessingTool.GetBase64(content);
Assert.Null(actual);
}
[Fact]
public void GetBase64_Empty_Null()
{
string? content = string.Empty;
string? actual = ProcessingTool.GetBase64(content);
Assert.Null(actual);
}
[Fact]
public void GetBase64_Valid_Filled()
{
string? expected = "MTIzNDVBQkNERQ==";
string? content = "12345ABCDE";
string? actual = ProcessingTool.GetBase64(content);
Assert.Equal(expected, actual);
}
#endregion
#region GetDatafile
[Fact]
public void GetDatafile_Null_Null()
{
string? dat = null;
Datafile? actual = ProcessingTool.GetDatafile(dat);
Assert.Null(actual);
}
[Fact]
public void GetDatafile_Empty_Null()
{
string? dat = string.Empty;
Datafile? actual = ProcessingTool.GetDatafile(dat);
Assert.Null(actual);
}
[Fact]
public void GetDatafile_Valid_Filled()
{
string? dat = Path.Combine(Environment.CurrentDirectory, "TestData", "ProcessingTool", "datfile.xml");
Datafile? actual = ProcessingTool.GetDatafile(dat);
// TODO: Add structure validation
Assert.NotNull(actual);
}
#endregion
#region GetDiscInformation
// TODO: Figure out how to mock a PIC file
#endregion
#region GetFileModifiedDate
// TODO: Figure out how to get a statically-dated file
#endregion
#region GetFullFile
[Fact]
public void GetFullFile_Empty_Null()
{
string filename = string.Empty;
string? actual = ProcessingTool.GetFullFile(filename);
Assert.Null(actual);
}
[Fact]
public void GetFullFile_Invalid_Null()
{
string filename = "INVALID";
string? actual = ProcessingTool.GetFullFile(filename);
Assert.Null(actual);
}
[Fact]
public void GetFullFile_ValidBinary_Filled()
{
string? expected = "544553542044415441";
string filename = Path.Combine(Environment.CurrentDirectory, "TestData", "ProcessingTool", "textfile.txt");
string? actual = ProcessingTool.GetFullFile(filename, binary: true);
Assert.Equal(expected, actual);
}
[Fact]
public void GetFullFile_ValidText_Filled()
{
string? expected = "TEST DATA";
string filename = Path.Combine(Environment.CurrentDirectory, "TestData", "ProcessingTool", "textfile.txt");
string? actual = ProcessingTool.GetFullFile(filename, binary: false);
Assert.Equal(expected, actual);
}
#endregion
#region GetISOHashValues
[Fact]
public void GetISOHashValues_Datafile_Null_Null()
{
Datafile? datafile = null;
bool actual = ProcessingTool.GetISOHashValues(datafile,
out long size,
out string? crc32,
out string? md5,
out string? sha1);
Assert.False(actual);
Assert.Equal(-1, size);
Assert.Null(crc32);
Assert.Null(md5);
Assert.Null(sha1);
}
[Fact]
public void GetISOHashValues_Datafile_Empty_Null()
{
Datafile? datafile = new Datafile();
bool actual = ProcessingTool.GetISOHashValues(datafile,
out long size,
out string? crc32,
out string? md5,
out string? sha1);
Assert.False(actual);
Assert.Equal(-1, size);
Assert.Null(crc32);
Assert.Null(md5);
Assert.Null(sha1);
}
[Fact]
public void GetISOHashValues_Datafile_Valid_Filled()
{
long expectedSize = 12345;
string? expectedCrc32 = "00000000";
string? expectedMd5 = "d41d8cd98f00b204e9800998ecf8427e";
string? expectedSha1 = "da39a3ee5e6b4b0d3255bfef95601890afd80709";
Rom rom = new Rom
{
Name = "test",
Size = "12345",
CRC = "00000000",
MD5 = "d41d8cd98f00b204e9800998ecf8427e",
SHA1 = "da39a3ee5e6b4b0d3255bfef95601890afd80709",
};
Game game = new Game { Rom = [rom] };
Datafile? datafile = new Datafile { Game = [game] };
bool actual = ProcessingTool.GetISOHashValues(datafile,
out long size,
out string? crc32,
out string? md5,
out string? sha1);
Assert.True(actual);
Assert.Equal(expectedSize, size);
Assert.Equal(expectedCrc32, crc32);
Assert.Equal(expectedMd5, md5);
Assert.Equal(expectedSha1, sha1);
}
[Fact]
public void GetISOHashValues_String_Null_Null()
{
string? hashData = null;
bool actual = ProcessingTool.GetISOHashValues(hashData,
out long size,
out string? crc32,
out string? md5,
out string? sha1);
Assert.False(actual);
Assert.Equal(-1, size);
Assert.Null(crc32);
Assert.Null(md5);
Assert.Null(sha1);
}
[Fact]
public void GetISOHashValues_String_Empty_Null()
{
string? hashData = string.Empty;
bool actual = ProcessingTool.GetISOHashValues(hashData,
out long size,
out string? crc32,
out string? md5,
out string? sha1);
Assert.False(actual);
Assert.Equal(-1, size);
Assert.Null(crc32);
Assert.Null(md5);
Assert.Null(sha1);
}
[Fact]
public void GetISOHashValues_String_Invalid_Filled()
{
string? hashData = "INVALID";
bool actual = ProcessingTool.GetISOHashValues(hashData,
out long size,
out string? crc32,
out string? md5,
out string? sha1);
Assert.False(actual);
Assert.Equal(-1, size);
Assert.Null(crc32);
Assert.Null(md5);
Assert.Null(sha1);
}
[Fact]
public void GetISOHashValues_String_Valid_Filled()
{
long expectedSize = 12345;
string? expectedCrc32 = "00000000";
string? expectedMd5 = "d41d8cd98f00b204e9800998ecf8427e";
string? expectedSha1 = "da39a3ee5e6b4b0d3255bfef95601890afd80709";
string? hashData = "<rom name=\"test\" size=\"12345\" crc=\"00000000\" md5=\"d41d8cd98f00b204e9800998ecf8427e\" sha1=\"da39a3ee5e6b4b0d3255bfef95601890afd80709\" />";
bool actual = ProcessingTool.GetISOHashValues(hashData,
out long size,
out string? crc32,
out string? md5,
out string? sha1);
Assert.True(actual);
Assert.Equal(expectedSize, size);
Assert.Equal(expectedCrc32, crc32);
Assert.Equal(expectedMd5, md5);
Assert.Equal(expectedSha1, sha1);
}
#endregion
#region GetLayerbreaks
[Fact]
public void GetLayerbreaks_Null_Null()
{
DiscInformation? di = null;
bool actual = ProcessingTool.GetLayerbreaks(di,
out long? layerbreak1,
out long? layerbreak2,
out long? layerbreak3);
Assert.False(actual);
Assert.Null(layerbreak1);
Assert.Null(layerbreak2);
Assert.Null(layerbreak3);
}
[Fact]
public void GetLayerbreaks_Empty_Null()
{
DiscInformation? di = new DiscInformation();
bool actual = ProcessingTool.GetLayerbreaks(di,
out long? layerbreak1,
out long? layerbreak2,
out long? layerbreak3);
Assert.False(actual);
Assert.Null(layerbreak1);
Assert.Null(layerbreak2);
Assert.Null(layerbreak3);
}
[Fact]
public void GetLayerbreaks_Valid_Filled()
{
long? expectedLayerbreak1 = 67372038;
long? expectedLayerbreak2 = 134744076;
long? expectedLayerbreak3 = 202116114;
DiscInformationUnit layer0 = new DiscInformationUnit
{
Body = new DiscInformationUnitBody
{
FormatDependentContents = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
}
};
DiscInformationUnit layer1 = new DiscInformationUnit
{
Body = new DiscInformationUnitBody
{
FormatDependentContents = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
}
};
DiscInformationUnit layer2 = new DiscInformationUnit
{
Body = new DiscInformationUnitBody
{
FormatDependentContents = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
}
};
DiscInformationUnit layer3 = new DiscInformationUnit
{
Body = new DiscInformationUnitBody
{
FormatDependentContents = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
}
};
DiscInformation? di = new DiscInformation
{
Units = [layer0, layer1, layer2, layer3],
};
bool actual = ProcessingTool.GetLayerbreaks(di,
out long? layerbreak1,
out long? layerbreak2,
out long? layerbreak3);
Assert.True(actual);
Assert.Equal(expectedLayerbreak1, layerbreak1);
Assert.Equal(expectedLayerbreak2, layerbreak2);
Assert.Equal(expectedLayerbreak3, layerbreak3);
}
#endregion
#region GetPICIdentifier
[Fact]
public void GetPICIdentifier_Null_Null()
{
DiscInformation? di = null;
string? actual = ProcessingTool.GetPICIdentifier(di);
Assert.Null(actual);
}
[Fact]
public void GetPICIdentifier_Empty_Null()
{
DiscInformation? di = new DiscInformation();
string? actual = ProcessingTool.GetPICIdentifier(di);
Assert.Null(actual);
}
[Fact]
public void GetPICIdentifier_Valid_Filled()
{
string? expected = "UHD";
DiscInformationUnit layer0 = new DiscInformationUnit
{
Body = new DiscInformationUnitBody
{
DiscTypeIdentifier = "UHD",
}
};
DiscInformation? di = new DiscInformation
{
Units = [layer0],
};
string? actual = ProcessingTool.GetPICIdentifier(di);
Assert.Equal(expected, actual);
}
#endregion
#region GetUMDCategory
[Theory]
[InlineData(null, null)]
[InlineData("", null)]
[InlineData("GAME", DiscCategory.Games)]
[InlineData("game", DiscCategory.Games)]
[InlineData("VIDEO", DiscCategory.Video)]
[InlineData("video", DiscCategory.Video)]
[InlineData("AUDIO", DiscCategory.Audio)]
[InlineData("audio", DiscCategory.Audio)]
[InlineData("INVALID", null)]
public void GetUMDCategoryTest(string? category, DiscCategory? expected)
{
DiscCategory? actual = ProcessingTool.GetUMDCategory(category);
Assert.Equal(expected, actual);
}
#endregion
#region GetPlayStationRegion
[Theory]
[InlineData(null, null)]
[InlineData("", null)]
[InlineData("S_A", Region.Asia)]
[InlineData("S_C", Region.China)]
[InlineData("S_E", Region.Europe)]
[InlineData("S_K", Region.SouthKorea)]
[InlineData("S_U", Region.UnitedStatesOfAmerica)]
[InlineData("S_PS_46", Region.SouthKorea)]
[InlineData("S_PS_51", Region.Asia)]
[InlineData("S_PS_56", Region.SouthKorea)]
[InlineData("S_PS_55", Region.Asia)]
[InlineData("S_PS_XX", Region.Japan)]
[InlineData("S_PM_645", Region.SouthKorea)]
[InlineData("S_PM_675", Region.SouthKorea)]
[InlineData("S_PM_885", Region.SouthKorea)]
[InlineData("S_PM_XXX", Region.Japan)]
[InlineData("S_PX", Region.Japan)]
[InlineData("PAPX", Region.Japan)]
[InlineData("PABX", null)]
[InlineData("PBPX", null)]
[InlineData("PCBX", Region.Japan)]
[InlineData("PCXC", Region.Japan)]
[InlineData("PDBX", Region.Japan)]
[InlineData("PEBX", Region.Europe)]
[InlineData("PUBX", Region.UnitedStatesOfAmerica)]
public void GetPlayStationRegionTest(string? serial, Region? expected)
{
Region? actual = ProcessingTool.GetPlayStationRegion(serial);
Assert.Equal(expected, actual);
}
#endregion
#region GetXGDRegion
[Theory]
[InlineData(null, null)]
[InlineData(' ', null)]
[InlineData('W', Region.World)]
[InlineData('A', Region.UnitedStatesOfAmerica)]
[InlineData('J', Region.JapanAsia)]
[InlineData('E', Region.Europe)]
[InlineData('K', Region.USAJapan)]
[InlineData('L', Region.USAEurope)]
[InlineData('H', Region.JapanEurope)]
[InlineData('X', null)]
public void GetXGDRegionTest(char? region, Region? expected)
{
Region? actual = ProcessingTool.GetXGDRegion(region);
Assert.Equal(expected, actual);
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
TEST DATA

View File

@@ -0,0 +1 @@
TEST DATA

View File

@@ -0,0 +1 @@
TEST DATA

View File

@@ -0,0 +1 @@
TEST DATA

View File

@@ -0,0 +1 @@
TEST DATA

View File

@@ -0,0 +1 @@
TEST DATA

View File

@@ -0,0 +1 @@
TEST DATA

View File

@@ -0,0 +1 @@
TEST DATA

View File

@@ -0,0 +1 @@
TEST DATA

View File

@@ -0,0 +1 @@
TEST DATA

View File

@@ -0,0 +1 @@
TEST DATA

View File

@@ -0,0 +1 @@
TEST DATA

Binary file not shown.

View File

@@ -0,0 +1,7 @@
--File Generated by CleanRip
CRC32: 00000000
MD5: d41d8cd98f00b204e9800998ecf8427e
SHA-1: da39a3ee5e6b4b0d3255bfef95601890afd80709
Version: version
Internal Name: name
Filename: 000A00

Binary file not shown.

View File

@@ -0,0 +1 @@
TEST DATA

View File

@@ -0,0 +1 @@
TEST DATA

View File

@@ -0,0 +1 @@
TEST DATA

View File

@@ -0,0 +1 @@
TEST DATA

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