Compare commits

..

343 Commits
1.17 ... 2.1

Author SHA1 Message Date
Matt Nadareski
7f4921a47c Bump version to 2.1 2021-07-22 21:02:32 -07:00
Matt Nadareski
07359d2a63 Tweak Linq statement 2021-07-22 20:59:08 -07:00
Matt Nadareski
e5ba670c04 Update to BurnOutSharp 1.7.0 2021-07-22 11:19:58 -07:00
Matt Nadareski
3096c369d3 Update changelog 2021-07-19 22:47:25 -07:00
Matt Nadareski
333368675a Add DMI/PFI/SS to zipfile (fixes #296) 2021-07-19 13:38:16 -07:00
Wilson
d78d744ae2 Fixed log window background turning white after some "time". (#295)
* Fixed launching MPF in Windows 7.

* Potential fix for log window background 'random' color change.

* Updated the color to use hex digits.
2021-07-17 20:35:38 -07:00
Wilson
a8efe056c1 Fixed launching MPF in Windows 7. (#292) 2021-07-12 16:46:30 -07:00
Matt Nadareski
9b2475a854 Add BD to list of supported types for PC (fixes #291) 2021-07-05 22:31:58 -07:00
Matt Nadareski
33e2b27e6d Add new header for mainInfo 2021-07-05 13:26:23 -07:00
Matt Nadareski
91fe9d9bec Support /mr value parameter 2021-07-02 22:57:07 -07:00
Matt Nadareski
b1b9b3134f Update to DIC 20210701 2021-07-01 14:19:25 -07:00
Matt Nadareski
ca5386b529 Update changelog 2021-06-20 11:23:30 -07:00
Matt Nadareski
347beca874 Handle Redump 503s / Timeouts (fixes #289) 2021-06-20 11:21:43 -07:00
Matt Nadareski
27ca4fd1af Check for updates logs as well 2021-06-19 20:47:41 -07:00
Matt Nadareski
6d57a05f8c Encode params for login 2021-06-19 16:12:42 -07:00
Matt Nadareski
4d81449cfa Minor updates 2021-06-19 15:51:18 -07:00
Matt Nadareski
76fcb3ae10 Separate "Include Artifacts" into a separate setting (fixes #287) 2021-06-19 15:41:46 -07:00
Matt Nadareski
b913f5f9ae Update Xbox disc detection (fixes #288) 2021-06-19 15:25:43 -07:00
Matt Nadareski
68fa1eecfb Replace dumping program output processing 2021-06-15 10:24:19 -07:00
Matt Nadareski
dc84f17ac5 Set the matcher for carriage returns 2021-06-15 10:23:14 -07:00
Matt Nadareski
c91137130b Fix newline processing, add changelog 2021-06-15 10:20:13 -07:00
Matt Nadareski
972b07551f Add Logging utility class 2021-06-15 09:55:14 -07:00
Matt Nadareski
61562fe995 Handle carriage returns even without fancy formatting 2021-06-15 09:35:11 -07:00
Matt Nadareski
01b6c3cc98 Minor formatting change in ProcessingQueue 2021-06-14 22:37:47 -07:00
Matt Nadareski
b461dc76b9 Fix incorrect normalization for Aaru 2021-06-14 22:15:36 -07:00
Matt Nadareski
03eeed4113 Update nuget packages 2021-06-03 22:39:50 -07:00
Matt Nadareski
07615cb336 Update nuget packages 2021-06-03 22:19:03 -07:00
Matt Nadareski
9a9a977cc4 Simplify flag validation
Instead of trying to determine if something is a flag, just check if it's one of the supported flags. This should reduce the amount of potential issues that come along with making assumptions about what a parameter could look like.
2021-06-03 22:13:50 -07:00
Matt Nadareski
ab5869331b Add throwability to cuesheet code 2021-06-03 21:58:52 -07:00
Matt Nadareski
1c9ebfd703 TODO additions 2021-06-03 21:20:45 -07:00
Matt Nadareski
a9bc3587a6 Update to DIC 20210601 2021-06-03 21:19:33 -07:00
BadAd84
b1af2b6061 Fix for high cpu usage, issue with loop. (#286) 2021-05-30 12:58:08 -07:00
Matt Nadareski
2fccd53098 Ensure CSSKey file included in log zipping 2021-05-27 12:07:21 -07:00
Matt Nadareski
a7ad3e41d9 Change offset value for HVN discs (fixes #285) 2021-05-27 11:49:24 -07:00
Matt Nadareski
1fc6476f71 Be smarter about checking for zipped logs 2021-05-27 11:46:47 -07:00
Matt Nadareski
53e5a1b1b1 Check for the zipped logs for dealing with overwrites (fixes #277) 2021-05-27 11:20:48 -07:00
Matt Nadareski
119e9dc4cc Always check for all DIC log files, just in case (fixes #281) 2021-05-27 11:00:56 -07:00
Matt Nadareski
9263769906 Fix negative offsets (fixes #282) 2021-05-27 10:41:25 -07:00
Matt Nadareski
ebaf9539b2 Allow users to customize protection scanning 2021-05-06 21:47:57 -07:00
Matt Nadareski
818fb5ab34 Add right click menu with theming 2021-04-28 11:07:54 -07:00
Matt Nadareski
2f514082a9 Replace WindowChrome with dragable titles instead 2021-04-28 10:08:18 -07:00
Matt Nadareski
5c5379e972 Update ScrollViewer style 2021-04-27 11:07:07 -07:00
Matt Nadareski
c39894d9fc Update ProgressBar style 2021-04-27 10:51:32 -07:00
Matt Nadareski
2c6cf0e736 Custom UI elements v2 2021-04-26 23:08:21 -07:00
Matt Nadareski
7e96bbee27 Custom UI elements v1
This enables full-window dark mode to be a reality. The problem is that my design skills are very low
2021-04-26 22:32:05 -07:00
Matt Nadareski
f7019546d1 Add experimental dark mode (fixes #272) 2021-04-26 12:07:21 -07:00
Matt Nadareski
086f54abf0 Topsy-turvy (fixes #274) 2021-04-25 14:08:00 -07:00
Matt Nadareski
143a4149bd Parametrics (#276)
* Begin reducing complexity of parameters classes

* Make the method virtual, not the field

* Consolidate helper methods

* Fix "empty" commands; Fix DD generation

* Handle all sorts of numerical values

* Rip out remaining unneeded enum
2021-04-25 14:03:55 -07:00
Whovian9369
20aed68d58 Fix README formatting in "Notable Testers" Section (#275) 2021-04-25 10:19:15 -07:00
Matt Nadareski
7a2061a36e Bump version for first MPF rebranded stable 2021-04-23 10:30:44 -07:00
Matt Nadareski
191c7b080e Add offset for all HVN discs 2021-04-18 10:42:09 -07:00
Matt Nadareski
aab0813688 Remove HVN-specific flags for now
These flags may cause dumping issues for some, if not a majority, of VideoNow discs
2021-04-16 21:18:48 -07:00
Matt Nadareski
9ad564772c Add content alignment to user input control 2021-04-15 12:59:44 -07:00
Matt Nadareski
20bb34c3c7 Handle Enter/Esc for relevant buttons 2021-04-14 22:26:23 -07:00
Matt Nadareski
b15ddf390b Update to BurnOutSharp 1.6.1 2021-04-14 09:27:42 -07:00
Matt Nadareski
18d1562ad3 Update changelog 2021-04-13 09:31:23 -07:00
Matt Nadareski
d6f2ecbd25 Add version from Git commit (fixes #271)
This also ensures that the new version check still works as well, so the commit hash addition doesn't screw anything up.
2021-04-13 09:30:26 -07:00
Matt Nadareski
3620686afa Change window title 2021-04-13 09:28:26 -07:00
Matt Nadareski
1524224bc3 Fix cursor positioning issue 2021-04-12 22:04:54 -07:00
Matt Nadareski
35200d53d6 Update changelog 2021-04-12 14:59:22 -07:00
Matt Nadareski
4b7d4e05e7 Streamline output path textbox handling
Addresses issue of cursor moving during typing
Addresses issue of extraneous spaces appearing
2021-04-12 13:25:12 -07:00
Matt Nadareski
7e73f69433 Fix Optuons XAML 2021-04-12 08:42:22 -07:00
Matt Nadareski
9e1a972df5 Remove needless UIOptions intermediate class 2021-04-11 22:30:23 -07:00
Matt Nadareski
1edac34c1a Handle dialog return properly
Also fixes an issue where dumpable media with no ring would show a ringcode tab
2021-04-11 09:31:22 -07:00
Matt Nadareski
9adc588c9c Reintroduce options cancel button 2021-04-11 00:09:13 -07:00
Matt Nadareski
71bfdcba8f Proofreading 2021-04-09 13:52:03 -07:00
Matt Nadareski
9854c9970a Add descriptions to new options, change defaults
The default changes are:
- Setting `CompressLogFiles` to `true`
- Setting `ToolsInSeparateWindow` to `true`
- Setting `EnableLogFormatting` to `false`
- Setting `EnableProgressProcessing` to `false`

The last two don't really matter if `ToolsInSeparateWindow` is `true` since no UI-derived logs will ever trigger them, so they're being disabled for now.
2021-04-09 13:31:23 -07:00
Matt Nadareski
0c68164d6d Add option for log formatting 2021-04-09 12:03:30 -07:00
Matt Nadareski
a413357b57 Help users be more patient when starting a dump 2021-04-09 11:47:12 -07:00
Matt Nadareski
5e283c9e80 Add option to enable progress processing
This is one of the larger pain-points for redirecting the output as it involves a regex. Make it optional so people with weaker systems have a better chance.
2021-04-09 11:16:50 -07:00
Matt Nadareski
500eb66e30 Fix the text... got it inverted 2021-04-09 10:59:00 -07:00
Matt Nadareski
411e5245a5 Update tooltip to help a bit more 2021-04-09 10:57:48 -07:00
Matt Nadareski
d270501c2d Update to BurnOutSharp 1.6.0 2021-04-09 10:31:27 -07:00
Matt Nadareski
f7f924593f Add Audio CD detection
On Windows 10, at least, when a purely Audio CD is put in, it gets the volume label of "Audio CD", conveniently. We can use this to at least attempt to match, even if this could be a false positive for some CD-i or things like Jag CD
2021-04-07 10:04:59 -07:00
Matt Nadareski
5126a66eb9 Color code the text 2021-04-06 13:35:47 -07:00
Matt Nadareski
7fddef238d Update changelog 2021-04-06 11:31:27 -07:00
Matt Nadareski
ace673f90d Integrate ring code guide into submission window
Adds a new button to show the ring code guide for easier reference
2021-04-06 11:05:03 -07:00
Matt Nadareski
e063df63df Merge pull request #269 from SabreTools/logjam
Add option to compress log files after dumping
2021-04-02 22:47:26 -07:00
Matt Nadareski
22b15710d0 Take output of compression into account for log 2021-04-02 22:34:46 -07:00
Matt Nadareski
87199c1b0d Update changelog 2021-04-02 22:28:01 -07:00
Matt Nadareski
7e5952bbb8 Add log file lsits for CleanRip and UIC 2021-04-02 22:23:15 -07:00
Matt Nadareski
1a52a3a205 Add Check parameter for compression 2021-04-02 22:20:15 -07:00
Matt Nadareski
742db4c854 Change default archive name 2021-04-02 22:12:32 -07:00
Matt Nadareski
4fd51dbe45 Default to false, for now 2021-04-02 21:57:00 -07:00
Matt Nadareski
096a8a6a06 Add Aaru log file paths, remove TODO in DIC 2021-04-02 21:56:14 -07:00
Matt Nadareski
ad5cd5b8f9 Only encode artifacts if we're outputting JSON 2021-04-02 21:53:41 -07:00
Matt Nadareski
3230d59f6a Fix options window 2021-04-02 21:49:57 -07:00
Matt Nadareski
96fa8d8cef Add DiscImageCreator log paths 2021-04-02 21:36:14 -07:00
Matt Nadareski
01bf3c9efb Add log file compression 2021-04-02 21:21:50 -07:00
Matt Nadareski
da0bf64e94 Add log compression option 2021-04-02 20:55:20 -07:00
Matt Nadareski
d39cf5d13f Make JSON optional (fixes #268) 2021-04-02 18:57:25 -07:00
Matt Nadareski
7c7e78fd4e Errors during dumping should be more verbose
This should *hopefully* be a temporary change in order to determine what is failing after many dumps in a row.
2021-04-02 14:23:02 -07:00
Matt Nadareski
d2c504898a Empty the queue at least 2021-04-01 19:08:39 -07:00
Matt Nadareski
58028b4f18 Reset queue entirely to prevent issues 2021-04-01 15:11:30 -07:00
Matt Nadareski
54e835687b Only rely on cancellation not disposal 2021-04-01 15:10:43 -07:00
Matt Nadareski
10f2318541 Update to DIC 20210401 2021-03-31 22:11:02 -07:00
Matt Nadareski
eb4e95e5db Fix ProcessingQueue disposal (fixes #267) 2021-03-31 21:26:55 -07:00
Matt Nadareski
203418eebc CD-i is a fake audio format 2021-03-31 20:36:06 -07:00
Matt Nadareski
136c6c8fbf Remove two useless TODOs 2021-03-29 13:11:45 -07:00
Matt Nadareski
2c216d6a58 Use BurnOutSharp for PSX scanning 2021-03-29 13:10:49 -07:00
Matt Nadareski
f7ec19cc5d Clean up a couple more TODOs 2021-03-29 13:05:46 -07:00
Matt Nadareski
e8c4a97158 Fix flag value 2021-03-29 12:14:06 -07:00
Matt Nadareski
5e5fc4c812 Factor in size to media type output 2021-03-29 12:12:20 -07:00
Matt Nadareski
5e0d99ff5d Remove unnecessary TODOs 2021-03-29 12:12:05 -07:00
Matt Nadareski
e88e67c927 Fix broken test 2021-03-29 11:56:28 -07:00
Matt Nadareski
d963dbbd5f Move some classes around and cleanup 2021-03-29 11:55:29 -07:00
Matt Nadareski
11ce78fca2 Fix and use ProcessingQueue 2021-03-29 10:50:43 -07:00
Matt Nadareski
fd4022ba84 Add ProcessingQueue (nw) 2021-03-29 10:23:34 -07:00
Matt Nadareski
f91aecad8e Add queueing mechanism to DumpEnvironment 2021-03-29 09:35:39 -07:00
Matt Nadareski
709b7d357f It's a secret... 2021-03-28 22:29:22 -07:00
Matt Nadareski
59980fa160 Clear button should clear progress bar too 2021-03-28 22:25:03 -07:00
Matt Nadareski
180caf83cc Forgot to update param comment and changelog 2021-03-28 22:22:27 -07:00
Matt Nadareski
7047ee832a Simplify null checks 2021-03-28 22:15:33 -07:00
Matt Nadareski
4b5532e1b0 Log levels, struct methods, simpler constructor 2021-03-28 22:10:17 -07:00
Matt Nadareski
137155d3dc Forgot summary comment 2021-03-28 21:34:27 -07:00
Matt Nadareski
793dd8289a Safer queue, use LogLine struct again
Once ConcurrentQueue was used, there were issues with using Run objects in the queue. Even with Dispatcher, there were access issues. So back to the minimal struct.
2021-03-28 21:30:42 -07:00
Matt Nadareski
bcf298e40b Change name of log queue 2021-03-28 20:38:59 -07:00
Matt Nadareski
589aef1e21 Use Run instead of custom wrapper
This simplifies a whole bunch of logic that had to convert from one type to another.
2021-03-28 20:38:15 -07:00
Matt Nadareski
9ab0b7ab3b Clean up var and methods in logger 2021-03-28 20:28:59 -07:00
Matt Nadareski
4c5ea13aac Add log queuing 2021-03-28 15:38:51 -07:00
Matt Nadareski
0cf48bbdaa Cache last line object instead 2021-03-28 13:58:11 -07:00
Matt Nadareski
8fc9cc18a3 Simplify dispatcher calls 2021-03-28 00:21:48 -07:00
Matt Nadareski
b1e156eed6 Smarter about matchers 2021-03-27 22:23:29 -07:00
Matt Nadareski
a8b3a837ef Simplify matchers, fix percentages 2021-03-27 13:21:42 -07:00
Matt Nadareski
3f3a1c9a44 Support new Redump languages and regions 2021-03-27 10:28:45 -07:00
Matt Nadareski
cf4d2f5055 Fix typo in progress 2021-03-25 22:56:17 -07:00
Matt Nadareski
2d19d51bc7 Add matcher for anti-mod string search 2021-03-25 18:48:19 -07:00
Matt Nadareski
4842bdd38b Have the log catch exceptions during matching 2021-03-24 20:20:24 -07:00
Matt Nadareski
7cc4f6d6a7 Only list protections found, not the files
This may be gated behind a flag in the future as having the full list of files and their associated protections can be useful.
2021-03-21 15:38:52 -07:00
Matt Nadareski
b284ffd99d Fix build 2021-03-20 12:47:51 -07:00
Matt Nadareski
81d0cc2cc2 Replace . with _ for DIC output paths (fixes #264) 2021-03-19 21:14:33 -07:00
Matt Nadareski
70f368d6e9 Make copy scan errors separate (fixes #263) 2021-03-19 17:44:42 -07:00
Matt Nadareski
bfbae5cf5c Fix default output directory in UI 2021-03-15 22:06:31 -07:00
Matt Nadareski
7cc231f5fd Fix incorrectly disposing stream 2021-03-15 22:06:14 -07:00
Matt Nadareski
eda34b3477 Fix text alignment 2021-03-14 19:37:06 -07:00
Matt Nadareski
bfb67ec0c9 Make UI more consistent for dump button 2021-03-12 15:29:26 -08:00
Matt Nadareski
275fd0da48 Rearrange DumpEnvironment code 2021-03-12 15:14:40 -08:00
Matt Nadareski
1ad5c25ed0 Remove .NET Framework 4.7.2, update copyright dates 2021-03-12 15:05:33 -08:00
Matt Nadareski
512f7ae016 Clean up parameters and related
This makes some former virtual methods into properties, cleans up the location of some logic, and makes the BaseParameters class a little neater
2021-03-12 14:59:04 -08:00
Matt Nadareski
3a00efc7fd Make dumping path a little easier to follow
Resets the progress bar a bit earlier
Disables/enables UI elements during dumping to avoid weird interactions
Handle more things that shouldn't be verbose logs
2021-03-11 22:14:19 -08:00
Matt Nadareski
3068c74ad7 DVD/BD have more label info possible 2021-03-11 18:50:06 -08:00
Matt Nadareski
9bdead5616 Various bits of maintenence
Added and fixed some of the CD DIC Matchers
Added caching for last line of text and last matcher used
Made replacing the last line more efficient
Fixed default system handling
Fixed potential issue with sector reading
2021-03-11 13:02:48 -08:00
Matt Nadareski
0ed5feb96b Support a new Matcher for DIC DVD 2021-03-10 19:11:31 -08:00
Matt Nadareski
ec80ef2ede Sort matchers and add a couple more 2021-03-10 16:08:08 -08:00
Matt Nadareski
617591cc26 Fix redump username binding 2021-03-10 15:25:42 -08:00
Matt Nadareski
c855aa5cef Make outputting to separate window a setting 2021-03-10 15:13:11 -08:00
Matt Nadareski
e2a27479f5 Display dump progress in log window (fixes #131)
This builds heavily upon the work that Jack put into capturing and processing DIC outputs. For now, there are only matchers for DIC outputs. All other programs will still direct to the log window, but may not be processed as neatly
2021-03-10 14:51:13 -08:00
Matt Nadareski
c8cfe76aa3 Better text bindings 2021-03-09 16:38:15 -08:00
Matt Nadareski
ecb0234258 Make inner and outer layers more apparent
Also makes label and data side data make more sense
2021-03-09 14:06:18 -08:00
Matt Nadareski
24ce4bcc51 Make layers more clearly named 2021-03-09 13:32:10 -08:00
Matt Nadareski
162af3de31 Hook up default system in options (fixes #246) 2021-03-09 12:01:45 -08:00
Matt Nadareski
7c0af96dc9 Make XGD extension 2021-03-09 09:55:08 -08:00
Matt Nadareski
026f999b46 VideoNow discs are audio only (fixes #261) 2021-03-09 09:41:39 -08:00
Matt Nadareski
bbbc3e98a0 One more pass on options 2021-03-08 22:19:22 -08:00
Matt Nadareski
f78ad4e7b6 Fix incorrect eject value for Check 2021-03-08 20:48:51 -08:00
Matt Nadareski
d756ae2163 Fix poorly designed tests 2021-03-08 16:19:53 -08:00
Matt Nadareski
701738ce25 Forgot about nulls 2021-03-08 15:47:29 -08:00
Matt Nadareski
620bdc9132 Reduce logic weirdness, possibly fix PIC layerbreak 2021-03-08 15:40:30 -08:00
Matt Nadareski
71f474c26c CMI is its own option 2021-03-08 15:20:13 -08:00
Matt Nadareski
c48137a5c1 Update changelog (fixes #259) 2021-03-08 15:11:11 -08:00
Matt Nadareski
e248368484 Add force dumping option for Aaru 2021-03-08 15:10:09 -08:00
Matt Nadareski
7225b8c32d Make eject after dump an option 2021-03-08 15:06:40 -08:00
Matt Nadareski
20e475e130 Separate out Aaru and DIC options 2021-03-08 14:56:26 -08:00
Matt Nadareski
88dc005592 Use aaruf instead of aif 2021-03-08 14:51:44 -08:00
Matt Nadareski
40792ff0eb Update changelist 2021-03-07 14:20:01 -08:00
Matt Nadareski
6ae59e91de Shuffle things for Redump obviousness 2021-03-07 14:17:25 -08:00
Matt Nadareski
5c7aa5f7f5 Hook up language selection for PS2 2021-03-07 13:45:24 -08:00
Matt Nadareski
aaa1ed674f Fix path population on drive scan 2021-03-07 10:19:59 -08:00
Matt Nadareski
42def3bbe5 Fix dropdown population 2021-03-07 10:05:54 -08:00
Matt Nadareski
9cdab52556 Fix system selection regression 2021-03-06 21:49:33 -08:00
Matt Nadareski
5c104ebf3d Fix tests 2021-03-06 21:47:02 -08:00
Matt Nadareski
7ab72e542c Fix auto extension filling 2021-03-05 17:18:08 -08:00
Matt Nadareski
3a8420cd2f Fix broken dumping 2021-03-05 17:14:15 -08:00
Matt Nadareski
916aa9fd70 Move things around like Shadow 2021-03-02 11:34:48 -08:00
Matt Nadareski
8809df10b6 Use Shadow's disable code for categories 2021-03-02 09:55:50 -08:00
Matt Nadareski
34d65a9d70 KnownSystem cleanup based on Shadow's stuff 2021-03-02 09:48:36 -08:00
Matt Nadareski
2830d7c8a2 Use Shadow's combined element model 2021-03-02 09:08:56 -08:00
Matt Nadareski
c702c8b0ac Update to DIC 20210301 2021-03-02 09:05:44 -08:00
Matt Nadareski
e1df9a9754 Use Shadow's description converter implementation 2021-03-01 23:02:45 -08:00
Matt Nadareski
03fe5ce8a5 Take Shadow's advice about lists 2021-03-01 22:58:55 -08:00
Matt Nadareski
432a9dda16 Clean up options binding 2021-03-01 21:51:40 -08:00
Matt Nadareski
1dfc0f731e UniformGrid 2021-03-01 21:09:26 -08:00
Matt Nadareski
af515e0adf Update attributions 2021-02-28 13:19:55 -08:00
Matt Nadareski
2222b57143 Fix spelling 2021-02-28 11:37:53 -08:00
Matt Nadareski
d8cfa2e6a4 Quick touch-up on disc info window 2021-02-28 11:36:29 -08:00
Matt Nadareski
a622cdd4e0 Clean up tabified Options window 2021-02-28 11:20:38 -08:00
Matt Nadareski
2a4ec83d0d 1 to 1 tabification of Options window 2021-02-28 11:02:21 -08:00
Matt Nadareski
b1d144d091 A little more log view cleanup 2021-02-28 10:55:49 -08:00
Matt Nadareski
23a8b66c16 Get rid of warning 2021-02-28 10:29:51 -08:00
Matt Nadareski
381ebd5961 Clean up logging view 2021-02-28 10:28:31 -08:00
Matt Nadareski
b4d1f7d6c3 LogWindow -> LogOutput 2021-02-28 02:28:53 -08:00
Matt Nadareski
b3eff64275 Get fancy with expander 2021-02-28 00:46:38 -08:00
Matt Nadareski
f15c00acca Multiline comments and contents 2021-02-28 00:36:36 -08:00
Matt Nadareski
a66d0d4722 Perform some cleanup on Options window 2021-02-27 23:23:12 -08:00
Matt Nadareski
66cdade01b Fix layerbreak reading (wrong endianness) 2021-02-27 23:04:25 -08:00
Matt Nadareski
9e9f001768 More StackPanel stuff 2021-02-27 22:39:07 -08:00
Matt Nadareski
3514bdcbc4 Update changelist 2021-02-27 22:32:37 -08:00
Matt Nadareski
312df37365 Use tabs, enable layers 2 and 3 2021-02-27 22:32:03 -08:00
Matt Nadareski
6214d91940 Rename ring fields in SubmissionInfo 2021-02-27 21:47:10 -08:00
Matt Nadareski
23d500434b Add and use UserInput
Please note that this only affects the disc information window for now. This may end up in the others later.
2021-02-27 21:33:37 -08:00
Matt Nadareski
7ee5e3ab43 Add PIC parsing 2021-02-27 16:58:09 -08:00
Matt Nadareski
6be4bb7c85 Boilerplate for 4 layer support 2021-02-26 22:52:28 -08:00
Matt Nadareski
d620c13e22 Update changelist 2021-02-26 22:38:21 -08:00
Matt Nadareski
73b585cdd2 Add PS5 version extraction (fixes #258) 2021-02-26 22:36:43 -08:00
Matt Nadareski
2f33581e4a Add PS5 console to list 2021-02-26 22:27:36 -08:00
Matt Nadareski
f3dba9a026 Add Xbox Series consoles to list 2021-02-26 22:13:18 -08:00
Matt Nadareski
d7d0af369c Boilerplate for 3 layer support 2021-02-26 21:58:10 -08:00
Matt Nadareski
2ab9a45a71 Update changelist 2021-02-04 22:06:13 -08:00
Matt Nadareski
dc0bf642a9 Better handling of drive changes
Similar to how things like changed options, UI initialization, and media scan all share basically the same path, most of what goes into changing drive letter is the same. So with a small tweak to that code, it is viable to use that method for all 4 paths.
2021-02-04 21:52:26 -08:00
Matt Nadareski
9e32435972 Reorganize Drive class a little 2021-02-04 21:38:57 -08:00
Matt Nadareski
c2b724e949 Auto-detect VCD (fixes #257) 2021-02-04 21:16:42 -08:00
Matt Nadareski
195d3c6ff7 Update to DIC 20210202 2021-02-01 21:16:59 -08:00
Matt Nadareski
04a8079cee Add better notes and outputs for process 2021-01-26 22:46:06 -08:00
Matt Nadareski
0b2daf7d30 Add notes, remove a couple files from serialization 2021-01-26 22:45:38 -08:00
Matt Nadareski
1353ee603b Fix serialization issue 2021-01-26 22:45:04 -08:00
Matt Nadareski
e9d272d139 Potentially massive file gets compressed 2021-01-26 20:55:45 -08:00
Matt Nadareski
0308c7a81e Direct to Base64 for binary files 2021-01-26 17:12:44 -08:00
Matt Nadareski
4caad10c9b Comment out binary files for now 2021-01-26 14:36:35 -08:00
Matt Nadareski
85c1623d33 Forgot the DVD/BD binary files 2021-01-26 13:55:05 -08:00
Matt Nadareski
5be1825bb5 Add all output files as encoded artifacts to JSON 2021-01-26 13:45:12 -08:00
Matt Nadareski
ec5e533bd8 Rename currently unused variable 2021-01-26 13:44:38 -08:00
Matt Nadareski
c3e4c7fa78 Add artifacts section to submission info 2021-01-26 11:39:45 -08:00
Matt Nadareski
bf66a3fcbd Add version to submission info 2021-01-25 17:05:32 -08:00
Matt Nadareski
101193cb78 Streamline statuses from trying to execute 2021-01-25 13:11:20 -08:00
Matt Nadareski
b610c29be6 Log exceptions on dumping as well 2021-01-25 12:05:46 -08:00
Matt Nadareski
999c4dceb5 Ensure the executable exists before trying to run it 2021-01-25 11:55:18 -08:00
Matt Nadareski
2957370fac Missed a couple of places 2021-01-25 10:21:50 -08:00
Matt Nadareski
5dd36d7b06 Inline all of those params during logging 2021-01-25 10:02:34 -08:00
Matt Nadareski
47b5bbe7e7 Update to BurnOutSharp 1.5.1 2021-01-22 12:03:12 -08:00
Matt Nadareski
5a2e4ca77e Add link to BOS in issue templates 2021-01-21 11:15:10 -08:00
Matt Nadareski
c479ddb80b Fix duplicate security sector data 2021-01-15 22:06:19 -08:00
Matt Nadareski
da1f59e0c1 Fix UIC output parsing and generation 2021-01-15 14:31:31 -08:00
Matt Nadareski
9574832e86 Add ability to get hashes for UIC outputs 2021-01-15 12:52:55 -08:00
Matt Nadareski
3df7842d23 Add ability to hash a file to base parameters 2021-01-15 12:13:27 -08:00
Matt Nadareski
62a0f6e49a Port most hashing code from SabreTools
Note that this explcitly omits both the formerly-supported RIPEMD160 as well as the currently-Aaru-specific SpamSum.
2021-01-15 11:57:24 -08:00
Matt Nadareski
60c180e4dd UIC outputs don't contain a datfile 2021-01-15 11:49:27 -08:00
Matt Nadareski
343d937362 Fix BCA formatting for CleanRip outputs (fixes #251) 2021-01-12 15:36:02 -08:00
Matt Nadareski
f20b321433 Add *tmp file support for DIC 2021-01-07 09:52:00 -08:00
Matt Nadareski
ba19b0825f Update changelist 2021-01-06 09:58:50 -08:00
Matt Nadareski
5abb44957c Add common path for init of full UI
This unites the code that runs when the application is loaded, when options are updated, and when a drive scan is initiated. All 3 situations require that nearly every bit of the UI and possibly even the disc to be re-scanned.
2021-01-05 21:39:46 -08:00
Matt Nadareski
b9d9cf812f Slightly different _mainInfo wording now... 2021-01-03 14:22:25 -08:00
Matt Nadareski
d1529f428a Updated to DIC version 20210102 2021-01-02 22:03:18 -08:00
Matt Nadareski
5061a79c4c Make initial window load more accurate 2020-12-31 14:57:06 -08:00
Matt Nadareski
eab3e25cf2 Fix crash on drive scan 2020-12-31 13:39:19 -08:00
Matt Nadareski
33e73a8992 More messages isnt a bad thing 2020-12-31 11:02:14 -08:00
Matt Nadareski
a63972b549 Get reasonable defaults based on selected system 2020-12-30 22:57:36 -08:00
Matt Nadareski
bc57df7fc1 Add a note for later 2020-12-30 22:29:42 -08:00
Matt Nadareski
e16f616286 Safer queries on getting disc type 2020-12-30 22:20:47 -08:00
Matt Nadareski
c5497d787b Ensure parameters have system and type set 2020-12-30 21:14:06 -08:00
Matt Nadareski
64f60004c4 Error messages on Redump errors 2020-12-30 15:00:52 -08:00
Matt Nadareski
020c063177 Parameters should know their state better 2020-12-30 14:49:28 -08:00
Matt Nadareski
a3e6f8157f Extension cleanup 2020-12-30 14:28:46 -08:00
Matt Nadareski
f27040cd1c Add informational issue template 2020-12-30 14:07:11 -08:00
Matt Nadareski
3a490cfc8d Add note about DIC-only dumps 2020-12-30 14:02:51 -08:00
Matt Nadareski
1f8c5998c1 Fix copy-paste error 2020-12-29 11:15:24 -08:00
Matt Nadareski
f96d4ee37e More safety around listing operations 2020-12-29 11:10:15 -08:00
Matt Nadareski
d0d15f03af Remove Avalonia UI (fixes #245) 2020-12-29 10:56:25 -08:00
Matt Nadareski
eff6407206 Remove CD-i DV from supported profiles 2020-12-27 13:39:26 -08:00
Matt Nadareski
c1e559568a Fix build 2020-12-26 14:31:59 -08:00
Matt Nadareski
ef030b290c Add support for new Redump regions 2020-12-26 14:03:24 -08:00
Matt Nadareski
71630591a1 Add short-circuit for unmatched tracks 2020-12-12 13:37:33 -08:00
Matt Nadareski
31505745be Update to Aaru v5.2 2020-12-02 20:51:56 -08:00
Matt Nadareski
e40444b60c Update changelist 2020-11-30 21:24:15 -08:00
Matt Nadareski
44edf387a6 Relabel labels depending on media type 2020-11-30 16:12:54 -08:00
Matt Nadareski
d3d225644d Add preliminary "default system" support 2020-11-23 14:00:15 -08:00
Matt Nadareski
3afd9200a9 Multiline fields require matching newlines 2020-11-23 13:45:36 -08:00
Matt Nadareski
c5c340ff12 Make label SID change for Avalonia too 2020-11-23 13:22:30 -08:00
Matt Nadareski
b28b85f7c6 Don't gray out label SID for DVD, HD-DVD, BD (fixes #247) 2020-11-23 13:20:37 -08:00
Matt Nadareski
c60684b83c Pass through progress in missing place 2020-11-23 13:17:27 -08:00
Matt Nadareski
a183a1ec91 Fix issue with 0xbe drives, again 2020-11-12 14:43:24 -08:00
Matt Nadareski
abd8488185 Fix remaining links 2020-11-10 20:42:04 -08:00
Matt Nadareski
e6dea158e5 Rename to MPF 2020-11-10 17:43:21 -08:00
Matt Nadareski
24150c7b3c Bump version to 1.18 2020-11-10 10:55:29 -08:00
Matt Nadareski
040720a1c2 Detect HD-DVD-Video 2020-11-08 13:40:30 -08:00
Matt Nadareski
70d30d370f Update to BurnOutSharp 1.5.0 2020-11-03 21:49:59 -08:00
Matt Nadareski
a50b99da07 Use older version of DIC for now 2020-11-01 16:08:57 -08:00
Matt Nadareski
2cecbe69ad Support the /ps command for DIC 2020-10-31 23:05:11 -07:00
Matt Nadareski
557410660f Update to DIC 20201101 2020-10-31 22:55:07 -07:00
Matt Nadareski
0d75dbaaa2 Add dumping program selection finally 2020-10-11 22:06:40 -07:00
Matt Nadareski
d38f95c73a Check sector 0 for Saturn, if possible (fixes #241) 2020-10-11 21:15:35 -07:00
Matt Nadareski
c9d59a90e4 Default to CD-ROM when detection fails as well 2020-10-11 21:07:28 -07:00
Matt Nadareski
fc6a34d987 Use CD-ROM as default when no type detection (fixes #237) 2020-10-11 20:46:24 -07:00
Matt Nadareski
8acabb692f Remove default config file (fixes #238) 2020-10-11 20:36:12 -07:00
Matt Nadareski
61f8871839 Change default for fixed drive detection (fixes #233) 2020-10-11 20:35:39 -07:00
Matt Nadareski
69d61ad185 Use selected drive in UI for copy protect scan (fixes #235) 2020-10-11 20:31:27 -07:00
Matt Nadareski
27391ed31b Remove subdump (fixes #234)
Note that it still downloaads the subdump executable and puts it in the same place. This won't be changing anytime soon since it's useful. It also is flat out removing the option in the menu without replacing or reshaping the menu. This will be addressed at a later date.
2020-10-11 20:24:41 -07:00
Matt Nadareski
ed56c92101 Clean up sector read method a bit more (nw) 2020-10-08 21:21:11 -07:00
Matt Nadareski
ab8ae1524f Actually use the drive letter (nw) 2020-10-08 14:18:23 -07:00
Matt Nadareski
de7c247583 Add initial version of sector reading to library 2020-10-08 12:26:28 -07:00
Matt Nadareski
997fd8f7ac Why do I keep forgetting changelist? 2020-10-01 11:46:55 -07:00
Matt Nadareski
e39e07246a Fix archive naming 2020-10-01 11:34:27 -07:00
Matt Nadareski
e0b0406d76 Let's see how badly this goes... 2020-10-01 11:28:39 -07:00
Matt Nadareski
1efbe9a784 Update BurnOutSharp version; fix autobuild 2020-10-01 09:44:49 -07:00
Matt Nadareski
fab921c2dd Added feature request template 2020-09-29 13:01:28 -07:00
Matt Nadareski
56896b4bea Update issue templates 2020-09-29 12:57:19 -07:00
Matt Nadareski
54eb7d8ecd Forgot the changelog 2020-09-28 11:26:47 -07:00
Matt Nadareski
114587b9f6 Reset paragraph state on clear (fixes #231) 2020-09-28 11:22:40 -07:00
Matt Nadareski
cad33c6c07 Don't lose automatic comments 2020-09-24 15:25:56 -07:00
Matt Nadareski
8154999f1c Fix alternate mainInfo parsing 2020-09-24 15:08:17 -07:00
Matt Nadareski
3a30c14085 Make this apparent on the main page 2020-09-24 11:42:28 -07:00
Matt Nadareski
db8b1df480 Add rolling changelog section 2020-09-24 11:35:16 -07:00
Matt Nadareski
e20cac8a80 Sync 2020-09-24 10:57:09 -07:00
Matt Nadareski
ce9b4e39f5 Add more internal info for GD-ROM LD 2020-09-24 10:49:27 -07:00
Matt Nadareski
ddff4b2e58 SCD has internal serial 2020-09-24 10:26:51 -07:00
Matt Nadareski
16a470475c Remember, no Disc 2020-09-24 10:21:35 -07:00
Matt Nadareski
6e01473e87 Saturn serial -> internal serial, strip 'V' from version 2020-09-24 10:19:34 -07:00
Matt Nadareski
8682089151 Update to DIC 20200921 2020-09-23 10:11:38 -07:00
Matt Nadareski
f45cb0075f Remove superflous check for PVD retrieval (fixes #229) 2020-09-19 14:31:17 -07:00
Matt Nadareski
afccb48798 Specify solution file 2020-09-19 13:40:36 -07:00
Matt Nadareski
ce6995fba0 It was seriously a directory marker issue 2020-09-17 22:04:31 -07:00
Matt Nadareski
3328d1adea Try without the git extension 2020-09-17 22:00:51 -07:00
Matt Nadareski
33d79df9a8 Update AppVeyor 2020-09-17 21:59:07 -07:00
Matt Nadareski
4fb64b19d6 Remove weird csproj stuff 2020-09-17 21:57:00 -07:00
Matt Nadareski
bf0f495c8b Ignore all files except the compiled cicm.cs 2020-09-17 21:54:50 -07:00
Matt Nadareski
5d5f8e8d8c Use official repo as submodule for CICM 2020-09-17 21:52:40 -07:00
Matt Nadareski
91aa248355 A little more cleanup and safety 2020-09-17 21:38:45 -07:00
Matt Nadareski
633c6c1efb Slight tweaks, mostly naming 2020-09-17 21:25:22 -07:00
Matt Nadareski
facb1f673f Wrap login call with try/catch 2020-09-17 15:52:29 -07:00
Matt Nadareski
9c8938c7f2 Get some more layerbreak stuff 2020-09-17 13:30:35 -07:00
Matt Nadareski
17f75f3ce6 First parts of layerbreak info 2020-09-17 10:37:04 -07:00
Matt Nadareski
b99c48afa2 First part of DVD protection extraction for Aaru 2020-09-16 20:45:07 -07:00
Matt Nadareski
9481fada23 Fix writing of valid indexes for Aaru cuesheet 2020-09-16 17:13:15 -07:00
Matt Nadareski
7efbc5043c Add error count for Aaru outputs 2020-09-16 17:00:11 -07:00
Matt Nadareski
92880d3148 Fix discs with ISO extension 2020-09-16 16:25:33 -07:00
Matt Nadareski
9800f2b8ae Use spans instead of Linq (and accidental commit) 2020-09-16 16:09:34 -07:00
Matt Nadareski
a5d01604cb Strip out hard-to-find CD Check instances 2020-09-16 16:01:16 -07:00
Matt Nadareski
aaab84f90a Fix multiple things in Aaru
Addresses overlooked issue with DatFile generation, consolidates common code into methods, fixes PVD generation and write
2020-09-16 15:59:11 -07:00
Matt Nadareski
318a1a303c Fix multiline outputs 2020-09-16 15:58:02 -07:00
Matt Nadareski
0061de6b2e Fix cuesheet write-to-stream 2020-09-16 15:57:22 -07:00
Matt Nadareski
b3db7c547f Generate cuesheet using new classes for Aaru 2020-09-16 14:31:29 -07:00
Matt Nadareski
1da29464a8 Add writing of cuesheets 2020-09-16 14:09:02 -07:00
Matt Nadareski
d1d4ff41c6 Fix reading (assumes reasonably sized cuesheets) 2020-09-16 13:41:00 -07:00
Matt Nadareski
673c2745a9 Fix index check 2020-09-16 13:00:42 -07:00
Matt Nadareski
4ad88441cc Add parsing in of cuesheets 2020-09-16 12:53:28 -07:00
Matt Nadareski
71bb822856 Add cuesheet structures 2020-09-16 11:22:33 -07:00
Matt Nadareski
2a7789bd12 Bump version to 1.17.1 2020-09-15 10:03:39 -07:00
Matt Nadareski
1d0417cc1c Fix DiscInformationWindow issues 2020-09-14 13:51:26 -07:00
Matt Nadareski
905c578d90 Fix DIC flags based on the code 2020-09-14 13:30:14 -07:00
Matt Nadareski
a457c85e53 Better internal handling of Options window 2020-09-13 21:01:53 -07:00
Matt Nadareski
36630fc0ed Fix the tests I broke 2020-09-13 20:52:08 -07:00
Matt Nadareski
f509ac60da Make DiscInformationWindow more robust 2020-09-13 20:41:23 -07:00
Matt Nadareski
bf8aac6f81 Move some constants around 2020-09-13 20:41:09 -07:00
Matt Nadareski
ceddcc0722 Remove useless passthrough vars 2020-09-12 14:11:55 -07:00
159 changed files with 22645 additions and 29799 deletions

View File

@@ -0,0 +1,28 @@
---
name: Feature Request
about: For when you know better than me what you want
title: "[Request]"
labels: enhancement
assignees: mnadareski
---
**Before You Submit**
- Remember to try the [latest WIP build](https://ci.appveyor.com/project/mnadareski/mpf/build/artifacts) to see if the feature already exists.
- Is it copy protection related? If so, report the issue [here](https://github.com/mnadareski/BurnOutSharp/issues) instead.
- .NET Core 3.1 and .NET 5.0 have known limitations, so make sure that what you're asking for isn't already in another build.
- Check [previous issues](https://github.com/SabreTools/MPF/issues) to see if any of those are related to what you're about to ask for.
If none of those apply, then continue...
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

22
.github/ISSUE_TEMPLATE/informational.md vendored Normal file
View File

@@ -0,0 +1,22 @@
---
name: Info
about: Something you need to tell me
title: "[Info]"
labels: question
assignees: mnadareski
---
**Before You Submit**
- Remember to try the [latest WIP build](https://ci.appveyor.com/project/mnadareski/mpf/build/artifacts) to see if the feature already exists.
- Is it copy protection related? If so, report the issue [here](https://github.com/mnadareski/BurnOutSharp/issues) instead.
- .NET Core 3.1 and .NET 5.0 have known limitations, so make sure that what you're giving information on isn't already in another build.
- Check [previous issues](https://github.com/SabreTools/MPF/issues) to see if any of those are related to what you're about to ask for.
If none of those apply, then continue...
**Is your information related to one of the dumping programs supported or something that isn't a bug in the code? Please describe.**
A clear and concise description of what the information is. Ex. With the latest build of DumpingProgram, it [...]
**Additional context**
Add any other context or screenshots about the information here.

49
.github/ISSUE_TEMPLATE/issue-report.md vendored Normal file
View File

@@ -0,0 +1,49 @@
---
name: Issue Report
about: Tell me what's wrong, seriously
title: "[Problem]"
labels: bug
assignees: mnadareski
---
**Before You Submit**
- Remember to try the [latest WIP build](https://ci.appveyor.com/project/mnadareski/mpf/build/artifacts) to see if the issue has already been addressed.
- Is it copy protection related? If so, report the issue [here](https://github.com/mnadareski/BurnOutSharp/issues) instead.
- .NET Core 3.1 and .NET 5.0 have known issues, please try using another build to reproduce the error
- Check multiple discs to help narrow down the issue
- Check the Options to see if changing any of those affects your issue.
If all of those fail, then continue...
**Version**
What version are you using?
- [ ] Stable release (version here)
- [ ] WIP release (version here)
**Build**
What runtime version are you using?
- [ ] .NET Framework 4.7.2 running on (Operating System)
- [ ] .NET Framework 4.8 running on (Operating System)
- [ ] .NET Core 3.1 running on (Operating System)
**Describe the issue**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.

3
.gitmodules vendored Normal file
View File

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

4
.vscode/launch.json vendored
View File

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

6
.vscode/tasks.json vendored
View File

@@ -7,7 +7,7 @@
"type": "process",
"args": [
"build",
"${workspaceFolder}/DICUI/DICUI.csproj",
"${workspaceFolder}/MPF/MPF.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
@@ -19,7 +19,7 @@
"type": "process",
"args": [
"publish",
"${workspaceFolder}/DICUI/DICUI.csproj",
"${workspaceFolder}/MPF/MPF.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
@@ -32,7 +32,7 @@
"args": [
"watch",
"run",
"${workspaceFolder}/DICUI/DICUI.csproj",
"${workspaceFolder}/MPF/MPF.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],

View File

@@ -1,3 +1,117 @@
### 2.1 (2021-07-22)
- Enum, no more
- Sony works backward
- Add experimental dark mode
- Allow users to customize protection scanning
- Fix negative offsets for `/a` flag
- Always check for all DIC log files, just in case
- Check for the zipped logs for dealing with overwrites
- Be smarter about checking for zipped logs
- Change offset value for HVN discs
- Update to DIC 20210601
- Fix Aaru command normalization
- Handle carriage returns better
- Add logging helper class
- Set matcher on carriage return for log formatting
- Replace dumping program output processing
- Fix volume name detection for XBOX discs
- Add new setting for including artifacts in serialzied JSON
- Fix logging in to Redump for verifications
- Gracefully handle timeouts during login
- Update to DIC 20210701
- Support `/mr` value parameter
- Support new mainInfo header
- Add BD to IBM-PC supported discs
- Fix launching MPF on Windows 7
- Fix log window background turning white
- Add DMI/PFI/SS to log zipfile
- Update to BurnOutSharp 1.7.0
### 2.0 (2021-04-23)
- Rename DICUI to Media Preservation Frontend (MPF)
- Add handling for BEh drive _mainInfo.txt changes
- Fix multiline regex fields during info pulling
- Add preliminary support for user-defined default system
- Change labels in media info window depending on media type
- Update to Aaru v5.2
- Only pull disc information if every track returns at least one ID
- Add new supported Redump regions
- Remove Philips CD-i Digital Video from supported profiles
- Remove experimental Avalonia UI, will wait for MAUI next year
- ~~Updated to DIC version 20210102~~
- Add support for `/mr` DIC flag
- UI initialization code refactored to have more consistent results
- Support DIC `.imgtmp`, `.scmtmp`, and `.subtmp` possible output files
- Fix BCA formatting for CleanRip outputs
- Add hashing for UMDs from UIC outputs
- Fix information gathering for UIC outputs
- Fix issue with duplicate security sector data in XGD DiscImageCreator outputs
- ~~Update to BurnOutSharp 1.5.1~~
- ~~Update to DIC version 20210202~~
- Add VCD detection
- Fix UI not updating properly on drive change
- Add Xbox Series and PS5 to supported systems
- Add PS5 type detection and version extraction
- Add internal support for 3- and 4-layer discs
- Revamp disc information window
- Add PIC layerbreak extraction
- Overhaul main window and logging panel
- Overhaul options window
- Update attributions and about text
- ~~Updated to DIC version 20210301~~
- Add user-selectable Language Selection via dropdown in disc submission window for PS2
- Separate out Aaru- and DIC-specific settings
- Add new options based on original "Paranoid Mode" mega-option
- Internal overhaul of options and dump environment
- VideoNow discs are audio only
- Hook up default system in options
- Make inner and outer layers in UI and outputs more clear
- Program output to log by default, setting otherwise
- DVDs and BDs can have label-side data
- Remove .NET Framework 4.7.2 support
- Make logging window a bit safer
- Support new Redump languages and regions
- Implement internal log queue
- It's a secret...
- Updated to DIC version 20210401
- Support log file compression
- Add ring code guide button to disc submission window
- ~~Update to BurnOutSharp 1.6.0~~
- Fix "rewinding" issue when inputting output paths with spaces
- Add version to About box
- Update to BurnOutSharp 1.6.1
### 1.18 (2020-11-10)
- Add more information extraction and generation for Aaru
- Remove instances of CD Check from copy protection (again, sorry)
- Fix multiline submission info outputs
- Fix PVD retrieval for multi-session discs
- Updated to DIC version 20200921
- Add and fix multiple Sega disc header pieces or submission info
- Fixed issues in parsing the alternate mainInfo format
- Fixed issue with logging clear not working properly
- ~~Updated to BurnOutSharp 1.4.1~~
- Added split archives for AppVeyor builds
- Remove subdump from both UI and run steps
- Removed default config file
- Fixed copy protect scan using wrong drive when using UI option
- Changed default to skip fixed drives
- Fixed default media type when skipping type detection
- Attempt sector reading for Saturn system detection
- Fixed default media type when detection fails
- Add option to allow users to select dumping program
- ~~Updated to DIC version 20201101~~
- Add support for `/ps` DIC flag
- Updated to BurnOutSharp 1.5.0
- Added HD-DVD-Video detection
### 1.17.1 (2020-09-14)
- Shuffled some shared, internal UI variables
- Synced WPF and Avalonia UI internals
- Made the disc information window less prone to bugs
- Fixed DIC flags based on code (not documentation)
- Added support for old(?) DIC flags: `/fix` and `/re`
### 1.17 (2020-09-12)
- Updated to Aaru version 5.1
- Updated to BurnOutSharp version 1.4.0

View File

@@ -1,8 +0,0 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="DICUI.Avalonia.App">
<Application.Styles>
<StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseLight.xaml"/>
</Application.Styles>
</Application>

View File

@@ -1,24 +0,0 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
namespace DICUI.Avalonia
{
public class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new MainWindow();
}
base.OnFrameworkInitializationCompleted();
}
}
}

View File

@@ -1,29 +0,0 @@
using DICUI.Utilities;
using DICUI.Web;
namespace DICUI.Avalonia
{
/// <summary>
/// Represents a single item in the Category combo box
/// </summary>
public class CategoryComboBoxItem
{
private object data;
public CategoryComboBoxItem(DiscCategory? category) => data = category;
public static implicit operator DiscCategory? (CategoryComboBoxItem item) => item.data as DiscCategory?;
public string Name
{
get { return (data as DiscCategory?).LongName(); }
}
public bool IsChecked { get; set; }
public DiscCategory? Value
{
get { return data as DiscCategory?; }
}
}
}

View File

@@ -1,35 +0,0 @@
using Avalonia.Media;
using DICUI.Data;
using DICUI.Utilities;
namespace DICUI.Avalonia
{
/// <summary>
/// Represents a single item in the System combo box
/// </summary>
public class KnownSystemComboBoxItem
{
private object data;
public KnownSystemComboBoxItem(KnownSystem? system) => data = system;
public KnownSystemComboBoxItem(KnownSystemCategory? category) => data = category;
public ISolidColorBrush Foreground { get => IsHeader() ? Brushes.Gray : Brushes.Black; }
public bool IsHeader() => data is KnownSystemCategory?;
public bool IsSystem() => data is KnownSystem?;
public static implicit operator KnownSystem? (KnownSystemComboBoxItem item) => item.data as KnownSystem?;
public string Name
{
get
{
if (IsHeader())
return "---------- " + (data as KnownSystemCategory?).LongName() + " ----------";
else
return (data as KnownSystem?).LongName();
}
}
}
}

View File

@@ -1,29 +0,0 @@
using DICUI.Utilities;
using DICUI.Web;
namespace DICUI.Avalonia
{
/// <summary>
/// Represents a single item in the Language combo box
/// </summary>
public class LanguageComboBoxItem
{
private object data;
public LanguageComboBoxItem(Language? region) => data = region;
public static implicit operator Language? (LanguageComboBoxItem item) => item.data as Language?;
public string Name
{
get { return (data as Language?).LongName(); }
}
public bool IsChecked { get; set; }
public Language? Value
{
get { return data as Language?; }
}
}
}

View File

@@ -1,20 +0,0 @@
using DICUI.Data;
using DICUI.Utilities;
namespace DICUI.Avalonia
{
/// <summary>
/// Represents a single item in the MediaType combo box
/// </summary>
public class MediaTypeComboBoxItem
{
private MediaType? data;
public MediaTypeComboBoxItem(MediaType? mediaType) => data = mediaType;
public static implicit operator MediaType? (MediaTypeComboBoxItem item) => item.data;
public string Name { get { return data.LongName(); }
}
}
}

View File

@@ -1,30 +0,0 @@
using DICUI.Utilities;
using DICUI.Web;
namespace DICUI.Avalonia
{
/// <summary>
/// Represents a single item in the Region combo box
/// </summary>
public class RegionComboBoxItem
{
private object data;
public RegionComboBoxItem(Region? region) => data = region;
public static implicit operator Region? (RegionComboBoxItem item) => item.data as Region?;
public string Name
{
get
{
return (data as Region?).LongName();
}
}
public Region? Value
{
get { return data as Region?; }
}
}
}

View File

@@ -1,55 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DICUI.Data;
namespace DICUI.Avalonia
{
/// <summary>
/// Variables for UI elements
/// </summary>
public static class Constants
{
public const string StartDumping = "Start Dumping";
public const string StopDumping = "Stop Dumping";
public const int LogWindowMarginFromMainWindow = 40;
// Private lists of known drive speed ranges
private static IReadOnlyList<int> cd { get; } = new List<int> { 1, 2, 3, 4, 6, 8, 12, 16, 20, 24, 32, 40, 44, 48, 52, 56, 72 };
private static IReadOnlyList<int> dvd { get; } = cd.Where(s => s <= 24).ToList();
private static IReadOnlyList<int> bd { get; } = cd.Where(s => s <= 16).ToList();
private static IReadOnlyList<int> unknown { get; } = cd; // TODO: All or {1}? Maybe null?
/// <summary>
/// Get list of all drive speeds for a given MediaType
/// </summary>
/// <param name="type">MediaType? that represents the current item</param>
/// <returns>Read-only list of drive speeds</returns>
public static IReadOnlyList<int> GetSpeedsForMediaType(MediaType? type)
{
switch (type)
{
case MediaType.CDROM:
case MediaType.GDROM:
return cd;
case MediaType.DVD:
case MediaType.HDDVD:
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
return dvd;
case MediaType.BluRay:
return bd;
default:
return unknown;
}
}
// Create collections for UI based on known drive speeds
public static List<double> SpeedsForCDAsCollection { get; } = GetDoubleCollectionFromIntList(cd);
public static List<double> SpeedsForDVDAsCollection { get; } = GetDoubleCollectionFromIntList(dvd);
public static List<double> SpeedsForBDAsCollection { get; } = GetDoubleCollectionFromIntList(bd);
private static List<double> GetDoubleCollectionFromIntList(IReadOnlyList<int> list)
=> new List<double>(list.Select(i => Convert.ToDouble(i)).ToList());
}
}

View File

@@ -1,51 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472;net48;netcoreapp3.1</TargetFrameworks>
<OutputType>WinExe</OutputType>
<ApplicationIcon>Icon.ico</ApplicationIcon>
<Prefer32Bit>true</Prefer32Bit>
<Title>DICUI</Title>
<AssemblyName>DICUI.Avalonia</AssemblyName>
<Description>Frontend for various dumping programs</Description>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2020</Copyright>
<RepositoryUrl>https://github.com/SabreTools/DICUI</RepositoryUrl>
<Version>1.17.0</Version>
<AssemblyVersion>1.17.0</AssemblyVersion>
<FileVersion>1.17.0</FileVersion>
<IncludeSource>true</IncludeSource>
<IncludeSymbols>true</IncludeSymbols>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.9.12" />
<PackageReference Include="Avalonia.Desktop" Version="0.9.12" />
<PackageReference Include="BurnOutSharp" Version="1.4.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.7.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DICUI.Library\DICUI.Library.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="DiscInformationWindow.axaml.cs">
<DependentUpon>DiscInformationWindow.axaml</DependentUpon>
</Compile>
<Compile Update="LogWindow.axaml.cs">
<DependentUpon>LogWindow.axaml</DependentUpon>
</Compile>
<Compile Update="MainWindow.axaml.cs">
<DependentUpon>MainWindow.axaml</DependentUpon>
</Compile>
<Compile Update="OptionsWindow.axaml.cs">
<DependentUpon>OptionsWindow.axaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<AvaloniaResource Include="Icon.ico" />
</ItemGroup>
</Project>

View File

@@ -1,120 +0,0 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="515.132" d:DesignHeight="705" Width="515.132" Height="705"
x:Class="DICUI.Avalonia.DiscInformationWindow" Icon="Icon.ico" CanResize="False"
Title="Disc Information" Closed="OnClosed">
<Grid RowDefinitions="585,80,25">
<!-- Common Disc Information -->
<Border Grid.Row="0" Margin="5" BorderThickness="1" BorderBrush="Gray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock Text="Common Disc Information" Margin="2" HorizontalAlignment="Left" VerticalAlignment="Top" FontWeight="Bold" FontSize="14" Foreground="Gray" />
</Border>
<Grid Grid.Row="0" Margin="10,15,10,10" ColumnDefinitions="1*,1*" RowDefinitions="1*,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25">
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Title" />
<TextBox Name="TitleTextBox" Grid.Row="1" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Foreign Title (Non-Latin)" />
<TextBox Name="ForeignTitleTextBox" Grid.Row="2" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<TextBlock Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Disc Number / Letter" />
<TextBox Name="DiscNumberLetterTextBox" Grid.Row="3" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<TextBlock Grid.Row="4" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Disc Title" />
<TextBox Name="DiscTitleTextBox" Grid.Row="4" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<TextBlock Grid.Row="5" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Category" />
<ComboBox Name="CategoryComboBox" Grid.Row="5" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Grid.Row="6" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Region" />
<ComboBox Name="RegionComboBox" Grid.Row="6" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Grid.Row="7" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Languages" />
<ComboBox Name="LanguagesComboBox" Grid.Row="7" Grid.Column="1" Height="24" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" >
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Path=Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Grid.Row="8" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Serial" />
<TextBox Name="SerialTextBox" Grid.Row="8" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<!-- Layer 0 / Data Side -->
<TextBlock Grid.Row="9" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Data/L0 Mastering Ring" />
<TextBox Name="L0MasteringRingTextBox" Grid.Row="9" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" AcceptsTab="True" />
<TextBlock Grid.Row="10" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Data/L0 Mastering SID" />
<TextBox Name="L0MasteringSIDTextBox" Grid.Row="10" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<TextBlock Grid.Row="11" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Data/L0 Toolstamp/Mastering Code" />
<TextBox Name="L0ToolstampTextBox" Grid.Row="11" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<TextBlock Grid.Row="12" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Data/L0 Mould SID" />
<TextBox Name="L0MouldSIDTextBox" Grid.Row="12" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<TextBlock Grid.Row="13" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Data/L0 Additional Mould" />
<TextBox Name="L0AdditionalMouldTextBox" Grid.Row="13" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<!-- Layer 1 / Label Side -->
<TextBlock Grid.Row="14" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Label/L1 Mastering Ring" />
<TextBox Name="L1MasteringRingTextBox" Grid.Row="14" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" AcceptsTab="True" />
<TextBlock Grid.Row="15" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Label/L1 Mastering SID" />
<TextBox Name="L1MasteringSIDTextBox" Grid.Row="15" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<TextBlock Grid.Row="16" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Label/L1 Toolstamp/Mastering Code" />
<TextBox Name="L1ToolstampTextBox" Grid.Row="16" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<TextBlock Grid.Row="17" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Label/L1 Mould SID" />
<TextBox Name="L1MouldSIDTextBox" Grid.Row="17" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<TextBlock Grid.Row="18" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Label/L1 Additional Mould" />
<TextBox Name="L1AdditionalMouldTextBox" Grid.Row="18" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<TextBlock Grid.Row="19" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Barcode" />
<TextBox Name="BarcodeTextBox" Grid.Row="19" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<!-- This needs to be a multiline textbox -->
<TextBlock Grid.Row="20" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Comments" />
<TextBox Name="CommentsTextBox" Grid.Row="20" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" AcceptsReturn="True" AcceptsTab="True" />
<!-- This needs to be a multiline textbox -->
<TextBlock Grid.Row="21" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Contents" />
<TextBox Name="ContentsTextBox" Grid.Row="21" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" AcceptsReturn="True" AcceptsTab="True"/>
</Grid>
<!-- Version and Editions -->
<Border Grid.Row="1" Margin="5" BorderThickness="1" BorderBrush="Gray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock Text="Version and Editions" Margin="2" HorizontalAlignment="Left" VerticalAlignment="Top" FontWeight="Bold" FontSize="14" Foreground="Gray" />
</Border>
<Grid Grid.Row="1" Margin="10,15,10,10" ColumnDefinitions="1*,1*" RowDefinitions="25,25">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Version" />
<TextBox Name="VersionTextBox" Grid.Row="0" Grid.Column="1" Height="25" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Edition" />
<TextBox Name="EditionTextBox" Grid.Row="1" Grid.Column="1" Height="25" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
</Grid>
<!-- Accept / Cancel -->
<Grid Height="25" Grid.Row="2" Grid.Column="0" ColumnDefinitions="2*,1*,1*">
<Button Name="AcceptButton" Grid.Row="0" Grid.Column="1" Height="25" Width="80" Content="Accept" Click="OnAcceptClick" />
<Button Name="CancelButton" Grid.Row="0" Grid.Column="2" Height="25" Width="80" Content="Cancel" Click="OnCancelClick" />
</Grid>
</Grid>
</Window>

View File

@@ -1,264 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using DICUI.Web;
namespace DICUI.Avalonia
{
public class DiscInformationWindow : Window
{
#region Fields
/// <summary>
/// List of available disc categories
/// </summary>
public List<CategoryComboBoxItem> Categories { get; private set; }
/// <summary>
/// SubmissionInfo object to fill and save
/// </summary>
public SubmissionInfo SubmissionInfo { get; set; }
/// <summary>
/// List of available regions
/// </summary>
public List<RegionComboBoxItem> Regions { get; private set; }
/// <summary>
/// List of available languages
/// </summary>
public List<LanguageComboBoxItem> Languages { get; private set; }
#endregion
public DiscInformationWindow()
{
this.InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
PopulateCategories();
PopulateRegions();
PopulateLanguages();
DisableFieldsIfNeeded();
}
#region Helpers
/// <summary>
/// Disable fields that aren't applicable to the current disc
/// </summary>
private void DisableFieldsIfNeeded()
{
// Only disable for single-layer discs
if (SubmissionInfo.SizeAndChecksums?.Layerbreak == default(long))
{
this.Find<TextBox>("L1MasteringRingTextBox").IsEnabled = false;
this.Find<TextBox>("L1MasteringRingTextBox").Background = Brushes.Gray;
this.Find<TextBox>("L1MasteringSIDTextBox").IsEnabled = false;
this.Find<TextBox>("L1MasteringSIDTextBox").Background = Brushes.Gray;
this.Find<TextBox>("L1ToolstampTextBox").IsEnabled = false;
this.Find<TextBox>("L1ToolstampTextBox").Background = Brushes.Gray;
this.Find<TextBox>("L1MouldSIDTextBox").IsEnabled = false;
this.Find<TextBox>("L1MouldSIDTextBox").Background = Brushes.Gray;
this.Find<TextBox>("L1AdditionalMouldTextBox").IsEnabled = false;
this.Find<TextBox>("L1AdditionalMouldTextBox").Background = Brushes.Gray;
}
}
/// <summary>
/// Load the current contents of the base SubmissionInfo to the UI
/// </summary>
public void Load()
{
// Common Disc Info
if (SubmissionInfo.CommonDiscInfo == null)
SubmissionInfo.CommonDiscInfo = new CommonDiscInfoSection();
this.Find<TextBox>("TitleTextBox").Text = SubmissionInfo.CommonDiscInfo.Title ?? "";
this.Find<TextBox>("ForeignTitleTextBox").Text = SubmissionInfo.CommonDiscInfo.ForeignTitleNonLatin ?? "";
this.Find<TextBox>("DiscNumberLetterTextBox").Text = SubmissionInfo.CommonDiscInfo.DiscNumberLetter ?? "";
this.Find<TextBox>("DiscTitleTextBox").Text = SubmissionInfo.CommonDiscInfo.DiscTitle ?? "";
this.Find<ComboBox>("CategoryComboBox").SelectedIndex = Categories.FindIndex(r => r == SubmissionInfo.CommonDiscInfo.Category);
this.Find<ComboBox>("RegionComboBox").SelectedIndex = Regions.FindIndex(r => r == SubmissionInfo.CommonDiscInfo.Region);
if (SubmissionInfo.CommonDiscInfo.Languages != null)
{
foreach (var language in SubmissionInfo.CommonDiscInfo.Languages)
Languages.Find(l => l == language).IsChecked = true;
}
this.Find<TextBox>("SerialTextBox").Text = SubmissionInfo.CommonDiscInfo.Serial ?? "";
this.Find<TextBox>("L0MasteringRingTextBox").Text = SubmissionInfo.CommonDiscInfo.MasteringRingFirstLayerDataSide ?? "";
this.Find<TextBox>("L0MasteringSIDTextBox").Text = SubmissionInfo.CommonDiscInfo.MasteringSIDCodeFirstLayerDataSide ?? "";
this.Find<TextBox>("L0ToolstampTextBox").Text = SubmissionInfo.CommonDiscInfo.ToolstampMasteringCodeFirstLayerDataSide ?? "";
this.Find<TextBox>("L0MouldSIDTextBox").Text = SubmissionInfo.CommonDiscInfo.MouldSIDCodeFirstLayerDataSide ?? "";
this.Find<TextBox>("L0AdditionalMouldTextBox").Text = SubmissionInfo.CommonDiscInfo.AdditionalMouldFirstLayerDataSide ?? "";
this.Find<TextBox>("L1MasteringRingTextBox").Text = SubmissionInfo.CommonDiscInfo.MasteringRingSecondLayerLabelSide ?? "";
this.Find<TextBox>("L1MasteringSIDTextBox").Text = SubmissionInfo.CommonDiscInfo.MasteringSIDCodeSecondLayerLabelSide ?? "";
this.Find<TextBox>("L1ToolstampTextBox").Text = SubmissionInfo.CommonDiscInfo.ToolstampMasteringCodeSecondLayerLabelSide ?? "";
this.Find<TextBox>("L1MouldSIDTextBox").Text = SubmissionInfo.CommonDiscInfo.MouldSIDCodeSecondLayerLabelSide ?? "";
this.Find<TextBox>("L1AdditionalMouldTextBox").Text = SubmissionInfo.CommonDiscInfo.AdditionalMouldSecondLayerLabelSide ?? "";
this.Find<TextBox>("BarcodeTextBox").Text = SubmissionInfo.CommonDiscInfo.Barcode ?? "";
this.Find<TextBox>("CommentsTextBox").Text = SubmissionInfo.CommonDiscInfo.Comments ?? "";
this.Find<TextBox>("ContentsTextBox").Text = SubmissionInfo.CommonDiscInfo.Contents ?? "";
// Version and Editions
if (SubmissionInfo.VersionAndEditions == null)
SubmissionInfo.VersionAndEditions = new VersionAndEditionsSection();
this.Find<TextBox>("VersionTextBox").Text = SubmissionInfo.VersionAndEditions.Version ?? "";
this.Find<TextBox>("EditionTextBox").Text = SubmissionInfo.VersionAndEditions.OtherEditions ?? "";
}
/// <summary>
/// Get a complete list of categories and fill the combo box
/// </summary>
private void PopulateCategories()
{
var categories = Enum.GetValues(typeof(DiscCategory)).OfType<DiscCategory?>().ToList();
ViewModels.LoggerViewModel.VerboseLogLn("Populating categories, {0} categories found.", categories.Count);
Categories = new List<CategoryComboBoxItem>();
foreach (var category in categories)
{
Categories.Add(new CategoryComboBoxItem(category));
}
this.Find<ComboBox>("CategoryComboBox").Items = Categories;
this.Find<ComboBox>("CategoryComboBox").SelectedIndex = 0;
}
/// <summary>
/// Get a complete list of languages and fill the combo box
/// </summary>
private void PopulateLanguages()
{
var languages = Enum.GetValues(typeof(Language)).OfType<Language?>().ToList();
ViewModels.LoggerViewModel.VerboseLogLn("Populating languages, {0} languages found.", languages.Count);
Languages = new List<LanguageComboBoxItem>();
foreach (var language in languages)
{
Languages.Add(new LanguageComboBoxItem(language));
}
this.Find<ComboBox>("LanguagesComboBox").Items = Languages;
this.Find<ComboBox>("LanguagesComboBox").SelectedIndex = 0;
}
/// <summary>
/// Get a complete list of regions and fill the combo box
/// </summary>
private void PopulateRegions()
{
var regions = Enum.GetValues(typeof(Region)).OfType<Region?>().ToList();
ViewModels.LoggerViewModel.VerboseLogLn("Populating regions, {0} regions found.", regions.Count);
Regions = new List<RegionComboBoxItem>();
foreach (var region in regions)
{
Regions.Add(new RegionComboBoxItem(region));
}
this.Find<ComboBox>("RegionComboBox").Items = Regions;
this.Find<ComboBox>("RegionComboBox").SelectedIndex = 0;
}
/// <summary>
/// Save the current contents of the UI to the base SubmissionInfo
/// </summary>
private void Save()
{
// Common Disc Info
if (SubmissionInfo.CommonDiscInfo == null)
SubmissionInfo.CommonDiscInfo = new CommonDiscInfoSection();
SubmissionInfo.CommonDiscInfo.Title = this.Find<TextBox>("TitleTextBox").Text ?? "";
SubmissionInfo.CommonDiscInfo.ForeignTitleNonLatin = this.Find<TextBox>("ForeignTitleTextBox").Text ?? "";
SubmissionInfo.CommonDiscInfo.DiscNumberLetter = this.Find<TextBox>(" DiscNumberLetterTextBox").Text ?? "";
SubmissionInfo.CommonDiscInfo.DiscTitle = this.Find<TextBox>("DiscTitleTextBox").Text ?? "";
SubmissionInfo.CommonDiscInfo.Category = (this.Find<ComboBox>("CategoryComboBox").SelectedItem as CategoryComboBoxItem)?.Value ?? DiscCategory.Games;
SubmissionInfo.CommonDiscInfo.Region = (this.Find<ComboBox>("RegionComboBox").SelectedItem as RegionComboBoxItem)?.Value ?? Region.World;
var languages = new List<Language?>();
foreach (var language in Languages)
{
if (language.IsChecked)
languages.Add(language.Value);
}
if (languages.Count == 0)
languages.Add(null);
SubmissionInfo.CommonDiscInfo.Languages = languages.ToArray();
SubmissionInfo.CommonDiscInfo.Serial = this.Find<TextBox>("SerialTextBox").Text ?? "";
SubmissionInfo.CommonDiscInfo.MasteringRingFirstLayerDataSide = this.Find<TextBox>("L0MasteringRingTextBox").Text ?? "";
SubmissionInfo.CommonDiscInfo.MasteringSIDCodeFirstLayerDataSide = this.Find<TextBox>("L0MasteringSIDTextBox").Text ?? "";
SubmissionInfo.CommonDiscInfo.ToolstampMasteringCodeFirstLayerDataSide = this.Find<TextBox>("L0ToolstampTextBox").Text ?? "";
SubmissionInfo.CommonDiscInfo.MouldSIDCodeFirstLayerDataSide = this.Find<TextBox>("L0MouldSIDTextBox").Text ?? "";
SubmissionInfo.CommonDiscInfo.AdditionalMouldFirstLayerDataSide = this.Find<TextBox>("L0AdditionalMouldTextBox").Text ?? "";
SubmissionInfo.CommonDiscInfo.MasteringRingSecondLayerLabelSide = this.Find<TextBox>("L1MasteringRingTextBox").Text ?? "";
SubmissionInfo.CommonDiscInfo.MasteringSIDCodeSecondLayerLabelSide = this.Find<TextBox>("L1MasteringSIDTextBox").Text ?? "";
SubmissionInfo.CommonDiscInfo.ToolstampMasteringCodeSecondLayerLabelSide = this.Find<TextBox>("L1ToolstampTextBox").Text ?? "";
SubmissionInfo.CommonDiscInfo.MouldSIDCodeSecondLayerLabelSide = this.Find<TextBox>("L1MouldSIDTextBox").Text ?? "";
SubmissionInfo.CommonDiscInfo.AdditionalMouldSecondLayerLabelSide = this.Find<TextBox>("L1AdditionalMouldTextBox").Text ?? "";
SubmissionInfo.CommonDiscInfo.Barcode = this.Find<TextBox>("BarcodeTextBox").Text ?? "";
SubmissionInfo.CommonDiscInfo.Comments = this.Find<TextBox>("CommentsTextBox").Text ?? "";
SubmissionInfo.CommonDiscInfo.Contents = this.Find<TextBox>("ContentsTextBox").Text ?? "";
// Version and Editions
if (SubmissionInfo.VersionAndEditions == null)
SubmissionInfo.VersionAndEditions = new VersionAndEditionsSection();
SubmissionInfo.VersionAndEditions.Version = this.Find<TextBox>("VersionTextBox").Text ?? "";
SubmissionInfo.VersionAndEditions.OtherEditions = this.Find<TextBox>("EditionTextBox").Text ?? "";
}
#endregion
#region Event Handlers
/// <summary>
/// Handler for AcceptButton Click event
/// </summary>
private void OnAcceptClick(object sender, RoutedEventArgs e)
{
Save();
Hide();
}
/// <summary>
/// Handler for CancelButton Click event
/// </summary>
private void OnCancelClick(object sender, RoutedEventArgs e)
{
Hide();
}
/// <summary>
/// Handler for DiscInformationWindow Closed event
/// </summary>
private void OnClosed(object sender, EventArgs e)
{
Hide();
}
#endregion
}
}

View File

@@ -1,32 +0,0 @@
using System;
using System.Globalization;
using Avalonia.Data.Converters;
using DICUI.Data;
using DICUI.Utilities;
namespace DICUI.Avalonia
{
/// <summary>
/// Used to provide a converter to XAML files to render comboboxes with enum values
/// </summary>
public class EnumDescriptionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// Common
if (value is MediaType?)
return ((MediaType?)value).LongName();
else if (value is KnownSystem?)
return ((KnownSystem?)value).LongName();
// Default
else
return "";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return string.Empty;
}
}
}

View File

@@ -1,40 +0,0 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DICUI.Avalonia"
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="350" Width="600" Height="350"
x:Class="DICUI.Avalonia.LogWindow" Icon="Icon.ico" CanResize="False"
Title="Log Window">
<Grid RowDefinitions="40,250,40">
<!-- Progress Bar -->
<Grid Grid.Row="0" Height="25" Margin="10 10 10 0">
<ProgressBar Name="ProgressBar" />
<TextBlock Name="ProgressLabel" Grid.Row="0" Height="25" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
<!-- Log Area -->
<Border Grid.Row="1" Background="White" BorderBrush="Gainsboro" BorderThickness="1" Margin="10">
<ScrollViewer Name="OutputViewer">
<TextBox Name="Output" FontFamily="Consolas" Background="Gray" IsReadOnly="True" />
</ScrollViewer>
</Border>
<!-- Options -->
<Grid Grid.Row="2" RowDefinitions="Auto" ColumnDefinitions="Auto,Auto,3*,Auto,Auto,Auto">
<CheckBox Name="VerboseCheckBox" Grid.Column="0" Height="25" VerticalAlignment="Center" Margin="10 0 0 10"
Content="Verbose" DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=VerboseLogging}"
ToolTip.Tip="Enable verbose logging of tasks" />
<CheckBox Name="OpenAtStartupCheckBox" Grid.Column="1" Grid.ColumnSpan="2" Height="25" VerticalAlignment="Center" Margin="10 0 0 10"
Content="Open at startup" DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=OpenLogWindowAtStartup}"
ToolTip.Tip="Open this window at startup" />
<Button Margin="0 0 10 10" Grid.Column="3" Height="25" Width="60" Content="Clear" HorizontalAlignment="Right" Click="OnClearButton" />
<Button Margin="0 0 10 10" Grid.Column="4" Height="25" Width="60" Content="Hide" HorizontalAlignment="Right" Click="OnHideButton" />
<Button Margin="0 0 10 10" Grid.Column="5" Height="25" Width="60" Content="Save" HorizontalAlignment="Right" Click="OnSaveButton" />
</Grid>
</Grid>
</Window>

View File

@@ -1,82 +0,0 @@
using System.IO;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
namespace DICUI.Avalonia
{
public class LogWindow : Window
{
public LogWindow()
{
this.InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
}
/// <summary>
/// Adjust the position of the log window if the main window is moved
/// </summary>
public void AdjustPositionToMainWindow()
{
var owner = Owner as Window;
Position = new PixelPoint(
owner.Position.X,
owner.Position.Y + (int)owner.Height + Constants.LogWindowMarginFromMainWindow);
}
/// <summary>
/// Append rich text to the scrolling element
/// </summary>
/// <param name="text">Text to add, including newlines</param>
/// <param name="color">Color to format the text</param>
public void AppendToTextBox(string text, ISolidColorBrush color)
{
// TODO: Use brush color
this.Find<TextBox>("Output").Text += $"{text}\n";
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
#region Event Handlers
/// <summary>
/// Handler for ClearButton Click event
/// </summary>
private void OnClearButton(object sender, RoutedEventArgs e)
{
this.Find<TextBox>("Output").Text = string.Empty;
}
/// <summary>
/// Handler for HideButton Click event
/// </summary>
private void OnHideButton(object sender, RoutedEventArgs e)
{
ViewModels.LoggerViewModel.WindowVisible = false;
//TODO: this should be bound directly to WindowVisible property in two way fashion
// we need to study how to properly do it in XAML
(Owner as MainWindow).Find<CheckBox>("ShowLogCheckBox").IsChecked = false;
}
/// <summary>
/// Handler for SaveButton Click event
/// </summary>
private void OnSaveButton(object sender, RoutedEventArgs e)
{
using (StreamWriter tw = new StreamWriter(File.OpenWrite("console.log")))
{
tw.Write(this.Find<TextBox>("Output").Text);
}
}
#endregion
}
}

View File

@@ -1,109 +0,0 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DICUI.Avalonia"
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="450" Width="600" Height="450"
x:Class="DICUI.Avalonia.MainWindow" Icon="Icon.ico" CanResize="False"
Title="DICUI" WindowStartupLocation="CenterScreen"
PositionChanged="MainWindowLocationChanged" Activated="MainWindowActivated" Closing="MainWindowClosing">
<Window.Resources>
<local:EnumDescriptionConverter x:Key="enumConverter" />
</Window.Resources>
<Grid ColumnDefinitions="4*,13*" RowDefinitions="30,4*,1*,1*">
<!-- Menu Bar -->
<StackPanel VerticalAlignment="Top" Grid.ColumnSpan="4">
<Menu Height="20" >
<MenuItem Header="_File">
<MenuItem Name="AppExitMenuItem" Header="E_xit" HorizontalAlignment="Left" Width="185" Click="AppExitMenuItemClick" />
</MenuItem>
<MenuItem Header="_Tools">
<MenuItem Name="OptionsMenuItem" Header="_Options" HorizontalAlignment="Left" Width="185" Click="OptionsMenuItemClick" />
<MenuItem Name="ShowLogMenuItem" Header="Show _Log Window" HorizontalAlignment="Left" Width="185">
<MenuItem.Icon>
<CheckBox Name="ShowLogCheckBox" BorderThickness="0" DataContext="{Binding Source={x:Static local:ViewModels.LoggerViewModel}}" IsChecked="{Binding Path=WindowVisible}" />
</MenuItem.Icon>
</MenuItem>
</MenuItem>
<MenuItem Header="_Help">
<MenuItem Name="AboutMenuItem" Header="_About" HorizontalAlignment="Left" Width="185" Click="AboutMenuItemClick" />
<MenuItem Name="CheckForUpdatesMenuItem" Header="_Check for Updates" HorizontalAlignment="Left" Width="185" Click="CheckForUpdatesMenuItemClick" />
</MenuItem>
</Menu>
</StackPanel>
<!-- Settings -->
<Border Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="5,5,5.2,5.4" BorderThickness="1" BorderBrush="Gray" HorizontalAlignment="Stretch">
<TextBlock Text="Settings" Margin="2" HorizontalAlignment="Left" VerticalAlignment="Top" FontWeight="Bold" FontSize="14" Foreground="Gray" />
</Border>
<Grid Grid.Row="1" Grid.Column="0" Margin="15,25,15.2,10.4" Grid.ColumnSpan="2" ColumnDefinitions="1*,2.5*" RowDefinitions="1*,1*,1*,1*,1*,1*">
<!-- System / Media Type Selection -->
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Text="System/Media Type" />
<ComboBox Name="SystemTypeComboBox" Grid.Row="0" Grid.Column="1" Height="25" Width="250" HorizontalAlignment="Left" AutoScrollToSelectedItem="True" SelectionChanged="SystemTypeComboBoxSelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" Foreground="{Binding Path=Foreground}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ComboBox Name="MediaTypeComboBox" Grid.Row="0" Grid.Column="1" Height="25" Width="140" HorizontalAlignment="Right" AutoScrollToSelectedItem="True" SelectionChanged="MediaTypeComboBoxSelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource enumConverter}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<!-- Output Filename -->
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Text="Output Filename" />
<TextBox Name="OutputFilenameTextBox" Grid.Row="1" Grid.Column="1" Height="25" ScrollViewer.VerticalScrollBarVisibility="Disabled" TextInput="OutputFilenameTextBoxTextChanged" />
<!-- Output Directory -->
<TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Text="Output Directory" />
<TextBox Name="OutputDirectoryTextBox" Grid.Row="2" Grid.Column="1" Height="25" Width="345" HorizontalAlignment="Left" ScrollViewer.VerticalScrollBarVisibility="Disabled" TextInput="OutputDirectoryTextBoxTextChanged" />
<Button Name="OutputDirectoryBrowseButton" Grid.Row="2" Grid.Column="1" Height="25" Width="50" HorizontalAlignment="Right" Content="Browse" Click="OutputDirectoryBrowseButtonClick" />
<!-- Drive Letter -->
<TextBlock Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" Text="Drive Letter" />
<ComboBox Name="DriveLetterComboBox" Grid.Row="3" Grid.Column="1" Height="25" Width="60" HorizontalAlignment="Left" SelectionChanged="DriveLetterComboBoxSelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Letter}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<!-- Drive Speed -->
<TextBlock Grid.Row="4" Grid.Column="0" VerticalAlignment="Center" Text="Drive Speed" />
<ComboBox Name="DriveSpeedComboBox" Grid.Row="4" Grid.Column="1" Height="25" Width="60" HorizontalAlignment="Left" SelectionChanged="DriveSpeedComboBoxSelectionChanged" />
<!-- Parameters -->
<TextBlock Grid.Row="5" Grid.Column="0" VerticalAlignment="Center" Text="Parameters" />
<TextBox Name="ParametersTextBox" Grid.Row="5" Grid.Column="1" Height="25" Width="370" HorizontalAlignment="Left" ScrollViewer.VerticalScrollBarVisibility="Disabled" IsEnabled="False" />
<CheckBox Name="EnableParametersCheckBox" Grid.Row="5" Grid.Column="1" Height="25" HorizontalAlignment="Right" IsChecked="False" Click="EnableParametersCheckBoxClick" />
</Grid>
<!-- Controls -->
<Border Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="5,4.6,5.2,4.8" BorderThickness="1" BorderBrush="Gray" HorizontalAlignment="Stretch">
<TextBlock Text="Controls" Margin="2" HorizontalAlignment="Left" VerticalAlignment="Top" FontWeight="Bold" FontSize="14" Foreground="Gray" />
</Border>
<Grid Grid.Row="2" Grid.Column="0" Margin="15,19.6,15.2,9.8" Grid.ColumnSpan="2" ColumnDefinitions="1*,1*,1*,1*" RowDefinitions="1*">
<Button Name="StartStopButton" Grid.Row="0" Grid.Column="0" Height="25" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Start Dumping" Click="StartStopButtonClick" IsEnabled="False" />
<Button Name="MediaScanButton" Grid.Row="0" Grid.Column="1" Height="25" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Scan For Media" Click="MediaScanButtonClick" />
<Button Name="CopyProtectScanButton" Grid.Row="0" Grid.Column="2" Height="25" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Scan For Protection" Click="CopyProtectScanButtonClick" />
<CheckBox Name="EjectWhenDoneCheckBox" Grid.Row="0" Grid.Column="3" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Eject When Done" IsChecked="False" />
</Grid>
<!-- Status -->
<Border Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Margin="5,5.2,5.2,4.8" BorderThickness="1" BorderBrush="Gray" HorizontalAlignment="Stretch">
<TextBlock Text="Status" Margin="2" HorizontalAlignment="Left" VerticalAlignment="Top" FontWeight="Bold" FontSize="14" Foreground="Gray" />
</Border>
<Grid Grid.Row="3" Grid.Column="0" Margin="15,20.2,15.2,9.8" Grid.ColumnSpan="2" ColumnDefinitions="1*" RowDefinitions="1*">
<TextBlock Name="StatusLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center" Text="Waiting for media..." />
</Grid>
</Grid>
</Window>

View File

@@ -1,820 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using BurnOutSharp;
using DICUI.Data;
using DICUI.Utilities;
using DICUI.Web;
namespace DICUI.Avalonia
{
public class MainWindow : Window
{
#region Fields
/// <summary>
/// Currently selected or detected media type
/// </summary>
public MediaType? CurrentMediaType { get; private set; }
/// <summary>
/// Current list of drives
/// </summary>
public List<Drive> Drives { get; private set; }
/// <summary>
/// Current dumping environment
/// </summary>
public DumpEnvironment Env { get; private set; }
/// <summary>
/// Current list of supported media types
/// </summary>
public List<MediaType?> MediaTypes { get; private set; } = new List<MediaType?>();
/// <summary>
/// Current list of supported system profiles
/// </summary>
public List<KnownSystemComboBoxItem> Systems { get; private set; }
/// <summary>
/// Current UI options
/// </summary>
public UIOptions UIOptions { get; private set; } = new UIOptions();
#endregion
#region Private Instance Variables
/// <summary>
/// Current attached LogWindow
/// </summary>
private LogWindow logWindow;
#endregion
public MainWindow()
{
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
// Load the options
ViewModels.OptionsViewModel = new OptionsViewModel(UIOptions);
// Load the log window
logWindow = new LogWindow();
logWindow.Owner = this;
ViewModels.LoggerViewModel.SetWindow(logWindow);
// Disable buttons until we load
this.Find<Button>("StartStopButton").IsEnabled = false;
this.Find<Button>("MediaScanButton").IsEnabled = false;
this.Find<Button>("CopyProtectScanButton").IsEnabled = false;
// TODO: If log window open, "dock" it to the current Window
if (UIOptions.OpenLogWindowAtStartup)
{
//TODO: this should be bound directly to WindowVisible property in two way fashion
// we need to study how to properly do it in XAML
this.Find<CheckBox>("ShowLogCheckBox").IsChecked = true;
ViewModels.LoggerViewModel.WindowVisible = true;
}
// Populate the list of systems
this.Find<TextBlock>("StatusLabel").Text = "Creating system list, please wait!";
PopulateSystems();
// Populate the list of drives
this.Find<TextBlock>("StatusLabel").Text = "Creating drive list, please wait!";
PopulateDrives();
}
#region Helpers
/// <summary>
/// Browse for an output folder
/// </summary>
private async void BrowseFolder()
{
OpenFolderDialog folderDialog = new OpenFolderDialog { Directory = AppDomain.CurrentDomain.BaseDirectory };
string directory = await folderDialog.ShowAsync(this);
if (!string.IsNullOrWhiteSpace(directory))
this.Find<TextBox>("OutputDirectoryTextBox").Text = directory;
}
/// <summary>
/// Cache the current disc type to internal variable
/// </summary>
private void CacheCurrentDiscType()
{
// Get the drive letter from the selected item
if (this.Find<ComboBox>("DriveLetterComboBox").SelectedItem is Drive drive)
{
// Get the current media type
if (!UIOptions.SkipMediaTypeDetection)
{
ViewModels.LoggerViewModel.VerboseLog("Trying to detect media type for drive {0}.. ", drive.Letter);
CurrentMediaType = Validators.GetMediaType(drive);
ViewModels.LoggerViewModel.VerboseLogLn(CurrentMediaType == null ? "unable to detect." : ("detected " + CurrentMediaType.LongName() + "."));
}
}
}
/// <summary>
/// Create a DumpEnvironment with all current settings
/// </summary>
/// <returns>Filled DumpEnvironment instance</returns>
private DumpEnvironment DetermineEnvironment()
{
// Populate the new environment
var env = new DumpEnvironment(UIOptions.Options,
this.Find<TextBox>("OutputDirectoryTextBox").Text,
this.Find<TextBox>("OutputFilenameTextBox").Text,
this.Find<ComboBox>("DriveLetterComboBox").SelectedItem as Drive,
this.Find<ComboBox>("SystemTypeComboBox").SelectedItem as KnownSystemComboBoxItem,
this.Find<ComboBox>("MediaTypeComboBox").SelectedItem as MediaType?,
this.Find<TextBox>("ParametersTextBox").Text);
// Disable automatic reprocessing of the textboxes until we're done
this.Find<TextBox>("OutputDirectoryTextBox").TextInput -= OutputDirectoryTextBoxTextChanged;
this.Find<TextBox>("OutputFilenameTextBox").TextInput -= OutputFilenameTextBoxTextChanged;
this.Find<TextBox>("OutputDirectoryTextBox").Text = env.OutputDirectory;
this.Find<TextBox>("OutputFilenameTextBox").Text = env.OutputFilename;
this.Find<TextBox>("OutputDirectoryTextBox").TextInput += OutputDirectoryTextBoxTextChanged;
this.Find<TextBox>("OutputFilenameTextBox").TextInput += OutputFilenameTextBoxTextChanged;
return env;
}
/// <summary>
/// Ensure information is consistent with the currently selected disc type
/// </summary>
private void EnsureDiscInformation()
{
// Get the current environment information
Env = DetermineEnvironment();
// Take care of null cases
if (Env.System == null)
Env.System = KnownSystem.NONE;
if (Env.Type == null)
Env.Type = MediaType.NONE;
// Get the status to write out
Result result = Validators.GetSupportStatus(Env.System, Env.Type);
this.Find<TextBlock>("StatusLabel").Text = result.Message;
// Set the index for the current disc type
SetCurrentDiscType();
this.Find<Button>("StartStopButton").IsEnabled = result && (Drives != null && Drives.Count > 0 ? true : false);
// If we're in a type that doesn't support drive speeds
this.Find<ComboBox>("DriveSpeedComboBox").IsEnabled = Env.Type.DoesSupportDriveSpeed();
// If input params are not enabled, generate the full parameters from the environment
if (!this.Find<TextBox>("ParametersTextBox").IsEnabled)
{
string generated = Env.GetFullParameters((int?)this.Find<ComboBox>("DriveSpeedComboBox").SelectedItem);
if (generated != null)
this.Find<TextBox>("ParametersTextBox").Text = generated;
}
}
/// <summary>
/// Get the default output directory name from the currently selected drive
/// </summary>
/// <param name="driveChanged">Force an updated name if the drive letter changes</param>
private void GetOutputNames(bool driveChanged)
{
Drive drive = this.Find<ComboBox>("DriveLetterComboBox").SelectedItem as Drive;
KnownSystem? systemType = this.Find<ComboBox>("SystemTypeComboBox").SelectedItem as KnownSystemComboBoxItem;
MediaType? mediaType = this.Find<ComboBox>("MediaTypeComboBox").SelectedItem as MediaType?;
// Set the output directory, if we changed drives or it's not already
if (driveChanged || string.IsNullOrEmpty(this.Find<TextBox>("OutputDirectoryTextBox").Text))
this.Find<TextBox>("OutputDirectoryTextBox").Text = Path.Combine(UIOptions.DefaultOutputPath, drive?.VolumeLabel ?? string.Empty);
// Get the extension for the file for the next two statements
string extension = Env?.GetExtension(mediaType);
// Set the output filename, if we changed drives or it's not already
if (driveChanged || string.IsNullOrEmpty(this.Find<TextBox>("OutputFilenameTextBox").Text))
this.Find<TextBox>("OutputFilenameTextBox").Text = (drive?.VolumeLabel ?? systemType.LongName()) + (extension ?? ".bin");
// If the extension for the file changed, update that automatically
else if (Path.GetExtension(this.Find<TextBox>("OutputFilenameTextBox").Text) != extension)
this.Find<TextBox>("OutputFilenameTextBox").Text = Path.GetFileNameWithoutExtension(this.Find<TextBox>("OutputFilenameTextBox").Text) + (extension ?? ".bin");
}
/// <summary>
/// Get a complete list of active disc drives and fill the combo box
/// </summary>
/// <remarks>TODO: Find a way for this to periodically run, or have it hook to a "drive change" event</remarks>
private void PopulateDrives()
{
ViewModels.LoggerViewModel.VerboseLogLn("Scanning for drives..");
// Always enable the disk scan
this.Find<Button>("MediaScanButton").IsEnabled = true;
// Populate the list of drives and add it to the combo box
Drives = Validators.CreateListOfDrives(UIOptions.IgnoreFixedDrives);
this.Find<ComboBox>("DriveLetterComboBox").Items = Drives;
if (Drives.Any())
{
// Check for active optical drives first
int index = Drives.FindIndex(d => d.MarkedActive && d.InternalDriveType == InternalDriveType.Optical);
// Then we check for floppy drives
if (index == -1)
index = Drives.FindIndex(d => d.MarkedActive && d.InternalDriveType == InternalDriveType.Floppy);
// Then we try all other drive types
if (index == -1)
index = Drives.FindIndex(d => d.MarkedActive);
// Set the selected index
this.Find<ComboBox>("DriveLetterComboBox").SelectedIndex = (index != -1 ? index : 0);
this.Find<TextBlock>("StatusLabel").Text = "Valid drive found! Choose your Media Type";
this.Find<Button>("CopyProtectScanButton").IsEnabled = true;
// Get the current media type
if (!UIOptions.SkipSystemDetection && index != -1)
{
ViewModels.LoggerViewModel.VerboseLog("Trying to detect system for drive {0}.. ", Drives[index].Letter);
var currentSystem = Validators.GetKnownSystem(Drives[index]);
ViewModels.LoggerViewModel.VerboseLogLn(currentSystem == null || currentSystem == KnownSystem.NONE ? "unable to detect." : ("detected " + currentSystem.LongName() + "."));
if (currentSystem != null && currentSystem != KnownSystem.NONE)
{
int sysIndex = Systems.FindIndex(s => s == currentSystem);
this.Find<ComboBox>("SystemTypeComboBox").SelectedIndex = sysIndex;
}
}
// Only enable the start/stop if we don't have the default selected
this.Find<Button>("StartStopButton").IsEnabled = (this.Find<ComboBox>("SystemTypeComboBox").SelectedItem as KnownSystemComboBoxItem) != KnownSystem.NONE;
ViewModels.LoggerViewModel.VerboseLogLn("Found {0} drives: {1}", Drives.Count, string.Join(", ", Drives.Select(d => d.Letter)));
}
else
{
this.Find<ComboBox>("DriveLetterComboBox").SelectedIndex = -1;
this.Find<TextBlock>("StatusLabel").Text = "No valid drive found!";
this.Find<Button>("StartStopButton").IsEnabled = false;
this.Find<Button>("CopyProtectScanButton").IsEnabled = false;
ViewModels.LoggerViewModel.VerboseLogLn("Found no drives");
}
}
/// <summary>
/// Populate media type according to system type
/// </summary>
private void PopulateMediaType()
{
KnownSystem? currentSystem = this.Find<ComboBox>("SystemTypeComboBox").SelectedItem as KnownSystemComboBoxItem;
if (currentSystem != null)
{
MediaTypes = Validators.GetValidMediaTypes(currentSystem);
this.Find<ComboBox>("MediaTypeComboBox").Items = MediaTypes;
this.Find<ComboBox>("MediaTypeComboBox").IsEnabled = MediaTypes.Count > 1;
this.Find<ComboBox>("MediaTypeComboBox").SelectedIndex = (MediaTypes.IndexOf(CurrentMediaType) >= 0 ? MediaTypes.IndexOf(CurrentMediaType) : 0);
}
else
{
this.Find<ComboBox>("MediaTypeComboBox").Items = null;
this.Find<ComboBox>("MediaTypeComboBox").IsEnabled = false;
this.Find<ComboBox>("MediaTypeComboBox").SelectedIndex = -1;
}
}
/// <summary>
/// Get a complete list of supported systems and fill the combo box
/// </summary>
private void PopulateSystems()
{
var knownSystems = Validators.CreateListOfSystems();
ViewModels.LoggerViewModel.VerboseLogLn("Populating systems, {0} systems found.", knownSystems.Count);
Dictionary<KnownSystemCategory, List<KnownSystem?>> mapping = knownSystems
.GroupBy(s => s.Category())
.ToDictionary(
k => k.Key,
v => v
.OrderBy(s => s.LongName())
.ToList()
);
Systems = new List<KnownSystemComboBoxItem>()
{
new KnownSystemComboBoxItem(KnownSystem.NONE),
};
foreach (var group in mapping)
{
Systems.Add(new KnownSystemComboBoxItem(group.Key));
group.Value.ForEach(system => Systems.Add(new KnownSystemComboBoxItem(system)));
}
this.Find<ComboBox>("SystemTypeComboBox").Items = Systems;
this.Find<ComboBox>("SystemTypeComboBox").SelectedIndex = 0;
this.Find<Button>("StartStopButton").IsEnabled = false;
}
/// <summary>
/// Process the current custom parameters back into UI values
/// </summary>
private void ProcessCustomParameters()
{
Env.SetParameters(this.Find<TextBox>("ParametersTextBox").Text);
if (Env.Parameters == null)
return;
int driveIndex = Drives.Select(d => d.Letter).ToList().IndexOf(Env.Parameters.InputPath()[0]);
if (driveIndex > -1)
this.Find<ComboBox>("DriveLetterComboBox").SelectedIndex = driveIndex;
int driveSpeed = Env.Parameters.GetSpeed() ?? -1;
if (driveSpeed > 0)
this.Find<ComboBox>("DriveSpeedComboBox").SelectedItem = driveSpeed;
else
Env.Parameters.SetSpeed((int?)this.Find<ComboBox>("DriveSpeedComboBox").SelectedItem);
string trimmedPath = Env.Parameters.OutputPath()?.Trim('"') ?? string.Empty;
string outputDirectory = Path.GetDirectoryName(trimmedPath);
string outputFilename = Path.GetFileName(trimmedPath);
if (!string.IsNullOrWhiteSpace(outputDirectory))
this.Find<TextBox>("OutputDirectoryTextBox").Text = outputDirectory;
else
outputDirectory = this.Find<TextBox>("OutputDirectoryTextBox").Text;
if (!string.IsNullOrWhiteSpace(outputFilename))
this.Find<TextBox>("OutputFilenameTextBox").Text = outputFilename;
else
outputFilename = this.Find<TextBox>("OutputFilenameTextBox").Text;
MediaType? mediaType = Env.Parameters.GetMediaType();
int mediaTypeIndex = MediaTypes.IndexOf(mediaType);
if (mediaTypeIndex > -1)
this.Find<ComboBox>("MediaTypeComboBox").SelectedIndex = mediaTypeIndex;
}
/// <summary>
/// Scan and show copy protection for the current disc
/// </summary>
private async void ScanAndShowProtection()
{
if (Env == null)
Env = DetermineEnvironment();
if (Env.Drive.Letter != default(char))
{
ViewModels.LoggerViewModel.VerboseLogLn("Scanning for copy protection in {0}", Env.Drive.Letter);
var tempContent = this.Find<TextBlock>("StatusLabel").Text;
this.Find<TextBlock>("StatusLabel").Text = "Scanning for copy protection... this might take a while!";
this.Find<Button>("StartStopButton").IsEnabled = false;
this.Find<Button>("MediaScanButton").IsEnabled = false;
this.Find<Button>("CopyProtectScanButton").IsEnabled = false;
var progress = new Progress<FileProtection>();
progress.ProgressChanged += ProgressUpdated;
string protections = await Validators.RunProtectionScanOnPath(Env.Drive.Letter + ":\\");
// If SmartE is detected on the current disc, remove `/sf` from the flags for DIC only
if (Env.InternalProgram == InternalProgram.DiscImageCreator && protections.Contains("SmartE"))
{
((DiscImageCreator.Parameters)Env.Parameters)[DiscImageCreator.Flag.ScanFileProtect] = false;
ViewModels.LoggerViewModel.VerboseLogLn($"SmartE detected, removing {DiscImageCreator.FlagStrings.ScanFileProtect} from parameters");
}
if (!ViewModels.LoggerViewModel.WindowVisible)
{
new Window()
{
Title = "Detected Protection",
Content = protections,
SizeToContent = SizeToContent.WidthAndHeight,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
}.ShowDialog(this);
}
ViewModels.LoggerViewModel.VerboseLog("Detected the following protections in {0}:\r\n\r\n{1}", Env.Drive.Letter, protections);
this.Find<TextBlock>("StatusLabel").Text = tempContent;
this.Find<Button>("StartStopButton").IsEnabled = true;
this.Find<Button>("MediaScanButton").IsEnabled = true;
this.Find<Button>("CopyProtectScanButton").IsEnabled = true;
}
}
/// <summary>
/// Set the current disc type in the combo box
/// </summary>
private void SetCurrentDiscType()
{
// If we have an invalid current type, we don't care and return
if (CurrentMediaType == null || CurrentMediaType == MediaType.NONE)
return;
// Now set the selected item, if possible
int index = MediaTypes.FindIndex(kvp => kvp.Value == CurrentMediaType);
if (index != -1)
this.Find<ComboBox>("MediaTypeComboBox").SelectedIndex = index;
else
this.Find<TextBlock>("StatusLabel").Text = $"Disc of type '{Converters.LongName(CurrentMediaType)}' found, but the current system does not support it!";
}
/// <summary>
/// Set the drive speed based on reported maximum and user-defined option
/// </summary>
private void SetSupportedDriveSpeed()
{
// Set the drive speed list that's appropriate
var values = Constants.GetSpeedsForMediaType(CurrentMediaType);
this.Find<ComboBox>("DriveSpeedComboBox").Items = values;
ViewModels.LoggerViewModel.VerboseLogLn("Supported media speeds: {0}", string.Join(",", values));
// Set the selected speed
int speed = UIOptions.GetPreferredDumpSpeedForMediaType(CurrentMediaType);
ViewModels.LoggerViewModel.VerboseLogLn("Setting drive speed to: {0}", speed);
this.Find<ComboBox>("DriveSpeedComboBox").SelectedItem = speed;
}
/// <summary>
/// Begin the dumping process using the given inputs
/// </summary>
private async void StartDumping()
{
// One last check to determine environment, just in case
Env = DetermineEnvironment();
// If still in custom parameter mode, check that users meant to continue or not
if (this.Find<CheckBox>("EnableParametersCheckBox").IsChecked == true)
{
MessageBoxResult result = await MessageBox.Show(this, "It looks like you have custom parameters that have not been saved. Would you like to apply those changes before starting to dump?", "Custom Changes", MessageBoxButtons.YesNoCancel);
if (result == MessageBoxResult.Yes)
{
this.Find<CheckBox>("EnableParametersCheckBox").IsChecked = false;
this.Find<TextBox>("ParametersTextBox").IsEnabled = false;
ProcessCustomParameters();
}
else if (result == MessageBoxResult.Cancel)
{
return;
}
// If "No", then we continue with the current known environment
}
// Fix the output paths
Env.FixOutputPaths();
try
{
// Validate that the user explicitly wants an inactive drive to be considered for dumping
if (!Env.Drive.MarkedActive)
{
MessageBoxResult mbresult = await MessageBox.Show(this, "The currently selected drive does not appear to contain a disc! Are you sure you want to continue?", "Missing Disc", MessageBoxButtons.YesNo);
if (mbresult == MessageBoxResult.No || mbresult == MessageBoxResult.Cancel)
{
ViewModels.LoggerViewModel.VerboseLogLn("Dumping aborted!");
return;
}
}
// If a complete dump already exists
if (Env.FoundAllFiles())
{
MessageBoxResult mbresult = await MessageBox.Show(this, "A complete dump already exists! Are you sure you want to overwrite?", "Overwrite?", MessageBoxButtons.YesNo);
if (mbresult == MessageBoxResult.No || mbresult == MessageBoxResult.Cancel)
{
ViewModels.LoggerViewModel.VerboseLogLn("Dumping aborted!");
return;
}
}
this.Find<Button>("StartStopButton").Content = Constants.StopDumping;
this.Find<Button>("CopyProtectScanButton").IsEnabled = false;
this.Find<TextBlock>("StatusLabel").Text = "Beginning dumping process";
ViewModels.LoggerViewModel.VerboseLogLn("Starting dumping process..");
// Get progress indicators
var resultProgress = new Progress<Result>();
resultProgress.ProgressChanged += ProgressUpdated;
var protectionProgress = new Progress<FileProtection>();
protectionProgress.ProgressChanged += ProgressUpdated;
// Run the program with the parameters
Result result = await Env.Run(resultProgress);
// If we didn't execute a dumping command we cannot get submission output
if (!Env.Parameters.IsDumpingCommand())
{
ViewModels.LoggerViewModel.VerboseLogLn("No dumping command was run, submission information will not be gathered.");
this.Find<TextBlock>("StatusLabel").Text = "Execution complete!";
this.Find<Button>("StartStopButton").Content = Constants.StartDumping;
this.Find<Button>("CopyProtectScanButton").IsEnabled = true;
return;
}
if (result)
{
// Verify dump output and save it
result = await Env.VerifyAndSaveDumpOutput(resultProgress,
protectionProgress,
this.Find<CheckBox>("EjectWhenDoneCheckBox").IsChecked,
UIOptions.ResetDriveAfterDump,
(si) =>
{
var discInformationWindow = new DiscInformationWindow();
discInformationWindow.SubmissionInfo = si;
discInformationWindow.Load();
discInformationWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
discInformationWindow.ShowDialog(this).ConfigureAwait(false).GetAwaiter().GetResult();
return true;
}
);
}
}
catch
{
// No-op, we don't care what it was
}
finally
{
this.Find<Button>("StartStopButton").Content = Constants.StartDumping;
this.Find<Button>("CopyProtectScanButton").IsEnabled = true;
}
}
#endregion
#region Event Handlers
/// <summary>
/// Handler for AboutMenuItem Click event
/// </summary>
private void AboutMenuItemClick(object sender, RoutedEventArgs e)
{
MessageBox.Show(this, $"darksabre76 - Project Lead / Backend Design"
+ $"{Environment.NewLine}ReignStumble - Former Project Lead / UI Design"
+ $"{Environment.NewLine}Jakz - Primary Feature Contributor"
+ $"{Environment.NewLine}NHellFire - Feature Contributor", "About", MessageBoxButtons.Ok);
}
/// <summary>
/// Handler for AppExitMenuItem Click event
/// </summary>
private void AppExitMenuItemClick(object sender, RoutedEventArgs e)
{
logWindow?.Close();
Close();
}
/// <summary>
/// Handler for CheckForUpdatesMenuItem Click event
/// </summary>
private void CheckForUpdatesMenuItemClick(object sender, RoutedEventArgs e)
{
(bool different, string message, string url) = Tools.CheckForNewVersion();
// If we have a new version, put it in the clipboard
if (different)
Application.Current.Clipboard.SetTextAsync(url);
MessageBox.Show(this, message, "Version Update Check", MessageBoxButtons.Ok);
}
/// <summary>
/// Handler for CopyProtectScanButton Click event
/// </summary>
private void CopyProtectScanButtonClick(object sender, RoutedEventArgs e)
{
ScanAndShowProtection();
}
/// <summary>
/// Handler for DriveLetterComboBox SelectionChanged event
/// </summary>
private void DriveLetterComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
CacheCurrentDiscType();
SetCurrentDiscType();
GetOutputNames(true);
SetSupportedDriveSpeed();
}
/// <summary>
/// Handler for DriveSpeedComboBox SelectionChanged event
/// </summary>
private void DriveSpeedComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
EnsureDiscInformation();
}
/// <summary>
/// Handler for EnableParametersCheckBox Click event
/// </summary>
private void EnableParametersCheckBoxClick(object sender, RoutedEventArgs e)
{
if (this.Find<CheckBox>("EnableParametersCheckBox").IsChecked == true)
this.Find<TextBox>("ParametersTextBox").IsEnabled = true;
else
{
this.Find<TextBox>("ParametersTextBox").IsEnabled = false;
ProcessCustomParameters();
}
}
/// <summary>
/// Handler for MediaTypeComboBox SelectionChanged event
/// </summary>
private void MediaTypeComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Only change the media type if the selection and not the list has changed
if (e.RemovedItems.Count == 1 && e.AddedItems.Count == 1)
{
CurrentMediaType = this.Find<ComboBox>("MediaTypeComboBox").SelectedItem as MediaType?;
SetSupportedDriveSpeed();
}
GetOutputNames(false);
EnsureDiscInformation();
}
/// <summary>
/// Handler for MediaScanButton Click event
/// </summary>
private void MediaScanButtonClick(object sender, RoutedEventArgs e)
{
PopulateDrives();
}
/// <summary>
/// Handler for MainWindow Activated event
/// </summary>
private void MainWindowActivated(object sender, EventArgs e)
{
if (logWindow.IsVisible && !this.Topmost)
{
logWindow.Topmost = true;
logWindow.Topmost = false;
}
}
/// <summary>
/// Handler for MainWindow Closing event
/// </summary>
private void MainWindowClosing(object sender, CancelEventArgs e)
{
if (logWindow.IsVisible)
logWindow?.Close();
}
/// <summary>
/// Handler for MainWindow PositionChanged event
/// </summary>
private void MainWindowLocationChanged(object sender, PixelPointEventArgs e)
{
if (logWindow.IsVisible)
logWindow.AdjustPositionToMainWindow();
}
/// <summary>
/// Handler for OptionsMenuItem Click event
/// </summary>
private async void OptionsMenuItemClick(object sender, RoutedEventArgs e)
{
// Show the window and wait for the response
var optionsWindow = new OptionsWindow();
optionsWindow.UIOptions = UIOptions;
optionsWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen;
await optionsWindow.ShowDialog(this);
// Set any new options
PopulateDrives();
GetOutputNames(false);
SetSupportedDriveSpeed();
EnsureDiscInformation();
}
/// <summary>
/// Handler for OutputDirectoryBrowseButton Click event
/// </summary>
private void OutputDirectoryBrowseButtonClick(object sender, RoutedEventArgs e)
{
BrowseFolder();
EnsureDiscInformation();
}
/// <summary>
/// Handler for OutputFilenameTextBox TextInput event
/// </summary>
// TODO: Not triggered properly
private void OutputDirectoryTextBoxTextChanged(object sender, TextInputEventArgs e)
{
EnsureDiscInformation();
}
/// <summary>
/// Handler for OutputFilenameTextBox TextInput event
/// </summary>
// TODO: Not triggered properly
private void OutputFilenameTextBoxTextChanged(object sender, TextInputEventArgs e)
{
EnsureDiscInformation();
}
/// <summary>
/// Handler for Result ProgressChanged event
/// </summary>
private void ProgressUpdated(object sender, Result value)
{
this.Find<TextBlock>("StatusLabel").Text = value.Message;
ViewModels.LoggerViewModel.VerboseLogLn(value.Message);
}
/// <summary>
/// Handler for FileProtection ProgressChanged event
/// </summary>
private void ProgressUpdated(object sender, FileProtection value)
{
string message = $"{value.Percentage * 100:N2}%: {value.Filename} - {value.Protection}";
this.Find<TextBlock>("StatusLabel").Text = message;
ViewModels.LoggerViewModel.VerboseLogLn(message);
}
/// <summary>
/// Handler for StartStopButton Click event
/// </summary>
private void StartStopButtonClick(object sender, RoutedEventArgs e)
{
// Dump or stop the dump
if ((string)this.Find<Button>("StartStopButton").Content == Constants.StartDumping)
{
StartDumping();
}
else if ((string)this.Find<Button>("StartStopButton").Content == Constants.StopDumping)
{
ViewModels.LoggerViewModel.VerboseLogLn("Canceling dumping process...");
Env.CancelDumping();
this.Find<Button>("CopyProtectScanButton").IsEnabled = true;
if (this.Find<CheckBox>("EjectWhenDoneCheckBox").IsChecked == true)
{
ViewModels.LoggerViewModel.VerboseLogLn($"Ejecting disc in drive {Env.Drive.Letter}");
Env.EjectDisc();
}
if (UIOptions.ResetDriveAfterDump)
{
ViewModels.LoggerViewModel.VerboseLogLn($"Resetting drive {Env.Drive.Letter}");
Env.ResetDrive();
}
}
}
/// <summary>
/// Handler for SystemTypeComboBox SelectionChanged event
/// </summary>
private void SystemTypeComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
// If we're on a separator, go to the next item and return
if ((this.Find<ComboBox>("SystemTypeComboBox").SelectedItem as KnownSystemComboBoxItem).IsHeader())
{
this.Find<ComboBox>("SystemTypeComboBox").SelectedIndex++;
return;
}
ViewModels.LoggerViewModel.VerboseLogLn("Changed system to: {0}", (this.Find<ComboBox>("SystemTypeComboBox").SelectedItem as KnownSystemComboBoxItem).Name);
PopulateMediaType();
GetOutputNames(false);
EnsureDiscInformation();
}
#endregion
}
}

View File

@@ -1,17 +0,0 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" Icon="Icon.ico"
x:Class="DICUI.Avalonia.MessageBox" SizeToContent="WidthAndHeight" CanResize="False">
<StackPanel HorizontalAlignment="Center">
<TextBlock HorizontalAlignment="Center" Name="Text"/>
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Name="Buttons">
<StackPanel.Styles>
<Style Selector="Button">
<Setter Property="Margin" Value="5"/>
</Style>
</StackPanel.Styles>
</StackPanel>
</StackPanel>
</Window>

View File

@@ -1,83 +0,0 @@
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
// https://stackoverflow.com/questions/55706291/how-to-show-a-message-box-in-avaloniaui-beta
namespace DICUI.Avalonia
{
public enum MessageBoxButtons
{
Ok,
OkCancel,
YesNo,
YesNoCancel
}
public enum MessageBoxResult
{
Ok,
Cancel,
Yes,
No
}
public class MessageBox : Window
{
public MessageBox()
{
this.InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
}
public static Task<MessageBoxResult> Show(Window parent, string text, string title, MessageBoxButtons buttons)
{
var msgbox = new MessageBox()
{
Title = title
};
msgbox.FindControl<TextBlock>("Text").Text = text;
var buttonPanel = msgbox.FindControl<StackPanel>("Buttons");
var res = MessageBoxResult.Ok;
void AddButton(string caption, MessageBoxResult r, bool def = false)
{
var btn = new Button { Content = caption };
btn.Click += (_, __) => {
res = r;
msgbox.Close();
};
buttonPanel.Children.Add(btn);
if (def)
res = r;
}
if (buttons == MessageBoxButtons.Ok || buttons == MessageBoxButtons.OkCancel)
AddButton("Ok", MessageBoxResult.Ok, true);
if (buttons == MessageBoxButtons.YesNo || buttons == MessageBoxButtons.YesNoCancel)
{
AddButton("Yes", MessageBoxResult.Yes);
AddButton("No", MessageBoxResult.No, true);
}
if (buttons == MessageBoxButtons.OkCancel || buttons == MessageBoxButtons.YesNoCancel)
AddButton("Cancel", MessageBoxResult.Cancel, true);
var tcs = new TaskCompletionSource<MessageBoxResult>();
msgbox.Closed += delegate { tcs.TrySetResult(res); };
if (parent != null)
msgbox.ShowDialog(parent);
else msgbox.Show();
return tcs.Task;
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

View File

@@ -1,162 +0,0 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DICUI.Avalonia"
mc:Ignorable="d" d:DesignWidth="515.132" d:DesignHeight="600" Width="515.132" Height="600"
x:Class="DICUI.Avalonia.OptionsWindow" Icon="Icon.ico" CanResize="False"
Title="Options">
<Grid RowDefinitions="150,150,150,80,40">
<!-- Paths -->
<Border Grid.Row="0" Grid.ColumnSpan="2" Margin="5" BorderThickness="1" BorderBrush="Gray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock Text="Paths" Margin="2" HorizontalAlignment="Left" VerticalAlignment="Top" FontWeight="Bold" FontSize="14" Foreground="Gray" />
</Border>
<Grid Grid.Row="0" Grid.ColumnSpan="2" Margin="10,15,10,10" ColumnDefinitions="1*,2*,0.2*" RowDefinitions="Auto,Auto,Auto,Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Aaru Path" />
<TextBox Name="AaruPathTextBox" Grid.Row="0" Grid.Column="1" Height="25" HorizontalAlignment="Stretch"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=AaruPath}" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<Button Name="AaruPathButton" Grid.Row="0" Grid.Column="2" Height="25" Width="25" Content="..." Click="BrowseForPathClick" />
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="DiscImageCreator Path" />
<TextBox Name="CreatorPathTextBox" Grid.Row="1" Grid.Column="1" Height="25" HorizontalAlignment="Stretch"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=CreatorPath}" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<Button Name="CreatorPathButton" Grid.Row="1" Grid.Column="2" Height="25" Width="25" Content="..." Click="BrowseForPathClick" />
<!--
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="dd Path" />
<TextBox Name="DDPathTextBox" Grid.Row="0" Grid.Column="1" Height="25" HorizontalAlignment="Stretch"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=DDPath}" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<Button Name="DDPathButton" Grid.Row="0" Grid.Column="2" Height="25" Width="25" Content="..." Click="BrowseForPathClick" />
-->
<TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Subdump Path" />
<TextBox Name="SubDumpPathTextBox" Grid.Row="2" Grid.Column="1" Height="25" HorizontalAlignment="Stretch"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=SubDumpPath}" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<Button Name="SubDumpPathButton" Grid.Row="2" Grid.Column="2" Height="25" Width="25" Content="..." Click="BrowseForPathClick" />
<TextBlock Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Default Output Path" />
<TextBox Name="DefaultOutputPathTextBox" Grid.Row="3" Grid.Column="1" Height="25" HorizontalAlignment="Stretch"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=DefaultOutputPath}" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<Button Name="DefaultOutputPathButton" Grid.Row="3" Grid.Column="2" Height="25" Width="25" Content="..." Click="BrowseForPathClick" />
</Grid>
<!-- Dumping Speeds -->
<Border Grid.Row="1" Grid.ColumnSpan="2" Margin="5" BorderThickness="1" BorderBrush="Gray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock Text="Preferred Dump Speed" Margin="2" HorizontalAlignment="Left" VerticalAlignment="Top" FontWeight="Bold" FontSize="14" Foreground="Gray" />
</Border>
<Grid Grid.Row="1" Grid.ColumnSpan="2" Margin="10,15,10,10" ColumnDefinitions="80,2*,40" RowDefinitions="1*,Auto,Auto,Auto">
<TextBlock Grid.Row="1" Grid.Column="0" Text="CD-ROM" Margin="5" />
<Slider Name="DumpSpeedCDSlider" Grid.Row="1" Grid.Column="1" Minimum="0" Maximum="72" Margin="5"
IsSnapToTickEnabled="True" TickFrequency="4"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Value="{Binding Path=PreferredDumpSpeedCD}" />
<!-- Ticks="{Binding Source={x:Static local:Constants.SpeedsForCDAsCollection}}" -->
<TextBox Name="DumpSpeedCDTextBox" Grid.Row="1" Grid.Column="2" Width="25" Height="25" TextAlignment="Center" VerticalAlignment="Center"
IsReadOnly="True" Text="{Binding ElementName=DumpSpeedCDSlider, Path=Value}"
Background="LightGray" Foreground="Gray" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="DVD-ROM" Margin="5" />
<Slider Name="DumpSpeedDVDSlider" Grid.Row="2" Grid.Column="1" Minimum="0" Maximum="24" Margin="5"
IsSnapToTickEnabled="True" TickFrequency="2"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Value="{Binding Path=PreferredDumpSpeedDVD}" />
<!-- Ticks="{Binding Source={x:Static local:Constants.SpeedsForDVDAsCollection}}" -->
<TextBox Name="DumpSpeedDVDTextBox" Grid.Row="2" Grid.Column="2" Width="25" Height="25" TextAlignment="Center" VerticalAlignment="Center"
IsReadOnly="True" Text="{Binding ElementName=DumpSpeedDVDSlider, Path=Value}"
Background="LightGray" Foreground="Gray" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<TextBlock Grid.Row="3" Grid.Column="0" Text="BD-ROM" Margin="5" />
<Slider Name="DumpSpeedBDSlider" Grid.Row="3" Grid.Column="1" Minimum="0" Maximum="16" Margin="5"
IsSnapToTickEnabled="True" TickFrequency="2"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Value="{Binding Path=PreferredDumpSpeedBD}" />
<!-- Ticks="{Binding Source={x:Static local:Constants.SpeedsForBDAsCollection}}" -->
<TextBox Name="DumpSpeedBDTextBox" Grid.Row="3" Grid.Column="2" Width="25" Height="25" TextAlignment="Center" VerticalAlignment="Center"
IsReadOnly="True" Text="{Binding ElementName=DumpSpeedBDSlider, Path=Value}"
Background="LightGray" Foreground="Gray" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
</Grid>
<!-- Misc. Options -->
<Border Grid.Row="2" Grid.ColumnSpan="2" Margin="5" BorderThickness="1" BorderBrush="Gray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock Text="Options" Margin="2" HorizontalAlignment="Left" VerticalAlignment="Top" FontWeight="Bold" FontSize="14" Foreground="Gray" />
</Border>
<Grid Grid.Row="2" Grid.ColumnSpan="2" Margin="10,15,10,10" ColumnDefinitions="1*,1*,1*,1*" RowDefinitions="1*,Auto,Auto,Auto">
<CheckBox Grid.Row="1" Grid.Column="0" Margin="0,4" VerticalAlignment="Center" Content="Quiet Mode"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=QuietMode}"
ToolTip.Tip="Disable DiscImageCreator sounds" />
<CheckBox Grid.Row="1" Grid.Column="1" Margin="0,4" VerticalAlignment="Center" Content="Paranoid Mode"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=ParanoidMode}"
ToolTip.Tip="Enable pedantic and super-safe flags" />
<TextBlock Grid.Row="1" Grid.Column="2" Margin="5" Text="Reread Tries:" VerticalAlignment="Center" HorizontalAlignment="Right"/>
<TextBox Grid.Row="1" Grid.Column="3" Margin="0,4" VerticalAlignment="Center"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=RereadAmountForC2}"
ToolTip.Tip="Specifies how many rereads are attempted on C2 error" />
<CheckBox Grid.Row="2" Grid.Column="0" Margin="0,4" VerticalAlignment="Center" Content="Protection Scan"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=ScanForProtection}"
ToolTip.Tip="Enable automatic checking for copy protection on dumped media" />
<CheckBox Grid.Row="2" Grid.Column="1" Margin="0,4" VerticalAlignment="Center" Content="Skip Type Detect"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=SkipMediaTypeDetection}"
ToolTip.Tip="Disable trying to guess media type inserted (may improve performance at startup)" />
<CheckBox Grid.Row="2" Grid.Column="2" Margin="0,4" VerticalAlignment="Center" Content="Add Placeholders"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=AddPlaceholders}"
ToolTip.Tip="Enable adding placeholder text in the submissioninfo output for required and optional fields" />
<CheckBox Grid.Row="3" Grid.Column="0" Margin="0,4" VerticalAlignment="Center" Content="Show Disc Info"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=PromptForDiscInformation}"
ToolTip.Tip="Enable showing the disc information output after dumping" />
<CheckBox Grid.Row="3" Grid.Column="1" Margin="0,4" VerticalAlignment="Center" Content="No Fixed Drives"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=IgnoreFixedDrives}"
ToolTip.Tip="Ignore hard drives and other fixed drives" />
<CheckBox Grid.Row="3" Grid.Column="2" Margin="0,4" VerticalAlignment="Center" Content="Reset After Dump"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=ResetDriveAfterDump}"
ToolTip.Tip="Reset disc drives after dumping; useful for some older machines" />
</Grid>
<!-- Redump -->
<Border Grid.Row="3" Grid.ColumnSpan="2" Margin="5" BorderThickness="1" BorderBrush="Gray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock Text="Redump Login" Margin="2" HorizontalAlignment="Left" VerticalAlignment="Top" FontWeight="Bold" FontSize="14" Foreground="Gray" />
</Border>
<Grid Grid.Row="3" Grid.ColumnSpan="2" Margin="10,15,10,10" ColumnDefinitions="1*,1*,1*,1*,1.2*" RowDefinitions="1*,Auto">
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Username" />
<TextBox Name="RedumpUsernameTextBox" Grid.Row="1" Grid.Column="1" Height="25" HorizontalAlignment="Stretch"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=Username}" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<TextBlock Grid.Row="1" Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Username" />
<TextBox Name="RedumpPasswordTextBox" Grid.Row="1" Grid.Column="3" Height="25" HorizontalAlignment="Stretch" PasswordChar="*"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=Password}" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<Button Name="RedumpLoginTestButton" Grid.Row="1" Grid.Column="5" Height="25" Width="80" Content="Test Login" Click="OnRedumpTestClick" />
</Grid>
<!-- Accept / Cancel -->
<Grid Height="25" Grid.Row="4" Grid.Column="0" ColumnDefinitions="2*,1*,1*">
<Button Name="AcceptButton" Grid.Row="0" Grid.Column="1" Height="25" Width="80" Content="Accept" Click="OnAcceptClick" />
<Button Name="CancelButton" Grid.Row="0" Grid.Column="2" Height="25" Width="80" Content="Cancel" Click="OnCancelClick" />
</Grid>
</Grid>
</Window>

View File

@@ -1,142 +0,0 @@
using System;
using System.IO;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using DICUI.Web;
namespace DICUI.Avalonia
{
public class OptionsWindow : Window
{
#region Fields
/// <summary>
/// Current UI options
/// </summary>
public UIOptions UIOptions { get; set; }
#endregion
public OptionsWindow()
{
this.InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
#region Helpers
/// <summary>
/// Find a TextBox by setting name
/// </summary>
/// <param name="name">Setting name to find</param>
/// <returns>TextBox for that setting</returns>
private TextBox TextBoxForPathSetting(string name)
{
return this.Find<TextBox>(name + "TextBox");
}
#endregion
#region Event Handlers
/// <summary>
/// Handler for generic Click event
/// </summary>
private async void BrowseForPathClick(object sender, RoutedEventArgs e)
{
Button button = sender as Button;
// strips button prefix to obtain the setting name
string pathSettingName = button.Name.Substring(0, button.Name.IndexOf("Button"));
// TODO: hack for now, then we'll see
bool shouldBrowseForPath = pathSettingName == "DefaultOutputPath";
// Directory
if (shouldBrowseForPath)
{
OpenFolderDialog dialog = new OpenFolderDialog();
string result = await dialog.ShowAsync(this);
if (!string.IsNullOrWhiteSpace(result))
{
if (Directory.Exists(result))
TextBoxForPathSetting(pathSettingName).Text = result;
else
Console.WriteLine($"Path '{result}' cannot be found!");
}
}
// File
else
{
OpenFileDialog dialog = new OpenFileDialog();
string[] result = await dialog.ShowAsync(this);
if (result != null && result.Length > 0 && !string.IsNullOrWhiteSpace(result[0]))
{
if (File.Exists(result[0]))
TextBoxForPathSetting(pathSettingName).Text = result[0];
else
Console.WriteLine($"Path '{result[0]}' cannot be found!");
}
}
}
/// <summary>
/// Handler for AcceptButton Click event
/// </summary>
private void OnAcceptClick(object sender, RoutedEventArgs e)
{
UIOptions.Save();
Hide();
}
/// <summary>
/// Handler for CancelButton Click event
/// </summary>
private void OnCancelClick(object sender, RoutedEventArgs e)
{
Hide();
}
/// <summary>
/// Handler for RedumpLoginTestButton Click event
/// </summary>
private void OnRedumpTestClick(object sender, RoutedEventArgs e)
{
using (RedumpWebClient wc = new RedumpWebClient())
{
if (wc.Login(this.Find<TextBox>("RedumpUsernameTextBox").Text, this.Find<TextBox>("RedumpPasswordTextBox").Text))
{
new Window()
{
Title = "Success",
Content = "Redump login credentials accepted!",
SizeToContent = SizeToContent.WidthAndHeight,
WindowStartupLocation = WindowStartupLocation.CenterScreen,
}.ShowDialog(this);
}
else
{
new Window()
{
Title = "Failure",
Content = "Redump login credentials denied!",
SizeToContent = SizeToContent.WidthAndHeight,
WindowStartupLocation = WindowStartupLocation.CenterScreen,
}.ShowDialog(this);
}
}
}
#endregion
}
}

View File

@@ -1,22 +0,0 @@
using System;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Logging.Serilog;
namespace DICUI.Avalonia
{
class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.LogToDebug();
}
}

View File

@@ -1,122 +0,0 @@
using System.Collections.Generic;
using System.Configuration;
using DICUI.Data;
namespace DICUI.Avalonia
{
public class UIOptions
{
// TODO: Is there any way that this can be made private?
public Options Options { get; set; }
#region Passthrough readonly values
// TODO: Can any of these be removed?
public string DefaultOutputPath { get { return Options.DefaultOutputPath; } }
public bool IgnoreFixedDrives { get { return Options.IgnoreFixedDrives; } }
public bool ResetDriveAfterDump { get { return Options.ResetDriveAfterDump; } }
public bool SkipMediaTypeDetection { get { return Options.SkipMediaTypeDetection; } }
public bool SkipSystemDetection { get { return Options.SkipSystemDetection; } }
public bool OpenLogWindowAtStartup { get { return Options.OpenLogWindowAtStartup; } }
#endregion
/// <summary>
/// Default constructor
/// </summary>
public UIOptions()
{
Load();
}
/// <summary>
/// Save a configuration from internal Options
/// </summary>
public void Save()
{
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
// Loop through all settings in Options and save them, overwriting existing settings
foreach (var kvp in Options)
{
configFile.AppSettings.Settings.Remove(kvp.Key);
configFile.AppSettings.Settings.Add(kvp.Key, kvp.Value);
}
configFile.Save(ConfigurationSaveMode.Modified);
}
/// <summary>
/// Load a configuration into internal Options
/// </summary>
private void Load()
{
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var settings = ConvertToDictionary(configFile);
Options = new Options(settings);
}
/// <summary>
/// Get a setting value from the base Options
/// </summary>
/// <param name="key">Key to retrieve the value for</param>
/// <returns>String value if possible, null otherwise</returns>
public string Get(string key)
{
return Options[key];
}
/// <summary>
/// Set a setting value in the base Options
/// </summary>
/// <param name="key">Key to set the value for</param>
/// <param name="value">Value to set</param>
public void Set(string key, string value)
{
Options[key] = value;
}
/// <summary>
/// Get the preferred dumping speed given a media type
/// </summary>
/// <param name="type">MediaType representing the current selection</param>
/// <returns>Int value representing the dump speed</returns>
public int GetPreferredDumpSpeedForMediaType(MediaType? type)
{
switch (type)
{
case MediaType.CDROM:
case MediaType.GDROM:
return this.Options.PreferredDumpSpeedCD;
case MediaType.DVD:
case MediaType.HDDVD:
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
return this.Options.PreferredDumpSpeedDVD;
case MediaType.BluRay:
return this.Options.PreferredDumpSpeedBD;
default:
return this.Options.PreferredDumpSpeedCD;
}
}
/// <summary>
/// Convert the configuration app settings to a dictionary
/// </summary>
/// <param name="configFile">Configuration to load from</param>
/// <returns>Dictionary with all values from app settings</returns>
private Dictionary<string, string> ConvertToDictionary(Configuration configFile)
{
var settings = configFile.AppSettings.Settings;
var dict = new Dictionary<string, string>();
foreach (string key in settings.AllKeys)
{
dict[key] = settings[key]?.Value ?? string.Empty;
}
return dict;
}
}
}

View File

@@ -1,233 +0,0 @@
using System;
using Avalonia.Media;
namespace DICUI.Avalonia
{
public class OptionsViewModel
{
private UIOptions _uiOptions;
#region Internal Program
public string AaruPath
{
get { return _uiOptions.Options.AaruPath; }
set { _uiOptions.Options.AaruPath = value; }
}
public string CreatorPath
{
get { return _uiOptions.Options.CreatorPath; }
set { _uiOptions.Options.CreatorPath = value; }
}
public string DDPath
{
get { return _uiOptions.Options.DDPath; }
set { _uiOptions.Options.DDPath = value; }
}
public string InternalProgram
{
get { return _uiOptions.Options.InternalProgram; }
set { _uiOptions.Options.InternalProgram = value; }
}
#endregion
#region Extra Paths
public string DefaultOutputPath
{
get { return _uiOptions.Options.DefaultOutputPath; }
set { _uiOptions.Options.DefaultOutputPath = value; }
}
public string SubDumpPath
{
get { return _uiOptions.Options.SubDumpPath; }
set { _uiOptions.Options.SubDumpPath = value; }
}
#endregion
#region Dumping Speeds
public int PreferredDumpSpeedCD
{
get { return _uiOptions.Options.PreferredDumpSpeedCD; }
set { _uiOptions.Options.PreferredDumpSpeedCD = value; }
}
public int PreferredDumpSpeedDVD
{
get { return _uiOptions.Options.PreferredDumpSpeedDVD; }
set { _uiOptions.Options.PreferredDumpSpeedDVD = value; }
}
public int PreferredDumpSpeedBD
{
get { return _uiOptions.Options.PreferredDumpSpeedBD; }
set { _uiOptions.Options.PreferredDumpSpeedBD = value; }
}
#endregion
#region Extra Dumping Options
public bool QuietMode
{
get { return _uiOptions.Options.QuietMode; }
set { _uiOptions.Options.QuietMode = value; }
}
public bool ParanoidMode
{
get { return _uiOptions.Options.ParanoidMode; }
set { _uiOptions.Options.ParanoidMode = value; }
}
public bool ScanForProtection
{
get { return _uiOptions.Options.ScanForProtection; }
set { _uiOptions.Options.ScanForProtection = value; }
}
public string RereadAmountForC2
{
get { return Convert.ToString(_uiOptions.Options.RereadAmountForC2); }
set
{
if (Int32.TryParse(value, out int result))
_uiOptions.Options.RereadAmountForC2 = result;
}
}
public bool AddPlaceholders
{
get { return _uiOptions.Options.AddPlaceholders; }
set { _uiOptions.Options.AddPlaceholders = value; }
}
public bool PromptForDiscInformation
{
get { return _uiOptions.Options.PromptForDiscInformation; }
set { _uiOptions.Options.PromptForDiscInformation = value; }
}
public bool IgnoreFixedDrives
{
get { return _uiOptions.Options.IgnoreFixedDrives; }
set { _uiOptions.Options.IgnoreFixedDrives = value; }
}
public bool ResetDriveAfterDump
{
get { return _uiOptions.Options.ResetDriveAfterDump; }
set { _uiOptions.Options.ResetDriveAfterDump = value; }
}
#endregion
#region Skip Options
public bool SkipMediaTypeDetection
{
get { return _uiOptions.Options.SkipMediaTypeDetection; }
set { _uiOptions.Options.SkipMediaTypeDetection = value; }
}
public bool SkipSystemDetection
{
get { return _uiOptions.Options.SkipSystemDetection; }
set { _uiOptions.Options.SkipSystemDetection = value; }
}
#endregion
#region Logging Options
public bool VerboseLogging
{
get { return _uiOptions.Options.VerboseLogging; }
set
{
_uiOptions.Options.VerboseLogging = value;
_uiOptions.Save(); // TODO: Why does this save here?
}
}
public bool OpenLogWindowAtStartup
{
get { return _uiOptions.Options.OpenLogWindowAtStartup; }
set
{
_uiOptions.Options.OpenLogWindowAtStartup = value;
_uiOptions.Save(); // TODO: Why does this save here?
}
}
#endregion
#region Redump Login Information
public string Username
{
get { return _uiOptions.Options.Username; }
set { _uiOptions.Options.Username = value; }
}
public string Password
{
get { return _uiOptions.Options.Password; }
set { _uiOptions.Options.Password = value; }
}
#endregion
public OptionsViewModel(UIOptions uiOptions)
{
this._uiOptions = uiOptions;
}
}
public class LoggerViewModel
{
private LogWindow _logWindow;
public void SetWindow(LogWindow logWindow) => _logWindow = logWindow;
public bool WindowVisible
{
get => _logWindow != null ? _logWindow.IsVisible : false;
set
{
if (_logWindow == null)
_logWindow = new LogWindow();
if (value)
{
_logWindow.AdjustPositionToMainWindow();
_logWindow.Show();
}
else
_logWindow.Hide();
}
}
public void VerboseLog(string text)
{
if (ViewModels.OptionsViewModel.VerboseLogging)
_logWindow.AppendToTextBox(text, Brushes.Yellow);
}
public void VerboseLog(string format, params object[] args) => VerboseLog(string.Format(format, args));
public void VerboseLogLn(string format, params object[] args) => VerboseLog(string.Format(format, args) + "\n");
}
public static class ViewModels
{
public static OptionsViewModel OptionsViewModel { get; set; }
public static LoggerViewModel LoggerViewModel { get; set; } = new LoggerViewModel();
}
}

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
To use the Avalonia CI feed to get unstable packages, move this file to the root of your solution.
-->
<configuration>
<packageSources>
<add key="AvaloniaCI" value="https://www.myget.org/F/avalonia-ci/api/v2" />
</packageSources>
</configuration>

View File

@@ -1,35 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472;net48;netcoreapp3.1</TargetFrameworks>
<OutputType>Exe</OutputType>
<Prefer32Bit>true</Prefer32Bit>
<Title>DICUI Check</Title>
<AssemblyName>DICUI.Check</AssemblyName>
<Description>Validator for various dumping programs</Description>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2020</Copyright>
<RepositoryUrl>https://github.com/SabreTools/DICUI</RepositoryUrl>
<Version>1.17.0</Version>
<AssemblyVersion>1.17.0</AssemblyVersion>
<FileVersion>1.17.0</FileVersion>
<IncludeSource>true</IncludeSource>
<IncludeSymbols>true</IncludeSymbols>
</PropertyGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BurnOutSharp" Version="1.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DICUI.Library\DICUI.Library.csproj">
<Project>{51ab0928-13f9-44bf-a407-b6957a43a056}</Project>
<Name>DICUI.Library</Name>
</ProjectReference>
</ItemGroup>
</Project>

View File

@@ -1,424 +0,0 @@
using DICUI.Data;
namespace DICUI.Aaru
{
public static class Converters
{
#region Cross-enumeration conversions
/// <summary>
/// Get the default extension for a given disc type
/// </summary>
/// <param name="type">MediaType value to check</param>
/// <returns>Valid extension (with leading '.'), null on error</returns>
public static string Extension(MediaType? type)
{
// Aaru has a single, unified output format by default
return ".aif";
}
#endregion
#region Convert to Long Name
/// <summary>
/// Get the string representation of the Command enum values
/// </summary>
/// <param name="command">Command value to convert</param>
/// <returns>String representing the value, if possible</returns>
public static string LongName(Command command)
{
switch (command)
{
// Database Family
case Command.DatabaseStats:
return $"{CommandStrings.DatabasePrefixLong} {CommandStrings.DatabaseStats}";
case Command.DatabaseUpdate:
return $"{CommandStrings.DatabasePrefixLong} {CommandStrings.DatabaseUpdate}";
// Device Family
case Command.DeviceInfo:
return $"{CommandStrings.DevicePrefixLong} {CommandStrings.DeviceInfo}";
case Command.DeviceList:
return $"{CommandStrings.DevicePrefixLong} {CommandStrings.DeviceList}";
case Command.DeviceReport:
return $"{CommandStrings.DevicePrefixLong} {CommandStrings.DeviceReport}";
// Filesystem Family
case Command.FilesystemExtract:
return $"{CommandStrings.FilesystemPrefixLong} {CommandStrings.FilesystemExtract}";
case Command.FilesystemList:
return $"{CommandStrings.FilesystemPrefixLong} {CommandStrings.FilesystemListLong}";
case Command.FilesystemOptions:
return $"{CommandStrings.FilesystemPrefixLong} {CommandStrings.FilesystemOptions}";
// Image Family
case Command.ImageAnalyze:
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageAnalyze}";
case Command.ImageChecksum:
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageChecksumLong}";
case Command.ImageCompare:
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageCompareLong}";
case Command.ImageConvert:
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageConvert}";
case Command.ImageCreateSidecar:
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageCreateSidecar}";
case Command.ImageDecode:
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageDecode}";
case Command.ImageEntropy:
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageEntropy}";
case Command.ImageInfo:
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageInfo}";
case Command.ImageOptions:
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageOptions}";
case Command.ImagePrint:
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImagePrint}";
case Command.ImageVerify:
return $"{CommandStrings.ImagePrefixLong} {CommandStrings.ImageVerify}";
// Media Family
case Command.MediaDump:
return $"{CommandStrings.MediaPrefixLong} {CommandStrings.MediaDump}";
case Command.MediaInfo:
return $"{CommandStrings.MediaPrefixLong} {CommandStrings.MediaInfo}";
case Command.MediaScan:
return $"{CommandStrings.MediaPrefixLong} {CommandStrings.MediaScan}";
// Standalone Commands
case Command.Configure:
return CommandStrings.Configure;
case Command.Formats:
return CommandStrings.Formats;
case Command.ListEncodings:
return CommandStrings.ListEncodings;
case Command.ListNamespaces:
return CommandStrings.ListNamespaces;
case Command.Remote:
return CommandStrings.Remote;
case Command.NONE:
default:
return "";
}
}
/// <summary>
/// Get the string representation of the Flag enum values
/// </summary>
/// <param name="command">Flag value to convert</param>
/// <returns>String representing the value, if possible</returns>
public static string LongName(Flag flag)
{
switch (flag)
{
// Boolean flags
case Flag.Adler32:
return FlagStrings.Adler32Long;
case Flag.Clear:
return FlagStrings.ClearLong;
case Flag.ClearAll:
return FlagStrings.ClearAllLong;
case Flag.CRC16:
return FlagStrings.CRC16Long;
case Flag.CRC32:
return FlagStrings.CRC32Long;
case Flag.CRC64:
return FlagStrings.CRC64Long;
case Flag.Debug:
return FlagStrings.DebugLong;
case Flag.DiskTags:
return FlagStrings.DiskTagsLong;
case Flag.DuplicatedSectors:
return FlagStrings.DuplicatedSectorsLong;
case Flag.Eject:
return FlagStrings.EjectLong;
case Flag.ExtendedAttributes:
return FlagStrings.ExtendedAttributesLong;
case Flag.Filesystems:
return FlagStrings.FilesystemsLong;
case Flag.FirstPregap:
return FlagStrings.FirstPregapLong;
case Flag.FixOffset:
return FlagStrings.FixOffsetLong;
case Flag.FixSubchannel:
return FlagStrings.FixSubchannelLong;
case Flag.FixSubchannelCrc:
return FlagStrings.FixSubchannelCrcLong;
case Flag.FixSubchannelPosition:
return FlagStrings.FixSubchannelPositionLong;
case Flag.Fletcher16:
return FlagStrings.Fletcher16Long;
case Flag.Fletcher32:
return FlagStrings.Fletcher32Long;
case Flag.Force:
return FlagStrings.ForceLong;
case Flag.GenerateSubchannels:
return FlagStrings.GenerateSubchannelsLong;
case Flag.Help:
return FlagStrings.HelpLong;
case Flag.LongFormat:
return FlagStrings.LongFormatLong;
case Flag.LongSectors:
return FlagStrings.LongSectorsLong;
case Flag.MD5:
return FlagStrings.MD5Long;
case Flag.Metadata:
return FlagStrings.MetadataLong;
case Flag.Partitions:
return FlagStrings.PartitionsLong;
case Flag.Persistent:
return FlagStrings.PersistentLong;
case Flag.Private:
return FlagStrings.PrivateLong;
case Flag.Resume:
return FlagStrings.ResumeLong;
case Flag.RetrySubchannel:
return FlagStrings.RetrySubchannelLong;
case Flag.SectorTags:
return FlagStrings.SectorTagsLong;
case Flag.SeparatedTracks:
return FlagStrings.SeparatedTracksLong;
case Flag.SHA1:
return FlagStrings.SHA1Long;
case Flag.SHA256:
return FlagStrings.SHA256Long;
case Flag.SHA384:
return FlagStrings.SHA384Long;
case Flag.SHA512:
return FlagStrings.SHA512Long;
case Flag.SkipCdiReadyHole:
return FlagStrings.SkipCdiReadyHoleLong;
case Flag.SpamSum:
return FlagStrings.SpamSumLong;
case Flag.StopOnError:
return FlagStrings.StopOnErrorLong;
case Flag.Tape:
return FlagStrings.TapeLong;
case Flag.Trim:
return FlagStrings.TrimLong;
case Flag.Verbose:
return FlagStrings.VerboseLong;
case Flag.VerifyDisc:
return FlagStrings.VerifyDiscLong;
case Flag.VerifySectors:
return FlagStrings.VerifySectorsLong;
case Flag.Version:
return FlagStrings.VersionLong;
case Flag.WholeDisc:
return FlagStrings.WholeDiscLong;
// Int8 flags
case Flag.Speed:
return FlagStrings.SpeedLong;
// Int16 flags
case Flag.RetryPasses:
return FlagStrings.RetryPassesLong;
case Flag.Width:
return FlagStrings.WidthLong;
// Int32 flags
case Flag.BlockSize:
return FlagStrings.BlockSizeLong;
case Flag.Count:
return FlagStrings.CountLong;
case Flag.MediaLastSequence:
return FlagStrings.MediaLastSequenceLong;
case Flag.MediaSequence:
return FlagStrings.MediaSequenceLong;
case Flag.Skip:
return FlagStrings.SkipLong;
// Int64 flags
case Flag.Length:
return FlagStrings.LengthLong;
case Flag.Start:
return FlagStrings.StartLong;
// String flags
case Flag.Comments:
return FlagStrings.CommentsLong;
case Flag.Creator:
return FlagStrings.CreatorLong;
case Flag.DriveManufacturer:
return FlagStrings.DriveManufacturerLong;
case Flag.DriveModel:
return FlagStrings.DriveModelLong;
case Flag.DriveRevision:
return FlagStrings.DriveRevisionLong;
case Flag.DriveSerial:
return FlagStrings.DriveSerialLong;
case Flag.Encoding:
return FlagStrings.EncodingLong;
case Flag.FormatConvert:
return FlagStrings.FormatConvertLong;
case Flag.FormatDump:
return FlagStrings.FormatDumpLong;
case Flag.ImgBurnLog:
return FlagStrings.ImgBurnLogLong;
case Flag.MediaBarcode:
return FlagStrings.MediaBarcodeLong;
case Flag.MediaManufacturer:
return FlagStrings.MediaManufacturerLong;
case Flag.MediaModel:
return FlagStrings.MediaModelLong;
case Flag.MediaPartNumber:
return FlagStrings.MediaPartNumberLong;
case Flag.MediaSerial:
return FlagStrings.MediaSerialLong;
case Flag.MediaTitle:
return FlagStrings.MediaTitleLong;
case Flag.MHDDLog:
return FlagStrings.MHDDLogLong;
case Flag.Namespace:
return FlagStrings.NamespaceLong;
case Flag.Options:
return FlagStrings.OptionsLong;
case Flag.OutputPrefix:
return FlagStrings.OutputPrefixLong;
case Flag.ResumeFile:
return FlagStrings.ResumeFileLong;
case Flag.Subchannel:
return FlagStrings.SubchannelLong;
case Flag.XMLSidecar:
return FlagStrings.XMLSidecarLong;
case Flag.NONE:
default:
return "";
}
}
#endregion
#region Convert From String
/// <summary>
/// Get the Command enum value for a given string
/// </summary>
/// <param name="commandOne">First part of String value to convert</param>
/// <param name="commandTwo">Second part of String value to convert</param>
/// <param name="useSecond">Output bool if the second command was used</param>
/// <returns>Command represented by the string(s), if possible</returns>
public static Command StringToCommand(string commandOne, string commandTwo, out bool useSecond)
{
useSecond = false;
switch (commandOne)
{
// Database Family
case CommandStrings.DatabasePrefixShort:
case CommandStrings.DatabasePrefixLong:
useSecond = true;
switch (commandTwo)
{
case CommandStrings.DatabaseStats:
return Command.DatabaseStats;
case CommandStrings.DatabaseUpdate:
return Command.DatabaseUpdate;
}
break;
// Device Family
case CommandStrings.DevicePrefixShort:
case CommandStrings.DevicePrefixLong:
useSecond = true;
switch (commandTwo)
{
case CommandStrings.DeviceInfo:
return Command.DeviceInfo;
case CommandStrings.DeviceList:
return Command.DeviceList;
case CommandStrings.DeviceReport:
return Command.DeviceReport;
}
break;
// Filesystem Family
case CommandStrings.FilesystemPrefixShort:
case CommandStrings.FilesystemPrefixShortAlt:
case CommandStrings.FilesystemPrefixLong:
useSecond = true;
switch (commandTwo)
{
case CommandStrings.FilesystemExtract:
return Command.FilesystemExtract;
case CommandStrings.FilesystemListShort:
case CommandStrings.FilesystemListLong:
return Command.FilesystemList;
case CommandStrings.DatabaseStats:
return Command.FilesystemOptions;
}
break;
// Image Family
case CommandStrings.ImagePrefixShort:
case CommandStrings.ImagePrefixLong:
useSecond = true;
switch (commandTwo)
{
case CommandStrings.ImageAnalyze:
return Command.ImageAnalyze;
case CommandStrings.ImageChecksumShort:
case CommandStrings.ImageChecksumLong:
return Command.ImageChecksum;
case CommandStrings.ImageCompareShort:
case CommandStrings.ImageCompareLong:
return Command.ImageCompare;
case CommandStrings.ImageConvert:
return Command.ImageConvert;
case CommandStrings.ImageCreateSidecar:
return Command.ImageCreateSidecar;
case CommandStrings.ImageDecode:
return Command.ImageDecode;
case CommandStrings.ImageEntropy:
return Command.ImageEntropy;
case CommandStrings.ImageInfo:
return Command.ImageInfo;
case CommandStrings.ImageOptions:
return Command.ImageOptions;
case CommandStrings.ImagePrint:
return Command.ImagePrint;
case CommandStrings.ImageVerify:
return Command.ImageVerify;
}
break;
// Media Family
case CommandStrings.MediaPrefixShort:
case CommandStrings.MediaPrefixLong:
useSecond = true;
switch (commandTwo)
{
case CommandStrings.MediaDump:
return Command.MediaDump;
case CommandStrings.MediaInfo:
return Command.MediaInfo;
case CommandStrings.MediaScan:
return Command.MediaScan;
}
break;
// Standalone Commands
case CommandStrings.Configure:
return Command.Configure;
case CommandStrings.Formats:
return Command.Formats;
case CommandStrings.ListEncodings:
return Command.ListEncodings;
case CommandStrings.ListNamespaces:
return Command.ListNamespaces;
case CommandStrings.Remote:
return Command.Remote;
}
return Command.NONE;
}
#endregion
}
}

View File

@@ -1,149 +0,0 @@
namespace DICUI.Aaru
{
/// <summary>
/// Supported Aaru commands
/// </summary>
public enum Command : int
{
NONE = 0,
// Database Family
DatabaseStats,
DatabaseUpdate,
// Device Family
DeviceInfo,
DeviceList,
DeviceReport,
// Filesystem Family
FilesystemExtract,
FilesystemList,
FilesystemOptions,
// Image Family
ImageAnalyze,
ImageChecksum,
ImageCompare,
ImageConvert,
ImageCreateSidecar,
ImageDecode,
ImageEntropy,
ImageInfo,
ImageOptions,
ImagePrint,
ImageVerify,
// Media Family
MediaDump,
MediaInfo,
MediaScan,
// Standalone Commands
Configure,
Formats,
ListEncodings,
ListNamespaces,
Remote,
}
/// <summary>
/// Supported Aaru flags
/// </summary>
public enum Flag : int
{
NONE = 0,
// Boolean flags
Adler32,
Clear,
ClearAll,
CRC16,
CRC32,
CRC64,
Debug,
DiskTags,
DuplicatedSectors,
Eject,
ExtendedAttributes,
Filesystems,
FirstPregap,
FixOffset,
FixSubchannel,
FixSubchannelCrc,
FixSubchannelPosition,
Fletcher16,
Fletcher32,
Force,
GenerateSubchannels,
Help,
LongFormat,
LongSectors,
MD5,
Metadata,
Partitions,
Persistent,
Private,
Resume,
RetrySubchannel,
SectorTags,
SeparatedTracks,
SHA1,
SHA256,
SHA384,
SHA512,
SkipCdiReadyHole,
SpamSum,
StopOnError,
Tape,
Trim,
Verbose,
VerifyDisc,
VerifySectors,
Version,
WholeDisc,
// Int8 flags
Speed,
// Int16 flags
RetryPasses,
Width,
// Int32 flags
BlockSize,
Count,
MediaLastSequence,
MediaSequence,
Skip,
// Int64 flags
Length,
Start,
// String flags
Comments,
Creator,
DriveManufacturer,
DriveModel,
DriveRevision,
DriveSerial,
Encoding,
FormatConvert,
FormatDump,
ImgBurnLog,
MediaBarcode,
MediaManufacturer,
MediaModel,
MediaPartNumber,
MediaSerial,
MediaTitle,
MHDDLog,
Namespace,
Options,
OutputPrefix,
ResumeFile,
Subchannel,
XMLSidecar,
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,104 +0,0 @@
using DICUI.Data;
namespace DICUI.DD
{
public static class Converters
{
#region Cross-enumeration conversions
/// <summary>
/// Get the default extension for a given disc type
/// </summary>
/// <param name="type">MediaType value to check</param>
/// <returns>Valid extension (with leading '.'), null on error</returns>
public static string Extension(MediaType? type)
{
// DD has a single, unified output format by default
return ".bin";
}
#endregion
#region Convert to Long Name
/// <summary>
/// Get the string representation of the Command enum values
/// </summary>
/// <param name="command">Command value to convert</param>
/// <returns>String representing the value, if possible</returns>
public static string LongName(Command command)
{
switch (command)
{
case Command.List:
return CommandStrings.List;
case Command.NONE:
default:
return "";
}
}
/// <summary>
/// Get the string representation of the Flag enum values
/// </summary>
/// <param name="command">Flag value to convert</param>
/// <returns>String representing the value, if possible</returns>
public static string LongName(Flag flag)
{
switch (flag)
{
// Boolean flags
case Flag.Progress:
return FlagStrings.Progress;
case Flag.Size:
return FlagStrings.Size;
// Int64 flags
case Flag.BlockSize:
return FlagStrings.BlockSize;
case Flag.Count:
return FlagStrings.Count;
case Flag.Seek:
return FlagStrings.Seek;
case Flag.Skip:
return FlagStrings.Skip;
// String flags
case Flag.Filter:
return FlagStrings.Filter;
case Flag.InputFile:
return FlagStrings.InputFile;
case Flag.OutputFile:
return FlagStrings.OutputFile;
case Flag.NONE:
default:
return "";
}
}
#endregion
#region Convert From String
/// <summary>
/// Get the Command enum value for a given string
/// </summary>
/// <param name="command">String value to convert</param>
/// <returns>Command represented by the string(s), if possible</returns>
public static Command StringToCommand(string command)
{
switch (command)
{
case CommandStrings.List:
return Command.List;
default:
return Command.NONE;
}
}
#endregion
}
}

View File

@@ -1,34 +0,0 @@
namespace DICUI.DD
{
/// <summary>
/// Supported DD commands
/// </summary>
public enum Command: int
{
NONE = 0, // For DD, this represents a normal dump
List,
}
/// <summary>
/// Supported DD flags
/// </summary>
public enum Flag : int
{
NONE = 0,
// Boolean flags
Progress,
Size,
// Int64 flags
BlockSize,
Count,
Seek,
Skip,
// String flags
Filter,
InputFile,
OutputFile,
}
}

View File

@@ -1,668 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using DICUI.Data;
using DICUI.Utilities;
using DICUI.Web;
namespace DICUI.DD
{
/// <summary>
/// Represents a generic set of DD parameters
/// </summary>
public class Parameters : BaseParameters
{
/// <summary>
/// Base command to run
/// </summary>
public Command BaseCommand { get; set; }
/// <summary>
/// Set of flags to pass to the executable
/// </summary>
protected Dictionary<Flag, bool?> _flags = new Dictionary<Flag, bool?>();
public bool? this[Flag key]
{
get
{
if (_flags.ContainsKey(key))
return _flags[key];
return null;
}
set
{
_flags[key] = value;
}
}
protected internal IEnumerable<Flag> Keys => _flags.Keys;
#region Flag Values
public long? BlockSizeValue { get; set; }
public long? CountValue { get; set; }
// fixed, removable, disk, partition
public string FilterValue { get; set; }
public string InputFileValue { get; set; }
public string OutputFileValue { get; set; }
public long? SeekValue { get; set; }
public long? SkipValue { get; set; }
#endregion
/// <summary>
/// Populate a Parameters object from a param string
/// </summary>
/// <param name="parameters">String possibly representing a set of parameters</param>
public Parameters(string parameters)
: base(parameters)
{
this.InternalProgram = InternalProgram.DD;
}
/// <summary>
/// Generate parameters based on a set of known inputs
/// </summary>
/// <param name="system">KnownSystem value to use</param>
/// <param name="type">MediaType value to use</param>
/// <param name="driveLetter">Drive letter to use</param>
/// <param name="filename">Filename to use</param>
/// <param name="driveSpeed">Drive speed to use</param>
/// <param name="paranoid">Enable paranoid mode (safer dumping)</param>
/// <param name="quietMode">Enable quiet mode (no beeps)</param>
/// <param name="retryCount">User-defined reread count</param>
public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, bool paranoid, bool quietMode, int retryCount)
: base(system, type, driveLetter, filename, driveSpeed, paranoid, quietMode, retryCount)
{
}
/// <summary>
/// Blindly generate a parameter string based on the inputs
/// </summary>
/// <returns>Correctly formatted parameter string, null on error</returns>
public override string GenerateParameters()
{
List<string> parameters = new List<string>();
if (BaseCommand != Command.NONE)
parameters.Add(Converters.LongName(BaseCommand));
#region Boolean flags
// Progress
if (GetSupportedCommands(Flag.Progress).Contains(BaseCommand))
{
if (this[Flag.Progress] == true)
parameters.Add($"{this[Flag.Progress]}");
}
// Size
if (GetSupportedCommands(Flag.Size).Contains(BaseCommand))
{
if (this[Flag.Size] == true)
parameters.Add($"{this[Flag.Size]}");
}
#endregion
#region Int64 flags
// Block Size
if (GetSupportedCommands(Flag.BlockSize).Contains(BaseCommand))
{
if (this[Flag.BlockSize] == true && BlockSizeValue != null)
parameters.Add($"{Converters.LongName(Flag.BlockSize)}={BlockSizeValue}");
}
// Count
if (GetSupportedCommands(Flag.Count).Contains(BaseCommand))
{
if (this[Flag.Count] == true && CountValue != null)
parameters.Add($"{Converters.LongName(Flag.Count)}={CountValue}");
}
// Seek
if (GetSupportedCommands(Flag.Seek).Contains(BaseCommand))
{
if (this[Flag.Seek] == true && SeekValue != null)
parameters.Add($"{Converters.LongName(Flag.Seek)}={SeekValue}");
}
// Skip
if (GetSupportedCommands(Flag.Skip).Contains(BaseCommand))
{
if (this[Flag.Skip] == true && SkipValue != null)
parameters.Add($"{Converters.LongName(Flag.Skip)}={SkipValue}");
}
#endregion
#region String flags
// Filter
if (GetSupportedCommands(Flag.Filter).Contains(BaseCommand))
{
if (this[Flag.Filter] == true && FilterValue != null)
parameters.Add($"{Converters.LongName(Flag.Filter)}={FilterValue}");
}
// Input File
if (GetSupportedCommands(Flag.InputFile).Contains(BaseCommand))
{
if (this[Flag.InputFile] == true && InputFileValue != null)
parameters.Add($"{Converters.LongName(Flag.InputFile)}={InputFileValue}");
else
return null;
}
// Output File
if (GetSupportedCommands(Flag.OutputFile).Contains(BaseCommand))
{
if (this[Flag.OutputFile] == true && OutputFileValue != null)
parameters.Add($"{Converters.LongName(Flag.OutputFile)}={OutputFileValue}");
else
return null;
}
#endregion
return string.Empty;
}
/// <summary>
/// Get the input path from the implementation
/// </summary>
/// <returns>String representing the path, null on error</returns>
public override string InputPath() => InputFileValue;
/// <summary>
/// Get the output path from the implementation
/// </summary>
/// <returns>String representing the path, null on error</returns>
public override string OutputPath() => OutputFileValue;
/// <summary>
/// Get the processing speed from the implementation
/// </summary>
/// <returns>int? representing the speed, null on error</returns>
/// <remarks>DD does not support drive speeds</remarks>
public override int? GetSpeed() => 1;
/// <summary>
/// Set the processing speed int the implementation
/// </summary>
/// <param name="speed">int? representing the speed</param>
/// <remarks>DD does not support drive speeds</remarks>
public override void SetSpeed(int? speed)
{
}
/// <summary>
/// Get the MediaType from the current set of parameters
/// </summary>
/// <returns>MediaType value if successful, null on error</returns>
/// <remarks>DD does not know the difference between media types</remarks>
public override MediaType? GetMediaType() => null;
/// <summary>
/// Gets if the current command is considered a dumping command or not
/// </summary>
/// <returns>True if it's a dumping command, false otherwise</returns>
public override bool IsDumpingCommand()
{
switch (this.BaseCommand)
{
case Command.List:
return false;
default:
return true;
}
}
/// <summary>
/// Reset all special variables to have default values
/// </summary>
protected override void ResetValues()
{
BaseCommand = Command.NONE;
_flags = new Dictionary<Flag, bool?>();
BlockSizeValue = null;
CountValue = null;
InputFileValue = null;
OutputFileValue = null;
SeekValue = null;
SkipValue = null;
}
/// <summary>
/// Set default parameters for a given system and media type
/// </summary>
/// <param name="system">KnownSystem value to use</param>
/// <param name="type">MediaType value to use</param>
/// <param name="driveLetter">Drive letter to use</param>
/// <param name="filename">Filename to use</param>
/// <param name="driveSpeed">Drive speed to use</param>
/// <param name="paranoid">Enable paranoid mode (safer dumping)</param>
/// <param name="retryCount">User-defined reread count</param>
protected override void SetDefaultParameters(
KnownSystem? system,
MediaType? type,
char driveLetter,
string filename,
int? driveSpeed,
bool paranoid,
int retryCount)
{
BaseCommand = Command.NONE;
this[Flag.InputFile] = true;
InputFileValue = $"\\\\?\\{driveLetter}:";
this[Flag.OutputFile] = true;
OutputFileValue = filename;
// TODO: Add more common block sizes
this[Flag.BlockSize] = true;
switch (type)
{
case MediaType.FloppyDisk:
BlockSizeValue = 1440 * 1024;
break;
default:
BlockSizeValue = 1024 * 1024 * 1024;
break;
}
this[Flag.Progress] = true;
this[Flag.Size] = true;
}
/// <summary>
/// Scan a possible parameter string and populate whatever possible
/// </summary>
/// <param name="parameters">String possibly representing parameters</param>
/// <returns></returns>
protected override bool ValidateAndSetParameters(string parameters)
{
// The string has to be valid by itself first
if (string.IsNullOrWhiteSpace(parameters))
return false;
// Now split the string into parts for easier validation
// https://stackoverflow.com/questions/14655023/split-a-string-that-has-white-spaces-unless-they-are-enclosed-within-quotes
parameters = parameters.Trim();
List<string> parts = Regex.Matches(parameters, @"[\""].+?[\""]|[^ ]+")
.Cast<Match>()
.Select(m => m.Value)
.ToList();
// Determine what the commandline should look like given the first item
int start = 0;
BaseCommand = Converters.StringToCommand(parts[0]);
if (BaseCommand != Command.NONE)
start = 1;
// Loop through all auxilary flags, if necessary
int i = 0;
for (i = start; i < parts.Count; i++)
{
// Flag read-out values
long? longValue = null;
string stringValue = null;
// Keep a count of keys to determine if we should break out to filename handling or not
int keyCount = Keys.Count();
#region Boolean flags
// Progress
ProcessBooleanParameter(parts, FlagStrings.Progress, Flag.Progress, ref i);
// Size
ProcessBooleanParameter(parts, FlagStrings.Size, Flag.Size, ref i);
#endregion
#region Int64 flags
// Block Size
longValue = ProcessInt64Parameter(parts, FlagStrings.BlockSize, Flag.BlockSize, ref i);
if (longValue == Int64.MinValue)
return false;
else if (longValue != null)
BlockSizeValue = longValue;
// Count
longValue = ProcessInt64Parameter(parts, FlagStrings.Count, Flag.Count, ref i);
if (longValue == Int64.MinValue)
return false;
else if (longValue != null)
CountValue = longValue;
// Seek
longValue = ProcessInt64Parameter(parts, FlagStrings.Seek, Flag.Seek, ref i);
if (longValue == Int64.MinValue)
return false;
else if (longValue != null)
SeekValue = longValue;
// Skip
longValue = ProcessInt64Parameter(parts, FlagStrings.Skip, Flag.Skip, ref i);
if (longValue == Int64.MinValue)
return false;
else if (longValue != null)
SkipValue = longValue;
#endregion
#region String flags
// Filter (fixed, removable, disk, partition)
stringValue = ProcessStringParameter(parts, FlagStrings.Filter, Flag.Filter, ref i);
if (!string.IsNullOrEmpty(stringValue))
FilterValue = stringValue;
// Input File
stringValue = ProcessStringParameter(parts, FlagStrings.InputFile, Flag.InputFile, ref i);
if (string.Equals(stringValue, string.Empty))
return false;
else if (stringValue != null)
InputFileValue = stringValue;
// Output File
stringValue = ProcessStringParameter(parts, FlagStrings.OutputFile, Flag.OutputFile, ref i);
if (string.Equals(stringValue, string.Empty))
return false;
else if (stringValue != null)
OutputFileValue = stringValue;
#endregion
}
return true;
}
/// <summary>
/// Validate if all required output files exist
/// </summary>
/// <param name="basePath">Base filename and path to use for checking</param>
/// <param name="system">KnownSystem type representing the media</param>
/// <param name="type">MediaType type representing the media</param>
/// <returns></returns>
public override bool CheckAllOutputFilesExist(string basePath, KnownSystem? system, MediaType? type, IProgress<Result> progress = null)
{
// TODO: Figure out what sort of output files are expected... just `.bin`?
return true;
}
/// <summary>
/// Generate a SubmissionInfo for the output files
/// </summary>
/// <param name="info">Base submission info to fill in specifics for</param>
/// <param name="basePath">Base filename and path to use for checking</param>
/// <param name="system">KnownSystem type representing the media</param>
/// <param name="type">MediaType type representing the media</param>
/// <param name="drive">Drive representing the disc to get information from</param>
/// <returns></returns>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, KnownSystem? system, MediaType? type, Drive drive)
{
// TODO: Fill in submission info specifics for DD
string outputDirectory = Path.GetDirectoryName(basePath);
switch (type)
{
// Determine type-specific differences
}
switch (system)
{
case KnownSystem.KonamiPython2:
if (GetPlayStationExecutableInfo(drive?.Letter, out string pythonTwoSerial, out Region? pythonTwoRegion, out string pythonTwoDate))
{
info.CommonDiscInfo.Comments += $"Internal Disc Serial: {pythonTwoSerial}\n";
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? pythonTwoRegion;
info.CommonDiscInfo.EXEDateBuildDate = pythonTwoDate;
}
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? "";
break;
case KnownSystem.SonyPlayStation:
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationSerial, out Region? playstationRegion, out string playstationDate))
{
info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationSerial}\n";
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationRegion;
info.CommonDiscInfo.EXEDateBuildDate = playstationDate;
}
info.CopyProtection.AntiModchip = GetPlayStationAntiModchipDetected(drive?.Letter) ? YesNo.Yes : YesNo.No;
break;
case KnownSystem.SonyPlayStation2:
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationTwoSerial, out Region? playstationTwoRegion, out string playstationTwoDate))
{
info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationTwoSerial}\n";
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationTwoRegion;
info.CommonDiscInfo.EXEDateBuildDate = playstationTwoDate;
}
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? "";
break;
case KnownSystem.SonyPlayStation4:
info.VersionAndEditions.Version = GetPlayStation4Version(drive?.Letter) ?? "";
break;
}
}
/// <summary>
/// Get the list of commands that use a given flag
/// </summary>
/// <param name="flag">Flag value to get commands for</param>
/// <returns>List of Commands, if possible</returns>
private static List<Command> GetSupportedCommands(Flag flag)
{
var commands = new List<Command>();
switch (flag)
{
#region Boolean flags
case Flag.Progress:
commands.Add(Command.NONE);
break;
case Flag.Size:
commands.Add(Command.NONE);
break;
#endregion
#region Int64 flags
case Flag.BlockSize:
commands.Add(Command.NONE);
break;
case Flag.Count:
commands.Add(Command.NONE);
break;
case Flag.Seek:
commands.Add(Command.NONE);
break;
case Flag.Skip:
commands.Add(Command.NONE);
break;
#endregion
#region String flags
case Flag.Filter:
commands.Add(Command.NONE);
break;
case Flag.InputFile:
commands.Add(Command.NONE);
break;
case Flag.OutputFile:
commands.Add(Command.NONE);
break;
#endregion
case Flag.NONE:
default:
return commands;
}
return commands;
}
/// <summary>
/// Process a boolean parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="flagString">Flag string to check</param>
/// <param name="flag">Flag value corresponding to the flag</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>
private bool ProcessBooleanParameter(List<string> parts, string flagString, Flag flag, ref int i)
{
if (parts == null)
return false;
if (parts[i] == flagString)
{
if (!GetSupportedCommands(flag).Contains(BaseCommand))
return false;
this[flag] = true;
}
return true;
}
/// <summary>
/// Process an Int64 parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="flagString">Flag string to check</param>
/// <param name="flag">Flag value corresponding to the flag</param>
/// <param name="i">Reference to the position in the parts</param>
/// <returns>Int64 value if success, Int64.MinValue if skipped, null on error/returns>
private long? ProcessInt64Parameter(List<string> parts, string flagString, Flag flag, ref int i)
{
if (parts == null)
return null;
if (parts[i].StartsWith(flagString))
{
if (!GetSupportedCommands(flag).Contains(BaseCommand))
return null;
string[] commandParts = parts[i].Split('=');
if (commandParts.Length != 2)
return null;
string valuePart = commandParts[1];
long factor = 1;
// Characters
if (valuePart.EndsWith("c", StringComparison.Ordinal))
{
factor = 1;
valuePart.TrimEnd('c');
}
// Words
else if (valuePart.EndsWith("w", StringComparison.Ordinal))
{
factor = 2;
valuePart.TrimEnd('w');
}
// Double Words
else if (valuePart.EndsWith("d", StringComparison.Ordinal))
{
factor = 4;
valuePart.TrimEnd('d');
}
// Quad Words
else if (valuePart.EndsWith("q", StringComparison.Ordinal))
{
factor = 8;
valuePart.TrimEnd('q');
}
// Kilobytes
else if (valuePart.EndsWith("k", StringComparison.Ordinal))
{
factor = 1024;
valuePart.TrimEnd('k');
}
// Megabytes
else if (valuePart.EndsWith("M", StringComparison.Ordinal))
{
factor = 1024 * 1024;
valuePart.TrimEnd('M');
}
// Gigabytes
else if (valuePart.EndsWith("G", StringComparison.Ordinal))
{
factor = 1024 * 1024 * 1024;
valuePart.TrimEnd('G');
}
if (!IsValidInt64(valuePart))
return null;
this[flag] = true;
return long.Parse(valuePart) * factor;
}
return Int64.MinValue;
}
/// <summary>
/// Process a string parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="flagString">Flag string to check</param>
/// <param name="flag">Flag value corresponding to the flag</param>
/// <param name="i">Reference to the position in the parts</param>
/// <returns>String value if possible, string.Empty on missing, null on error</returns>
private string ProcessStringParameter(List<string> parts, string flagString, Flag flag, ref int i)
{
if (parts == null)
return null;
if (parts[i] == flagString)
{
if (!GetSupportedCommands(flag).Contains(BaseCommand))
return null;
string[] commandParts = parts[i].Split('=');
if (commandParts.Length != 2)
return null;
string valuePart = commandParts[1];
this[flag] = true;
return valuePart.Trim('"');
}
return string.Empty;
}
}
}

View File

@@ -1,54 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472;net48;netcoreapp3.1</TargetFrameworks>
<Title>DICUI Library</Title>
<AssemblyName>DICUI.Library</AssemblyName>
<Description>Library code for DICUI and DICUI.Check</Description>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2020</Copyright>
<RepositoryUrl>https://github.com/SabreTools/DICUI</RepositoryUrl>
<Version>1.17.0</Version>
<AssemblyVersion>1.17.0</AssemblyVersion>
<FileVersion>1.17.0</FileVersion>
<IncludeSource>true</IncludeSource>
<IncludeSymbols>true</IncludeSymbols>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)'!='netcoreapp3.1'">
<DefineConstants>NET_FRAMEWORK</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'!='netcoreapp3.1'">
<COMReference Include="IMAPI2">
<Guid>{2735412F-7F64-5B0F-8F00-5D77AFBE261E}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
<COMReference Include="IMAPI2FS">
<Guid>{2C941FD0-975B-59BE-A960-9A2A262853A5}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="BurnOutSharp" Version="1.4.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="System.Management" Version="4.7.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Management" />
</ItemGroup>
</Project>

View File

@@ -1,710 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using DICUI.Utilities;
using DICUI.Web;
namespace DICUI.Data
{
public abstract class BaseParameters
{
/// <summary>
/// Path to the executable
/// </summary>
public string ExecutablePath { get; set; }
/// <summary>
/// Program that this set of parameters represents
/// </summary>
public InternalProgram InternalProgram { get; set; }
/// <summary>
/// Process to track external program
/// </summary>
private Process process;
/// <summary>
/// Populate a Parameters object from a param string
/// </summary>
/// <param name="parameters">String possibly representing a set of parameters</param>
public BaseParameters(string parameters)
{
// If any parameters are not valid, wipe out everything
if (!ValidateAndSetParameters(parameters))
{
ResetValues();
}
}
/// <summary>
/// Generate parameters based on a set of known inputs
/// </summary>
/// <param name="system">KnownSystem value to use</param>
/// <param name="type">MediaType value to use</param>
/// <param name="driveLetter">Drive letter to use</param>
/// <param name="filename">Filename to use</param>
/// <param name="driveSpeed">Drive speed to use</param>
/// <param name="paranoid">Enable paranoid mode (safer dumping)</param>
/// <param name="quietMode">Enable quiet mode (no beeps)</param>
/// <param name="retryCount">User-defined reread count</param>
public BaseParameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, bool paranoid, bool quietMode, int retryCount)
{
SetDefaultParameters(system, type, driveLetter, filename, driveSpeed, paranoid, retryCount);
}
/// <summary>
/// Blindly generate a parameter string based on the inputs
/// </summary>
/// <returns>Correctly formatted parameter string, null on error</returns>
public abstract string GenerateParameters();
/// <summary>
/// Get the input path from the implementation
/// </summary>
/// <returns>String representing the path, null on error</returns>
public abstract string InputPath();
/// <summary>
/// Get the output path from the implementation
/// </summary>
/// <returns>String representing the path, null on error</returns>
public abstract string OutputPath();
/// <summary>
/// Get the processing speed from the implementation
/// </summary>
/// <returns>int? representing the speed, null on error</returns>
public abstract int? GetSpeed();
/// <summary>
/// Set the processing speed int the implementation
/// </summary>
/// <param name="speed">int? representing the speed</param>
public abstract void SetSpeed(int? speed);
/// <summary>
/// Get the MediaType from the current set of parameters
/// </summary>
/// <returns>MediaType value if successful, null on error</returns>
public abstract MediaType? GetMediaType();
/// <summary>
/// Gets if the current command is considered a dumping command or not
/// </summary>
/// <returns>True if it's a dumping command, false otherwise</returns>
public abstract bool IsDumpingCommand();
/// <summary>
/// Returns if the current Parameter object is valid
/// </summary>
/// <returns></returns>
public bool IsValid()
{
return GenerateParameters() != null;
}
/// <summary>
/// Reset all special variables to have default values
/// </summary>
protected abstract void ResetValues();
/// <summary>
/// Set default parameters for a given system and media type
/// </summary>
/// <param name="system">KnownSystem value to use</param>
/// <param name="type">MediaType value to use</param>
/// <param name="driveLetter">Drive letter to use</param>
/// <param name="filename">Filename to use</param>
/// <param name="driveSpeed">Drive speed to use</param>
/// <param name="paranoid">Enable paranoid mode (safer dumping)</param>
/// <param name="retryCount">User-defined reread count</param>
protected abstract void SetDefaultParameters(
KnownSystem? system,
MediaType? type,
char driveLetter,
string filename,
int? driveSpeed,
bool paranoid,
int retryCount);
/// <summary>
/// Scan a possible parameter string and populate whatever possible
/// </summary>
/// <param name="parameters">String possibly representing parameters</param>
/// <returns></returns>
protected abstract bool ValidateAndSetParameters(string parameters);
/// <summary>
/// Validate if all required output files exist
/// </summary>
/// <param name="basePath">Base filename and path to use for checking</param>
/// <param name="system">KnownSystem type representing the media</param>
/// <param name="type">MediaType type representing the media</param>
/// <param name="progress">Optional result progress callback</param>
/// <returns></returns>
public abstract bool CheckAllOutputFilesExist(string basePath, KnownSystem? system, MediaType? type, IProgress<Result> progress = null);
/// <summary>
/// Generate a SubmissionInfo for the output files
/// </summary>
/// <param name="submissionInfo">Base submission info to fill in specifics for</param>
/// <param name="basePath">Base filename and path to use for checking</param>
/// <param name="system">KnownSystem type representing the media</param>
/// <param name="type">MediaType type representing the media</param>
/// <param name="drive">Drive representing the disc to get information from</param>
public abstract void GenerateSubmissionInfo(SubmissionInfo submissionInfo, string basePath, KnownSystem? system, MediaType? type, Drive drive);
/// <summary>
/// Run internal program
/// </summary>
public void ExecuteInternalProgram()
{
process = new Process()
{
StartInfo = new ProcessStartInfo()
{
FileName = ExecutablePath,
Arguments = GenerateParameters() ?? "",
},
};
process.Start();
process.WaitForExit();
}
/// <summary>
/// Run internal program async with an input set of parameters
/// </summary>
/// <param name="parameters"></param>
/// <returns>Standard output from commandline window</returns>
public async Task<string> ExecuteInternalProgram(BaseParameters parameters)
{
Process childProcess;
string output = await Task.Run(() =>
{
childProcess = new Process()
{
StartInfo = new ProcessStartInfo()
{
FileName = parameters.ExecutablePath,
Arguments = parameters.GenerateParameters(),
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
},
};
childProcess.Start();
childProcess.WaitForExit(1000);
// Just in case, we want to push a button 5 times to clear any errors
for (int i = 0; i < 5; i++)
childProcess.StandardInput.WriteLine("Y");
string stdout = childProcess.StandardOutput.ReadToEnd();
childProcess.Dispose();
return stdout;
});
return output;
}
/// <summary>
/// Cancel an in-progress dumping process
/// </summary>
public void KillInternalProgram()
{
try
{
if (process != null && !process.HasExited)
process.Kill();
}
catch
{ }
}
#region Parameter Parsing
/// <summary>
/// Returns whether or not the selected item exists
/// </summary>
/// <param name="parameters">List of parameters to check against</param>
/// <param name="index">Current index</param>
/// <returns>True if the next item exists, false otherwise</returns>
protected static bool DoesExist(List<string> parameters, int index)
{
if (index >= parameters.Count)
return false;
return true;
}
/// <summary>
/// Get the full lines from the input file, if possible
/// </summary>
/// <param name="filename">file location</param>
/// <param name="binary">True if should read as binary, false otherwise (default)</param>
/// <returns>Full text of the file, null on error</returns>
protected static string GetFullFile(string filename, bool binary = false)
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(filename))
return null;
// If we're reading as binary
if (binary)
{
string hex = string.Empty;
using (BinaryReader br = new BinaryReader(File.OpenRead(filename)))
{
while (br.BaseStream.Position < br.BaseStream.Length)
{
hex += Convert.ToString(br.ReadByte(), 16);
}
}
return hex;
}
return string.Join("\n", File.ReadAllLines(filename));
}
/// <summary>
/// Returns whether a string is a flag (starts with '/')
/// </summary>
/// <param name="parameter">String value to check</param>
/// <returns>True if it's a flag, false otherwise</returns>
protected static bool IsFlag(string parameter)
{
if (parameter.Trim('\"').StartsWith("/"))
return true;
return false;
}
/// <summary>
/// Returns whether a string is a valid drive letter
/// </summary>
/// <param name="parameter">String value to check</param>
/// <returns>True if it's a valid drive letter, false otherwise</returns>
protected static bool IsValidDriveLetter(string parameter)
{
if (!Regex.IsMatch(parameter, @"^[A-Z]:?\\?$"))
return false;
return true;
}
/// <summary>
/// Returns whether a string is a valid bool
/// </summary>
/// <param name="parameter">String value to check</param>
/// <returns>True if it's a valid bool, false otherwise</returns>
protected static bool IsValidBool(string parameter)
{
return bool.TryParse(parameter, out bool _);
}
/// <summary>
/// Returns whether a string is a valid byte
/// </summary>
/// <param name="parameter">String value to check</param>
/// <param name="lowerBound">Lower bound (>=)</param>
/// <param name="upperBound">Upper bound (<=)</param>
/// <returns>True if it's a valid byte, false otherwise</returns>
protected static bool IsValidInt8(string parameter, sbyte lowerBound = -1, sbyte upperBound = -1)
{
if (!sbyte.TryParse(parameter, out sbyte temp))
return false;
else if (lowerBound != -1 && temp < lowerBound)
return false;
else if (upperBound != -1 && temp > upperBound)
return false;
return true;
}
/// <summary>
/// Returns whether a string is a valid Int16
/// </summary>
/// <param name="parameter">String value to check</param>
/// <param name="lowerBound">Lower bound (>=)</param>
/// <param name="upperBound">Upper bound (<=)</param>
/// <returns>True if it's a valid Int16, false otherwise</returns>
protected static bool IsValidInt16(string parameter, short lowerBound = -1, short upperBound = -1)
{
if (!short.TryParse(parameter, out short temp))
return false;
else if (lowerBound != -1 && temp < lowerBound)
return false;
else if (upperBound != -1 && temp > upperBound)
return false;
return true;
}
/// <summary>
/// Returns whether a string is a valid Int32
/// </summary>
/// <param name="parameter">String value to check</param>
/// <param name="lowerBound">Lower bound (>=)</param>
/// <param name="upperBound">Upper bound (<=)</param>
/// <returns>True if it's a valid Int32, false otherwise</returns>
protected static bool IsValidInt32(string parameter, int lowerBound = -1, int upperBound = -1)
{
if (!int.TryParse(parameter, out int temp))
return false;
else if (lowerBound != -1 && temp < lowerBound)
return false;
else if (upperBound != -1 && temp > upperBound)
return false;
return true;
}
/// <summary>
/// Returns whether a string is a valid Int64
/// </summary>
/// <param name="parameter">String value to check</param>
/// <param name="lowerBound">Lower bound (>=)</param>
/// <param name="upperBound">Upper bound (<=)</param>
/// <returns>True if it's a valid Int64, false otherwise</returns>
protected static bool IsValidInt64(string parameter, long lowerBound = -1, long upperBound = -1)
{
if (!long.TryParse(parameter, out long temp))
return false;
else if (lowerBound != -1 && temp < lowerBound)
return false;
else if (upperBound != -1 && temp > upperBound)
return false;
return true;
}
#endregion
#region Common Information Extraction
/// <summary>
/// Get the split values for ISO-based media
/// </summary>
/// <param name="hashData">String representing the combined hash data</param>
/// <returns>True if extraction was successful, false otherwise</returns>
protected static bool GetISOHashValues(string hashData, out long size, out string crc32, out string md5, out string sha1)
{
size = -1; crc32 = null; md5 = null; sha1 = null;
if (string.IsNullOrWhiteSpace(hashData))
return false;
Regex hashreg = new Regex(@"<rom name="".*?"" size=""(.*?)"" crc=""(.*?)"" md5=""(.*?)"" sha1=""(.*?)""");
Match m = hashreg.Match(hashData);
if (m.Success)
{
Int64.TryParse(m.Groups[1].Value, out size);
crc32 = m.Groups[2].Value;
md5 = m.Groups[3].Value;
sha1 = m.Groups[4].Value;
return true;
}
else
{
return false;
}
}
/// <summary>
/// Get the existance of an anti-modchip string from a PlayStation disc, if possible
/// </summary>
/// <param name="driveLetter">Drive letter to use to check</param>
/// <returns>Anti-modchip existance if possible, false on error</returns>
protected static bool GetPlayStationAntiModchipDetected(char? driveLetter)
{
// If there's no drive letter, we can't do this part
if (driveLetter == null)
return false;
// If the folder no longer exists, we can't do this part
string drivePath = driveLetter + ":\\";
if (!Directory.Exists(drivePath))
return false;
string enAntiModString = " SOFTWARE TERMINATED\nCONSOLE MAY HAVE BEEN MODIFIED\n CALL 1-888-780-7690";
string jpAntiModString = "強制終了しました。\n本体が改造されている\nおそれがあります。";
// Scan through each file to check for the anti-modchip strings
foreach (string path in Directory.EnumerateFiles(drivePath, "*", SearchOption.AllDirectories))
{
try
{
// TODO: This is a memory hog
string fileContents = File.ReadAllText(path);
if (fileContents.Contains(enAntiModString) || fileContents.Contains(jpAntiModString))
return true;
}
catch
{
// No-op, we don't care what the error was
}
}
return false;
}
/// <summary>
/// Get the EXE date from a PlayStation disc, if possible
/// </summary>
/// <param name="driveLetter">Drive letter to use to check</param>
/// <param name="serial">Internal disc serial, if possible</param>
/// <param name="region">Output region, if possible</param>
/// <param name="date">Output EXE date in "yyyy-mm-dd" format if possible, null on error</param>
/// <returns></returns>
protected static bool GetPlayStationExecutableInfo(char? driveLetter, out string serial, out Region? region, out string date)
{
serial = null; region = null; date = null;
// If there's no drive letter, we can't do this part
if (driveLetter == null)
return false;
// If the folder no longer exists, we can't do this part
string drivePath = driveLetter + ":\\";
if (!Directory.Exists(drivePath))
return false;
// Get the two paths that we will need to check
string psxExePath = Path.Combine(drivePath, "PSX.EXE");
string systemCnfPath = Path.Combine(drivePath, "SYSTEM.CNF");
// Try both of the common paths that contain information
string exeName = null;
// 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))
{
var match = Regex.Match(bootValue, @"cdrom.?:\\?(.*)");
if (match != null && match.Groups.Count > 1)
{
exeName = match.Groups[1].Value;
exeName = exeName.Split(';')[0];
serial = exeName.Replace('_', '-').Replace(".", string.Empty);
}
}
// If the SYSTEM.CNF value can't be found, try PSX.EXE
if (string.IsNullOrWhiteSpace(exeName) && File.Exists(psxExePath))
exeName = "PSX.EXE";
// If neither can be found, we return false
if (string.IsNullOrWhiteSpace(exeName))
return false;
// Get the region, if possible
region = GetPlayStationRegion(exeName);
// Now that we have the EXE name, try to get the fileinfo for it
string exePath = Path.Combine(drivePath, exeName);
if (!File.Exists(exePath))
return false;
// Fix the Y2K timestamp issue
FileInfo fi = new FileInfo(exePath);
DateTime dt = new DateTime(fi.LastWriteTimeUtc.Year >= 1900 && fi.LastWriteTimeUtc.Year < 1920 ? 2000 + fi.LastWriteTimeUtc.Year % 100 : fi.LastWriteTimeUtc.Year,
fi.LastWriteTimeUtc.Month, fi.LastWriteTimeUtc.Day);
date = dt.ToString("yyyy-MM-dd");
return true;
}
/// <summary>
/// Get the version from a PlayStation 2 disc, if possible
/// </summary>
/// <param name="driveLetter">Drive letter to use to check</param>
/// <returns>Game version if possible, null on error</returns>
protected static string GetPlayStation2Version(char? driveLetter)
{
// If there's no drive letter, we can't do this part
if (driveLetter == null)
return null;
// If the folder no longer exists, we can't do this part
string drivePath = driveLetter + ":\\";
if (!Directory.Exists(drivePath))
return null;
// Get the SYSTEM.CNF path to check
string systemCnfPath = Path.Combine(drivePath, "SYSTEM.CNF");
// 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;
}
/// <summary>
/// Get the version from a PlayStation 4 disc, if possible
/// </summary>
/// <param name="driveLetter">Drive letter to use to check</param>
/// <returns>Game version if possible, null on error</returns>
protected static string GetPlayStation4Version(char? driveLetter)
{
// If there's no drive letter, we can't do this part
if (driveLetter == null)
return null;
// If the folder no longer exists, we can't do this part
string drivePath = driveLetter + ":\\";
if (!Directory.Exists(drivePath))
return null;
// If we can't find param.sfo, we don't have a PlayStation 4 disc
string paramSfoPath = Path.Combine(drivePath, "bd", "param.sfo");
if (!File.Exists(paramSfoPath))
return null;
// Let's try reading param.sfo to find the version at the end of the file
try
{
using (BinaryReader br = new BinaryReader(File.OpenRead(paramSfoPath)))
{
br.BaseStream.Seek(-0x08, SeekOrigin.End);
return new string(br.ReadChars(5));
}
}
catch
{
// We don't care what the error was
return null;
}
}
#endregion
#region Category Extraction
/// <summary>
/// Determine the category based on the UMDImageCreator string
/// </summary>
/// <param name="region">String representing the category</param>
/// <returns>Category, if possible</returns>
protected static DiscCategory? GetUMDCategory(string category)
{
switch (category)
{
case "GAME":
return DiscCategory.Games;
case "VIDEO":
return DiscCategory.Video;
case "AUDIO":
return DiscCategory.Audio;
default:
return null;
}
}
#endregion
#region Region Extraction
/// <summary>
/// Determine the region based on the PlayStation serial code
/// </summary>
/// <param name="serial">PlayStation serial code</param>
/// <returns>Region mapped from name, if possible</returns>
protected static Region? GetPlayStationRegion(string serial)
{
// Standardized "S" serials
if (serial.StartsWith("S"))
{
// string publisher = serial[0] + serial[1];
// char secondRegion = serial[3];
switch (serial[2])
{
case 'A':
return Region.Asia;
case 'C':
return Region.China;
case 'E':
return Region.Europe;
case 'J':
return Region.JapanKorea;
case 'K':
return Region.Korea;
case 'P':
return Region.Japan;
case 'U':
return Region.USA;
}
}
// Japan-only special serial
else if (serial.StartsWith("PAPX"))
return Region.Japan;
// Region appears entirely random
else if (serial.StartsWith("PABX"))
return null;
// Japan-only special serial
else if (serial.StartsWith("PCBX"))
return Region.Japan;
// Single disc known, Japan
else if (serial.StartsWith("PDBX"))
return Region.Japan;
// Single disc known, Europe
else if (serial.StartsWith("PEBX"))
return Region.Europe;
return null;
}
/// <summary>
/// Determine the region based on the XGD serial character
/// </summary>
/// <param name="region">Character denoting the region</param>
/// <returns>Region, if possible</returns>
protected static Region? GetXgdRegion(char region)
{
switch (region)
{
case 'W':
return Region.World;
case 'A':
return Region.USA;
case 'J':
return Region.JapanAsia;
case 'E':
return Region.Europe;
case 'K':
return Region.USAJapan;
case 'L':
return Region.USAEurope;
case 'H':
return Region.JapanEurope;
default:
return null;
}
}
#endregion
}
}

View File

@@ -1,286 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace DICUI.Data
{
public class Options : IDictionary<string, string>
{
private Dictionary<string, string> _settings;
#region Internal Program
public string AaruPath
{
get { return GetStringSetting(_settings, "AaruPath", "Programs\\Aaru\\Aaru.exe"); }
set { _settings["AaruPath"] = value; }
}
public string CreatorPath
{
get { return GetStringSetting(_settings, "CreatorPath", "Programs\\Creator\\DiscImageCreator.exe"); }
set { _settings["CreatorPath"] = value; }
}
public string DDPath
{
get { return GetStringSetting(_settings, "DDPath", "Programs\\DD\\dd.exe"); }
set { _settings["DDPath"] = value; }
}
public string InternalProgram
{
get { return GetStringSetting(_settings, "InternalProgram", Data.InternalProgram.DiscImageCreator.ToString()); }
set { _settings["InternalProgram"] = value; }
}
#endregion
#region Extra Paths
public string DefaultOutputPath
{
get { return GetStringSetting(_settings, "DefaultOutputPath", "ISO"); }
set { _settings["DefaultOutputPath"] = value; }
}
public string SubDumpPath
{
get { return GetStringSetting(_settings, "SubDumpPath", "Programs\\Subdump\\subdump.exe"); }
set { _settings["SubDumpPath"] = value; }
}
#endregion
#region Dumping Speeds
public int PreferredDumpSpeedCD
{
get { return GetInt32Setting(_settings, "PreferredDumpSpeedCD", 72); }
set { _settings["PreferredDumpSpeedCD"] = value.ToString(); }
}
public int PreferredDumpSpeedDVD
{
get { return GetInt32Setting(_settings, "PreferredDumpSpeedDVD", 24); }
set { _settings["PreferredDumpSpeedDVD"] = value.ToString(); }
}
public int PreferredDumpSpeedBD
{
get { return GetInt32Setting(_settings, "PreferredDumpSpeedBD", 16); }
set { _settings["PreferredDumpSpeedBD"] = value.ToString(); }
}
#endregion
#region Extra Dumping Options
public bool QuietMode
{
get { return GetBooleanSetting(_settings, "QuietMode", false); }
set { _settings["QuietMode"] = value.ToString(); }
}
public bool ParanoidMode
{
get { return GetBooleanSetting(_settings, "ParanoidMode", false); }
set { _settings["ParanoidMode"] = value.ToString(); }
}
public bool ScanForProtection
{
get { return GetBooleanSetting(_settings, "ScanForProtection", true); }
set { _settings["ScanForProtection"] = value.ToString(); }
}
public int RereadAmountForC2
{
get { return GetInt32Setting(_settings, "RereadAmountForC2", 20); }
set { _settings["RereadAmountForC2"] = value.ToString(); }
}
public bool AddPlaceholders
{
get { return GetBooleanSetting(_settings, "AddPlaceholders", true); }
set { _settings["AddPlaceholders"] = value.ToString(); }
}
public bool PromptForDiscInformation
{
get { return GetBooleanSetting(_settings, "PromptForDiscInformation", true); }
set { _settings["PromptForDiscInformation"] = value.ToString(); }
}
public bool IgnoreFixedDrives
{
get { return GetBooleanSetting(_settings, "IgnoreFixedDrives", false); }
set { _settings["IgnoreFixedDrives"] = value.ToString(); }
}
public bool ResetDriveAfterDump
{
get { return GetBooleanSetting(_settings, "ResetDriveAfterDump", false); }
set { _settings["ResetDriveAfterDump"] = value.ToString(); }
}
#endregion
#region Skip Options
public bool SkipMediaTypeDetection
{
get { return GetBooleanSetting(_settings, "SkipMediaTypeDetection", false); }
set { _settings["SkipMediaTypeDetection"] = value.ToString(); }
}
public bool SkipSystemDetection
{
get { return GetBooleanSetting(_settings, "SkipSystemDetection", false); }
set { _settings["SkipSystemDetection"] = value.ToString(); }
}
#endregion
#region Logging Options
public bool VerboseLogging
{
get { return GetBooleanSetting(_settings, "VerboseLogging", true); }
set { _settings["VerboseLogging"] = value.ToString(); }
}
public bool OpenLogWindowAtStartup
{
get { return GetBooleanSetting(_settings, "OpenLogWindowAtStartup", true); }
set { _settings["OpenLogWindowAtStartup"] = value.ToString(); }
}
#endregion
#region Redump Login Information
public string Username
{
get { return GetStringSetting(_settings, "Username", ""); }
set { _settings["Username"] = value; }
}
// TODO: Figure out a way to keep this encrypted in some way, BASE64 to start?
public string Password
{
get { return GetStringSetting(_settings, "Password", ""); }
set { _settings["Password"] = value; }
}
#endregion
/// <summary>
/// Constructor taking a dictionary for settings
/// </summary>
/// <param name="settings"></param>
public Options(Dictionary<string, string> settings = null)
{
this._settings = settings ?? new Dictionary<string, string>();
}
/// <summary>
/// Get a Boolean setting from a settings, dictionary
/// </summary>
/// <param name="settings">Dictionary representing the settings</param>
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
private bool GetBooleanSetting(Dictionary<string, string> settings, string key, bool defaultValue)
{
if (settings.ContainsKey(key))
{
if (Boolean.TryParse(settings[key], out bool value))
return value;
else
return defaultValue;
}
else
{
return defaultValue;
}
}
/// <summary>
/// Get an Int32 setting from a settings, dictionary
/// </summary>
/// <param name="settings">Dictionary representing the settings</param>
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
private int GetInt32Setting(Dictionary<string, string> settings, string key, int defaultValue)
{
if (settings.ContainsKey(key))
{
if (Int32.TryParse(settings[key], out int value))
return value;
else
return defaultValue;
}
else
{
return defaultValue;
}
}
/// <summary>
/// Get a String setting from a settings, dictionary
/// </summary>
/// <param name="settings">Dictionary representing the settings</param>
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
private string GetStringSetting(Dictionary<string, string> settings, string key, string defaultValue)
{
if (settings.ContainsKey(key))
return settings[key];
else
return defaultValue;
}
#region IDictionary implementations
public ICollection<string> Keys => _settings.Keys;
public ICollection<string> Values => _settings.Values;
public int Count => _settings.Count;
public bool IsReadOnly => ((IDictionary<string, string>)_settings).IsReadOnly;
public string this[string key]
{
get { return (_settings.ContainsKey(key) ? _settings[key] : null); }
set { _settings[key] = value; }
}
public bool ContainsKey(string key) => _settings.ContainsKey(key);
public void Add(string key, string value) => _settings.Add(key, value);
public bool Remove(string key) => _settings.Remove(key);
public bool TryGetValue(string key, out string value) => _settings.TryGetValue(key, out value);
public void Add(KeyValuePair<string, string> item) => _settings.Add(item.Key, item.Value);
public void Clear() => _settings.Clear();
public bool Contains(KeyValuePair<string, string> item) => ((IDictionary<string, string>)_settings).Contains(item);
public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex) => ((IDictionary<string, string>)_settings).CopyTo(array, arrayIndex);
public bool Remove(KeyValuePair<string, string> item) => ((IDictionary<string, string>)_settings).Remove(item);
public IEnumerator<KeyValuePair<string, string>> GetEnumerator() => _settings.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _settings.GetEnumerator();
#endregion
}
}

View File

@@ -1,333 +0,0 @@
using DICUI.Data;
namespace DICUI.DiscImageCreator
{
public static class Converters
{
#region Cross-enumeration conversions
/// <summary>
/// Get the most common known system for a given MediaType
/// </summary>
/// <param name="baseCommand">Command value to check</param>
/// <returns>KnownSystem if possible, null on error</returns>
public static KnownSystem? ToKnownSystem(Command baseCommand)
{
switch (baseCommand)
{
case Command.Audio:
return KnownSystem.AudioCD;
case Command.CompactDisc:
case Command.Data:
case Command.DigitalVideoDisc:
case Command.Disk:
case Command.Floppy:
case Command.Tape:
return KnownSystem.IBMPCCompatible;
case Command.GDROM:
case Command.Swap:
return KnownSystem.SegaDreamcast;
case Command.BluRay:
return KnownSystem.SonyPlayStation3;
case Command.SACD:
return KnownSystem.SuperAudioCD;
case Command.XBOX:
case Command.XBOXSwap:
return KnownSystem.MicrosoftXBOX;
case Command.XGD2Swap:
case Command.XGD3Swap:
return KnownSystem.MicrosoftXBOX360;
default:
return null;
}
}
/// <summary>
/// Get the MediaType associated with a given base command
/// </summary>
/// <param name="baseCommand">Command value to check</param>
/// <returns>MediaType if possible, null on error</returns>
/// <remarks>This takes the "safe" route by assuming the larger of any given format</remarks>
public static MediaType? ToMediaType(Command baseCommand)
{
switch (baseCommand)
{
case Command.Audio:
case Command.CompactDisc:
case Command.Data:
case Command.SACD:
return MediaType.CDROM;
case Command.GDROM:
case Command.Swap:
return MediaType.GDROM;
case Command.DigitalVideoDisc:
case Command.XBOX:
case Command.XBOXSwap:
case Command.XGD2Swap:
case Command.XGD3Swap:
return MediaType.DVD;
case Command.BluRay:
return MediaType.BluRay;
// Non-optical
case Command.Floppy:
return MediaType.FloppyDisk;
case Command.Disk:
return MediaType.HardDisk;
case Command.Tape:
return MediaType.DataCartridge;
default:
return null;
}
}
/// <summary>
/// Get the default extension for a given disc type
/// </summary>
/// <param name="type">MediaType value to check</param>
/// <returns>Valid extension (with leading '.'), null on error</returns>
public static string Extension(MediaType? type)
{
switch (type)
{
case MediaType.CDROM:
case MediaType.GDROM:
case MediaType.Cartridge:
case MediaType.HardDisk:
case MediaType.CompactFlash:
case MediaType.MMC:
case MediaType.SDCard:
case MediaType.FlashDrive:
return ".bin";
case MediaType.DVD:
case MediaType.HDDVD:
case MediaType.BluRay:
case MediaType.NintendoWiiOpticalDisc:
return ".iso";
case MediaType.LaserDisc:
case MediaType.NintendoGameCubeGameDisc:
return ".raw";
case MediaType.NintendoWiiUOpticalDisc:
return ".wud";
case MediaType.FloppyDisk:
return ".img";
case MediaType.Cassette:
return ".wav";
case MediaType.NONE:
default:
return null;
}
}
#endregion
#region Convert to Long Name
/// <summary>
/// Get the string representation of the Command enum values
/// </summary>
/// <param name="command">Command value to convert</param>
/// <returns>String representing the value, if possible</returns>
public static string LongName(Command command)
{
switch (command)
{
case Command.Audio:
return CommandStrings.Audio;
case Command.BluRay:
return CommandStrings.BluRay;
case Command.Close:
return CommandStrings.Close;
case Command.CompactDisc:
return CommandStrings.CompactDisc;
case Command.Data:
return CommandStrings.Data;
case Command.DigitalVideoDisc:
return CommandStrings.DigitalVideoDisc;
case Command.Disk:
return CommandStrings.Disk;
case Command.DriveSpeed:
return CommandStrings.DriveSpeed;
case Command.Eject:
return CommandStrings.Eject;
case Command.Floppy:
return CommandStrings.Floppy;
case Command.GDROM:
return CommandStrings.GDROM;
case Command.MDS:
return CommandStrings.MDS;
case Command.Merge:
return CommandStrings.Merge;
case Command.Reset:
return CommandStrings.Reset;
case Command.SACD:
return CommandStrings.SACD;
case Command.Start:
return CommandStrings.Start;
case Command.Stop:
return CommandStrings.Stop;
case Command.Sub:
return CommandStrings.Sub;
case Command.Swap:
return CommandStrings.Swap;
case Command.Tape:
return CommandStrings.Tape;
case Command.XBOX:
return CommandStrings.XBOX;
case Command.XBOXSwap:
return CommandStrings.XBOXSwap;
case Command.XGD2Swap:
return CommandStrings.XGD2Swap;
case Command.XGD3Swap:
return CommandStrings.XGD3Swap;
case Command.NONE:
default:
return "";
}
}
/// <summary>
/// Get the string representation of the Flag enum values
/// </summary>
/// <param name="command">Flag value to convert</param>
/// <returns>String representing the value, if possible</returns>
public static string LongName(Flag flag)
{
switch (flag)
{
case Flag.AddOffset:
return FlagStrings.AddOffset;
case Flag.AMSF:
return FlagStrings.AMSF;
case Flag.AtariJaguar:
return FlagStrings.AtariJaguar;
case Flag.BEOpcode:
return FlagStrings.BEOpcode;
case Flag.C2Opcode:
return FlagStrings.C2Opcode;
case Flag.CopyrightManagementInformation:
return FlagStrings.CopyrightManagementInformation;
case Flag.D8Opcode:
return FlagStrings.D8Opcode;
case Flag.DisableBeep:
return FlagStrings.DisableBeep;
case Flag.ExtractMicroSoftCabFile:
return FlagStrings.ExtractMicroSoftCabFile;
case Flag.ForceUnitAccess:
return FlagStrings.ForceUnitAccess;
case Flag.MultiSession:
return FlagStrings.MultiSession;
case Flag.NoFixSubP:
return FlagStrings.NoFixSubP;
case Flag.NoFixSubQ:
return FlagStrings.NoFixSubQ;
case Flag.NoFixSubQLibCrypt:
return FlagStrings.NoFixSubQLibCrypt;
case Flag.NoFixSubRtoW:
return FlagStrings.NoFixSubRtoW;
case Flag.NoFixSubQSecuROM:
return FlagStrings.NoFixSubQSecuROM;
case Flag.NoSkipSS:
return FlagStrings.NoSkipSS;
case Flag.Raw:
return FlagStrings.Raw;
case Flag.Reverse:
return FlagStrings.Reverse;
case Flag.ScanAntiMod:
return FlagStrings.ScanAntiMod;
case Flag.ScanFileProtect:
return FlagStrings.ScanFileProtect;
case Flag.ScanSectorProtect:
return FlagStrings.ScanSectorProtect;
case Flag.SeventyFour:
return FlagStrings.SeventyFour;
case Flag.SkipSector:
return FlagStrings.SkipSector;
case Flag.SubchannelReadLevel:
return FlagStrings.SubchannelReadLevel;
case Flag.UseAnchorVolumeDescriptorPointer:
return FlagStrings.UseAnchorVolumeDescriptorPointer;
case Flag.VideoNow:
return FlagStrings.VideoNow;
case Flag.VideoNowColor:
return FlagStrings.VideoNowColor;
case Flag.VideoNowXP:
return FlagStrings.VideoNowXP;
case Flag.NONE:
default:
return "";
}
}
#endregion
#region Convert From String
/// <summary>
/// Get the Command enum value for a given string
/// </summary>
/// <param name="command">String value to convert</param>
/// <returns>Command represented by the string(s), if possible</returns>
public static Command StringToCommand(string command)
{
switch (command)
{
case CommandStrings.Audio:
return Command.Audio;
case CommandStrings.BluRay:
return Command.BluRay;
case CommandStrings.Close:
return Command.Close;
case CommandStrings.CompactDisc:
return Command.CompactDisc;
case CommandStrings.Data:
return Command.Data;
case CommandStrings.DigitalVideoDisc:
return Command.DigitalVideoDisc;
case CommandStrings.Disk:
return Command.Disk;
case CommandStrings.DriveSpeed:
return Command.DriveSpeed;
case CommandStrings.Eject:
return Command.Eject;
case CommandStrings.Floppy:
return Command.Floppy;
case CommandStrings.GDROM:
return Command.GDROM;
case CommandStrings.MDS:
return Command.MDS;
case CommandStrings.Merge:
return Command.Merge;
case CommandStrings.Reset:
return Command.Reset;
case CommandStrings.SACD:
return Command.SACD;
case CommandStrings.Start:
return Command.Start;
case CommandStrings.Stop:
return Command.Stop;
case CommandStrings.Sub:
return Command.Sub;
case CommandStrings.Swap:
return Command.Swap;
case CommandStrings.Tape:
return Command.Tape;
case CommandStrings.XBOX:
return Command.XBOX;
case CommandStrings.XBOXSwap:
return Command.XBOXSwap;
case CommandStrings.XGD2Swap:
return Command.XGD2Swap;
case CommandStrings.XGD3Swap:
return Command.XGD3Swap;
default:
return Command.NONE;
}
}
#endregion
}
}

View File

@@ -1,71 +0,0 @@
namespace DICUI.DiscImageCreator
{
/// <summary>
/// Supported DiscImageCreator commands
/// </summary>
public enum Command : int
{
NONE = 0,
Audio,
BluRay,
Close,
CompactDisc,
Data,
DigitalVideoDisc,
Disk,
DriveSpeed,
Eject,
Floppy,
GDROM,
MDS,
Merge,
Reset,
SACD,
Start,
Stop,
Sub,
Swap,
Tape,
XBOX,
XBOXSwap,
XGD2Swap,
XGD3Swap,
}
/// <summary>
/// Supported DiscImageCreator flags
/// </summary>
public enum Flag : int
{
NONE = 0,
AddOffset,
AMSF,
AtariJaguar,
BEOpcode,
C2Opcode,
CopyrightManagementInformation,
D8Opcode,
DisableBeep,
ExtractMicroSoftCabFile,
ForceUnitAccess,
MultiSession,
NoFixSubP,
NoFixSubQ,
NoFixSubQLibCrypt,
NoFixSubRtoW,
NoFixSubQSecuROM,
NoSkipSS,
Raw,
Reverse,
ScanAntiMod,
ScanFileProtect,
ScanSectorProtect,
SeventyFour,
SkipSector,
SubchannelReadLevel,
UseAnchorVolumeDescriptorPointer,
VideoNow,
VideoNowColor,
VideoNowXP,
}
}

View File

@@ -1,325 +0,0 @@
using System;
using System.IO;
using DICUI.Data;
using DICUI.Utilities;
using DICUI.Web;
namespace DICUI.UmdImageCreator
{
/// <summary>
/// Represents a generic set of UmdImageCreator parameters
/// </summary>
public class Parameters : BaseParameters
{
/// <summary>
/// Populate a Parameters object from a param string
/// </summary>
/// <param name="parameters">String possibly representing a set of parameters</param>
public Parameters(string parameters)
: base(parameters)
{
this.InternalProgram = InternalProgram.UmdImageCreator;
}
/// <summary>
/// Generate parameters based on a set of known inputs
/// </summary>
/// <param name="system">KnownSystem value to use</param>
/// <param name="type">MediaType value to use</param>
/// <param name="driveLetter">Drive letter to use</param>
/// <param name="filename">Filename to use</param>
/// <param name="driveSpeed">Drive speed to use</param>
/// <param name="paranoid">Enable paranoid mode (safer dumping)</param>
/// <param name="quietMode">Enable quiet mode (no beeps)</param>
/// <param name="retryCount">User-defined reread count</param>
public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, bool paranoid, bool quietMode, int retryCount)
: base(system, type, driveLetter, filename, driveSpeed, paranoid, quietMode, retryCount)
{
}
/// <summary>
/// Blindly generate a parameter string based on the inputs
/// </summary>
/// <returns>Correctly formatted parameter string, null on error</returns>
public override string GenerateParameters() => null;
/// <summary>
/// Get the input path from the implementation
/// </summary>
/// <returns>String representing the path, null on error</returns>
public override string InputPath() => null;
/// <summary>
/// Get the output path from the implementation
/// </summary>
/// <returns>String representing the path, null on error</returns>
public override string OutputPath() => null;
/// <summary>
/// Get the processing speed from the implementation
/// </summary>
/// <returns>int? representing the speed, null on error</returns>
public override int? GetSpeed() => null;
/// <summary>
/// Set the processing speed int the implementation
/// </summary>
/// <param name="speed">int? representing the speed</param>
public override void SetSpeed(int? speed) { }
/// <summary>
/// Get the MediaType from the current set of parameters
/// </summary>
/// <returns>MediaType value if successful, null on error</returns>
public override MediaType? GetMediaType() => null;
/// <summary>
/// Gets if the current command is considered a dumping command or not
/// </summary>
/// <returns>True if it's a dumping command, false otherwise</returns>
public override bool IsDumpingCommand() => true;
/// <summary>
/// Reset all special variables to have default values
/// </summary>
protected override void ResetValues() { }
/// <summary>
/// Set default parameters for a given system and media type
/// </summary>
/// <param name="system">KnownSystem value to use</param>
/// <param name="type">MediaType value to use</param>
/// <param name="driveLetter">Drive letter to use</param>
/// <param name="filename">Filename to use</param>
/// <param name="driveSpeed">Drive speed to use</param>
/// <param name="paranoid">Enable paranoid mode (safer dumping)</param>
/// <param name="retryCount">User-defined reread count</param>
protected override void SetDefaultParameters(
KnownSystem? system,
MediaType? type,
char driveLetter,
string filename,
int? driveSpeed,
bool paranoid,
int retryCount)
{
}
/// <summary>
/// Scan a possible parameter string and populate whatever possible
/// </summary>
/// <param name="parameters">String possibly representing parameters</param>
/// <returns></returns>
protected override bool ValidateAndSetParameters(string parameters) => true;
/// <summary>
/// Validate if all required output files exist
/// </summary>
/// <param name="basePath">Base filename and path to use for checking</param>
/// <param name="system">KnownSystem type representing the media</param>
/// <param name="type">MediaType type representing the media</param>
/// <param name="progress">Optional result progress callback</param>
/// <returns></returns>
public override bool CheckAllOutputFilesExist(string basePath, KnownSystem? system, MediaType? type, IProgress<Result> progress = null)
{
string missingFiles = string.Empty;
switch (type)
{
case MediaType.UMD:
if (!File.Exists($"{basePath}_disc.txt"))
missingFiles += $";{basePath}_disc.txt";
if (!File.Exists($"{basePath}_mainError.txt"))
missingFiles += $";{basePath}_mainError.txt";
if (!File.Exists($"{basePath}_mainInfo.txt"))
missingFiles += $";{basePath}_mainInfo.txt";
if (!File.Exists($"{basePath}_volDesc.txt"))
missingFiles += $";{basePath}_volDesc.txt";
break;
default:
// Non-dumping commands will usually produce no output, so this is irrelevant
return true;
}
// Use the missing files list as an indicator
if (string.IsNullOrEmpty(missingFiles))
{
return true;
}
else
{
progress?.Report(Result.Failure($"The following files were missing: {missingFiles.TrimStart(';')}"));
return false;
}
}
/// <summary>
/// Generate a SubmissionInfo for the output files
/// </summary>
/// <param name="info">Base submission info to fill in specifics for</param>
/// <param name="basePath">Base filename and path to use for checking</param>
/// <param name="system">KnownSystem type representing the media</param>
/// <param name="type">MediaType type representing the media</param>
/// <param name="drive">Drive representing the disc to get information from</param>
/// <returns></returns>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, KnownSystem? system, MediaType? type, Drive drive)
{
// Fill in the hash data
info.TracksAndWriteOffsets.ClrMameProData = GetDatfile(basePath + ".dat");
// Extract info based generically on MediaType
switch (type)
{
case MediaType.UMD:
info.Extras.PVD = GetPVD(basePath + "_mainInfo.txt") ?? "";
if (GetUMDAuxInfo(basePath + "_disc.txt", out string title, out DiscCategory? umdcat, out string umdversion, out string umdlayer, out long umdsize))
{
info.CommonDiscInfo.Title = title ?? "";
info.CommonDiscInfo.Category = umdcat ?? DiscCategory.Games;
info.VersionAndEditions.Version = umdversion ?? "";
info.SizeAndChecksums.Size = umdsize;
if (!string.IsNullOrWhiteSpace(umdlayer))
info.SizeAndChecksums.Layerbreak = Int64.Parse(umdlayer ?? "-1");
}
break;
}
}
#region Information Extraction Methods
/// <summary>
/// Get the proper datfile from the input file, if possible
/// </summary>
/// <param name="dat">.dat file location</param>
/// <returns>Relevant pieces of the datfile, null on error</returns>
private static string GetDatfile(string dat)
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(dat))
return null;
using (StreamReader sr = File.OpenText(dat))
{
try
{
// Make sure this file is a .dat
if (sr.ReadLine() != "<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
return null;
if (sr.ReadLine() != "<!DOCTYPE datafile PUBLIC \"-//Logiqx//DTD ROM Management Datafile//EN\" \"http://www.logiqx.com/Dats/datafile.dtd\">")
return null;
// Fast forward to the rom lines
while (!sr.ReadLine().TrimStart().StartsWith("<game")) ;
sr.ReadLine(); // <category>Games</category>
sr.ReadLine(); // <description>Plextor</description>
// Now that we're at the relevant entries, read each line in and concatenate
string pvd = "", line = sr.ReadLine().Trim();
while (line.StartsWith("<rom"))
{
pvd += line + "\n";
line = sr.ReadLine().Trim();
}
return pvd.TrimEnd('\n');
}
catch
{
// We don't care what the exception is right now
return null;
}
}
}
/// <summary>
/// Get the PVD from the input file, if possible
/// </summary>
/// <param name="mainInfo">_mainInfo.txt file location</param>
/// <returns>Newline-deliminated PVD if possible, null on error</returns>
private static string GetPVD(string mainInfo)
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(mainInfo))
return null;
using (StreamReader sr = File.OpenText(mainInfo))
{
try
{
// Make sure we're in the right sector
while (!sr.ReadLine().StartsWith("========== LBA[000016, 0x00010]: Main Channel ==========")) ;
// Fast forward to the PVD
while (!sr.ReadLine().StartsWith("0310")) ;
// Now that we're at the PVD, read each line in and concatenate
string pvd = "";
for (int i = 0; i < 6; i++)
pvd += sr.ReadLine() + "\n"; // 320-370
return pvd;
}
catch
{
// We don't care what the exception is right now
return null;
}
}
}
/// <summary>
/// Get the UMD auxiliary info from the outputted files, if possible
/// </summary>
/// <param name="disc">_disc.txt file location</param>
/// <returns>True on successful extraction of info, false otherwise</returns>
private static bool GetUMDAuxInfo(string disc, out string title, out DiscCategory? umdcat, out string umdversion, out string umdlayer, out long umdsize)
{
title = null; umdcat = null; umdversion = null; umdlayer = null; umdsize = -1;
// If the file doesn't exist, we can't get info from it
if (!File.Exists(disc))
return false;
using (StreamReader sr = File.OpenText(disc))
{
try
{
// Loop through everything to get the first instance of each required field
string line = string.Empty;
while (!sr.EndOfStream)
{
line = sr.ReadLine().Trim();
if (line.StartsWith("TITLE") && title == null)
title = line.Substring("TITLE: ".Length);
else if (line.StartsWith("DISC_VERSION") && umdversion == null)
umdversion = line.Split(' ')[1];
else if (line.StartsWith("pspUmdTypes"))
umdcat = GetUMDCategory(line.Split(' ')[1]);
else if (line.StartsWith("L0 length"))
umdlayer = line.Split(' ')[2];
else if (line.StartsWith("FileSize:"))
umdsize = Int64.Parse(line.Split(' ')[1]);
}
// If the L0 length is the size of the full disc, there's no layerbreak
if (Int64.Parse(umdlayer) * 2048 == umdsize)
umdlayer = null;
return true;
}
catch
{
// We don't care what the exception is right now
return false;
}
}
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,65 +0,0 @@
using System.IO;
using DICUI.Data;
namespace DICUI.Utilities
{
/// <summary>
/// Represents information for a single drive
/// </summary>
public class Drive
{
/// <summary>
/// Represents drive type
/// </summary>
public InternalDriveType? InternalDriveType { get; set; }
/// <summary>
/// DriveInfo object representing the drive, if possible
/// </summary>
public DriveInfo DriveInfo { get; private set; }
/// <summary>
/// Windows drive letter
/// </summary>
public char Letter { get { return DriveInfo?.Name[0] ?? '\0'; } }
/// <summary>
/// Media label as read by Windows
/// </summary>
public string VolumeLabel
{
get
{
string volumeLabel = Template.DiscNotDetected;
if (DriveInfo.IsReady)
{
if (string.IsNullOrWhiteSpace(DriveInfo.VolumeLabel))
volumeLabel = "track";
else
volumeLabel = DriveInfo.VolumeLabel;
}
foreach (char c in Path.GetInvalidFileNameChars())
volumeLabel = volumeLabel.Replace(c, '_');
return volumeLabel;
}
}
/// <summary>
/// Drive partition format
/// </summary>
public string DriveFormat { get { return DriveInfo.DriveFormat; } }
/// <summary>
/// Represents if Windows has marked the drive as active
/// </summary>
public bool MarkedActive { get { return DriveInfo.IsReady; } }
public Drive(InternalDriveType? driveType, DriveInfo driveInfo)
{
this.InternalDriveType = driveType;
this.DriveInfo = driveInfo;
}
}
}

View File

@@ -1,57 +0,0 @@
using DICUI.Data;
namespace DICUI.Utilities
{
public static class Extensions
{
public static bool DoesSupportDriveSpeed(this MediaType? type)
{
switch (type)
{
case MediaType.CDROM:
case MediaType.DVD:
case MediaType.GDROM:
case MediaType.HDDVD:
case MediaType.BluRay:
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
return true;
default:
return false;
}
}
public static KnownSystemCategory Category(this KnownSystem? system)
{
if (system < KnownSystem.MarkerDiscBasedConsoleEnd)
return KnownSystemCategory.DiscBasedConsole;
/*
else if (system < KnownSystem.MarkerOtherConsoleEnd)
return KnownSystemCategory.OtherConsole;
*/
else if (system < KnownSystem.MarkerComputerEnd)
return KnownSystemCategory.Computer;
else if (system < KnownSystem.MarkerArcadeEnd)
return KnownSystemCategory.Arcade;
else if (system < KnownSystem.MarkerOtherEnd)
return KnownSystemCategory.Other;
else
return KnownSystemCategory.Custom;
}
public static bool IsMarker(this KnownSystem? system)
{
switch (system)
{
case KnownSystem.MarkerArcadeEnd:
case KnownSystem.MarkerComputerEnd:
case KnownSystem.MarkerDiscBasedConsoleEnd:
// case KnownSystem.MarkerOtherConsoleEnd:
case KnownSystem.MarkerOtherEnd:
return true;
default:
return false;
}
}
}
}

View File

@@ -1,48 +0,0 @@
using System;
using System.Reflection;
using DICUI.Web;
namespace DICUI.Utilities
{
public class Tools
{
/// <summary>
/// Check for a new DICUI version
/// </summary>
/// <returns>
/// Bool representing if the values are different.
/// String representing the message to display the the user.
/// String representing the new release URL.
/// </returns>
public static (bool different, string message, string url) CheckForNewVersion()
{
// Get current assembly version
string version = GetCurrentVersion();
// Get the latest tag from GitHub
using (var client = new RedumpWebClient())
{
(string tag, string url) = client.GetRemoteVersionAndUrl();
bool different = version != tag;
string message = $"Local version: {version}"
+ $"{Environment.NewLine}Remote version: {tag}"
+ (different
? $"{Environment.NewLine}The update URL has been added copied to your clipboard"
: $"{Environment.NewLine}You have the newest version!");
return (different, message, url);
}
}
/// <summary>
/// Get the current assembly version formatted as a string
/// </summary>
private static string GetCurrentVersion()
{
var assemblyVersion = Assembly.GetEntryAssembly().GetName().Version;
return $"{assemblyVersion.Major}.{assemblyVersion.Minor}" + (assemblyVersion.Build != 0 ? $".{assemblyVersion.Build}" : string.Empty);
}
}
}

View File

@@ -1,244 +0,0 @@
namespace DICUI.Web
{
/// <summary>
/// List of all disc categories
/// </summary>
public enum DiscCategory
{
Games = 1,
Demos = 2,
Video = 3,
Audio = 4,
Multimedia = 5,
Applications = 6,
Coverdiscs = 7,
Educational = 8,
BonusDiscs = 9,
Preproduction = 10,
AddOns = 11,
}
/// <summary>
/// Dump status
/// </summary>
public enum DumpStatus
{
BadDumpRed = 2,
PossibleBadDumpYellow = 3,
OriginalMediaBlue = 4,
TwoOrMoreDumpsGreen = 5,
}
/// <summary>
/// List of all disc langauges
/// </summary>
public enum Language
{
Afrikaans,
Arabic,
Basque,
Bulgarian,
Catalan,
Chinese,
Croatian,
Czech,
Danish,
Dutch,
English,
Finnish,
French,
Gaelic,
German,
Greek,
Hebrew,
Hindi,
Hungarian,
Italian,
Japanese,
Korean,
Norwegian,
Polish,
Portuguese,
Punjabi,
Romanian,
Russian,
Slovak,
Slovenian,
Spanish,
Swedish,
Tamil,
Thai,
Turkish,
Ukrainian,
}
/// <summary>
/// All possible language selections
/// </summary>
public enum LanguageSelection
{
BiosSettings,
LanguageSelector,
OptionsMenu,
}
/// <summary>
/// List of all known Redump systems
/// </summary>
public enum RedumpSystem
{
// Special BIOS sets
MicrosoftXboxBIOS,
NintendoGameCubeBIOS,
SonyPlayStationBIOS,
SonyPlayStation2BIOS,
// Regular systems
AcornArchimedes,
AppleMacintosh,
AtariJaguarCDInteractiveMultimediaSystem,
AudioCD,
BandaiPippin,
BandaiPlaydiaQuickInteractiveSystem,
BDVideo,
CommodoreAmigaCD,
CommodoreAmigaCD32,
CommodoreAmigaCDTV,
DVDVideo,
EnhancedCD,
FujitsuFMTownsseries,
funworldPhotoPlay,
HasbroVideoNow,
HasbroVideoNowColor,
HasbroVideoNowJr,
HasbroVideoNowXP,
IBMPCcompatible,
IncredibleTechnologiesEagle,
KonamieAmusement,
KonamiFireBeat,
KonamiM2,
KonamiSystem573,
KonamiSystemGV,
KonamiTwinkle,
MattelFisherPriceiXL,
MattelHyperScan,
MemorexVisualInformationSystem,
MicrosoftXbox,
MicrosoftXbox360,
MicrosoftXboxOne,
NamcoSegaNintendoTriforce,
NamcoSystem12,
NamcoSystem246,
NavisoftNaviken21,
NECPCEngineCDTurboGrafxCD,
NECPC88series,
NECPC98series,
NECPCFXPCFXGA,
NintendoGameCube,
NintendoWii,
NintendoWiiU,
PalmOS,
Panasonic3DOInteractiveMultiplayer,
PanasonicM2,
PhilipsCDi,
PhilipsCDiDigitalVideo,
PhotoCD,
PlayStationGameSharkUpdates,
SegaChihiro,
SegaDreamcast,
SegaLindbergh,
SegaMegaCDSegaCD,
SegaNaomi,
SegaNaomi2,
SegaPrologue21,
SegaRingEdge,
SegaRingEdge2,
SegaSaturn,
SegaTitanVideo,
SharpX68000,
SNKNeoGeoCD,
SonyPlayStation,
SonyPlayStation2,
SonyPlayStation3,
SonyPlayStation4,
SonyPlayStationPortable,
TABAustriaQuizard,
TaoiKTV,
TomyKissSite,
VideoCD,
VMLabsNUON,
VTechVFlashVSmilePro,
ZAPiTGamesGameWaveFamilyEntertainmentSystem,
}
/// <summary>
/// List of all known Redump regions
/// </summary>
public enum Region
{
Argentina,
Asia,
AsiaEurope,
AsiaUSA,
Australia,
Austria,
AustriaSwitzerland,
Belgium,
BelgiumNetherlands,
Brazil,
Canada,
China,
Croatia,
Czech,
Denmark,
Europe,
EuropeAsia,
EuropeAustralia,
Finland,
France,
FranceSpain,
Germany,
GreaterChina,
Greece,
Hungary,
India,
Ireland,
Israel,
Italy,
Japan,
JapanAsia,
JapanEurope,
JapanKorea,
JapanUSA,
Korea,
LatinAmerica,
Netherlands,
Norway,
Poland,
Portugal,
Russia,
Scandinavia,
Singapore,
Slovakia,
SouthAfrica,
Spain,
SpainPortugal,
Sweden,
Switzerland,
Taiwan,
Thailand,
Turkey,
UnitedArabEmirates,
UK,
UKAustralia,
Ukraine,
USA,
USAAsia,
USABrazil,
USACanada,
USAEurope,
USAGermany,
USAJapan,
World,
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,129 +0,0 @@
using System;
using DICUI.Data;
using DICUI.Utilities;
using Xunit;
namespace DICUI.Test.Utilities
{
public class ConvertersTest
{
[Theory]
[InlineData(DiscImageCreator.Command.Audio, MediaType.CDROM)]
[InlineData(DiscImageCreator.Command.BluRay, MediaType.BluRay)]
[InlineData(DiscImageCreator.Command.Close, null)]
[InlineData(DiscImageCreator.Command.CompactDisc, MediaType.CDROM)]
[InlineData(DiscImageCreator.Command.Data, MediaType.CDROM)]
[InlineData(DiscImageCreator.Command.DigitalVideoDisc, MediaType.DVD)]
[InlineData(DiscImageCreator.Command.Eject, null)]
[InlineData(DiscImageCreator.Command.Floppy, MediaType.FloppyDisk)]
[InlineData(DiscImageCreator.Command.GDROM, MediaType.GDROM)]
[InlineData(DiscImageCreator.Command.MDS, null)]
[InlineData(DiscImageCreator.Command.Reset, null)]
[InlineData(DiscImageCreator.Command.SACD, MediaType.CDROM)]
[InlineData(DiscImageCreator.Command.Start, null)]
[InlineData(DiscImageCreator.Command.Stop, null)]
[InlineData(DiscImageCreator.Command.Sub, null)]
[InlineData(DiscImageCreator.Command.Swap, MediaType.GDROM)]
[InlineData(DiscImageCreator.Command.XBOX, MediaType.DVD)]
public void BaseCommandToMediaTypeTest(DiscImageCreator.Command command, MediaType? expected)
{
MediaType? actual = DiscImageCreator.Converters.ToMediaType(command);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(DiscImageCreator.Command.Audio, KnownSystem.AudioCD)]
[InlineData(DiscImageCreator.Command.BluRay, KnownSystem.SonyPlayStation3)]
[InlineData(DiscImageCreator.Command.Close, null)]
[InlineData(DiscImageCreator.Command.CompactDisc, KnownSystem.IBMPCCompatible)]
[InlineData(DiscImageCreator.Command.Data, KnownSystem.IBMPCCompatible)]
[InlineData(DiscImageCreator.Command.DigitalVideoDisc, KnownSystem.IBMPCCompatible)]
[InlineData(DiscImageCreator.Command.Eject, null)]
[InlineData(DiscImageCreator.Command.Floppy, KnownSystem.IBMPCCompatible)]
[InlineData(DiscImageCreator.Command.GDROM, KnownSystem.SegaDreamcast)]
[InlineData(DiscImageCreator.Command.MDS, null)]
[InlineData(DiscImageCreator.Command.Reset, null)]
[InlineData(DiscImageCreator.Command.SACD, KnownSystem.SuperAudioCD)]
[InlineData(DiscImageCreator.Command.Start, null)]
[InlineData(DiscImageCreator.Command.Stop, null)]
[InlineData(DiscImageCreator.Command.Sub, null)]
[InlineData(DiscImageCreator.Command.Swap, KnownSystem.SegaDreamcast)]
[InlineData(DiscImageCreator.Command.XBOX, KnownSystem.MicrosoftXBOX)]
public void BaseCommandToKnownSystemTest(DiscImageCreator.Command command, KnownSystem? expected)
{
KnownSystem? actual = DiscImageCreator.Converters.ToKnownSystem(command);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(MediaType.CDROM, ".bin")]
[InlineData(MediaType.DVD, ".iso")]
[InlineData(MediaType.LaserDisc, ".raw")]
[InlineData(MediaType.NintendoWiiUOpticalDisc, ".wud")]
[InlineData(MediaType.FloppyDisk, ".img")]
[InlineData(MediaType.Cassette, ".wav")]
[InlineData(MediaType.NONE, null)]
public void MediaTypeToExtensionTest(MediaType? mediaType, string expected)
{
string actual = DiscImageCreator.Converters.Extension(mediaType);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(MediaType.CDROM, "CD-ROM")]
[InlineData(MediaType.LaserDisc, "LD-ROM / LV-ROM")]
[InlineData(MediaType.NONE, "Unknown")]
public void MediaTypeToStringTest(MediaType? mediaType, string expected)
{
string actual = Converters.LongName(mediaType);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(KnownSystem.MicrosoftXBOX, "Microsoft XBOX")]
[InlineData(KnownSystem.NECPC88, "NEC PC-88")]
[InlineData(KnownSystem.KonamiPython, "Konami Python")]
[InlineData(KnownSystem.HDDVDVideo, "HD-DVD-Video")]
[InlineData(KnownSystem.NONE, "Unknown")]
public void KnownSystemToStringTest(KnownSystem? knownSystem, string expected)
{
string actual = Converters.LongName(knownSystem);
Assert.Equal(expected, actual);
}
[Fact]
public void KnownSystemHasValidCategory()
{
var values = Validators.CreateListOfSystems();
KnownSystem[] markers = { KnownSystem.MarkerArcadeEnd, KnownSystem.MarkerDiscBasedConsoleEnd, /* KnownSystem.MarkerOtherConsoleEnd, */ KnownSystem.MarkerComputerEnd, KnownSystem.MarkerOtherEnd };
values.ForEach(system => {
if (system == KnownSystem.NONE)
return;
// we check that the category is the first category value higher than the system
KnownSystemCategory category = ((KnownSystem?)system).Category();
KnownSystem marker = KnownSystem.NONE;
switch (category)
{
case KnownSystemCategory.Arcade: marker = KnownSystem.MarkerArcadeEnd; break;
case KnownSystemCategory.DiscBasedConsole: marker = KnownSystem.MarkerDiscBasedConsoleEnd; break;
/* case KnownSystemCategory.OtherConsole: marker = KnownSystem.MarkerOtherConsoleEnd; break; */
case KnownSystemCategory.Computer: marker = KnownSystem.MarkerComputerEnd; break;
case KnownSystemCategory.Other: marker = KnownSystem.MarkerOtherEnd; break;
}
Assert.NotEqual(KnownSystem.NONE, marker);
Assert.True(marker > system);
Array.ForEach(markers, mmarker =>
{
// a marker can be the same of the found one, or one of a category before or a category after but never in the middle between
// the system and the mapped category
Assert.True(mmarker == marker || mmarker < system || mmarker > marker);
});
});
}
}
}

View File

@@ -1,31 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="AaruPath" value="Programs\Aaru\Aaru.exe"/>
<add key="CreatorPath" value="Programs\Creator\DiscImageCreator.exe"/>
<add key="DDPath" value="Programs\DD\dd.exe"/>
<add key="SubDumpPath" value="Programs\Subdump\subdump.exe"/>
<add key="DefaultOutputPath" value="ISO"/>
<add key="InternalProgram" value="DiscImageCreator"/>
<add key="PreferredDumpSpeedCD" value="48"/>
<add key="PreferredDumpSpeedDVD" value="24"/>
<add key="PreferredDumpSpeedBD" value="16"/>
<add key="QuietMode" value="false"/>
<add key="ParanoidMode" value="false"/>
<add key="ScanForProtection" value="true"/>
<add key="SkipMediaTypeDetection" value="false"/>
<add key="SkipSystemDetection" value="false"/>
<add key="RereadAmountForC2" value="20"/>
<add key="VerboseLogging" value="true"/>
<add key="OpenLogWindowAtStartup" value="true"/>
<add key="AddPlaceholders" value="true"/>
<add key="PromptForDiscInformation" value="true"/>
<add key="IgnoreFixedDrives" value="false"/>
<add key="ResetDriveAfterDump" value="false"/>
<add key="Username" value=""/>
<add key="Password" value=""/>
</appSettings>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/></startup></configuration>

View File

@@ -1,9 +0,0 @@
<Application x:Class="DICUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DICUI"
StartupUri="Windows\MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>

View File

@@ -1,29 +0,0 @@
using DICUI.Utilities;
using DICUI.Web;
namespace DICUI
{
/// <summary>
/// Represents a single item in the Category combo box
/// </summary>
public class CategoryComboBoxItem
{
private object data;
public CategoryComboBoxItem(DiscCategory? category) => data = category;
public static implicit operator DiscCategory? (CategoryComboBoxItem item) => item.data as DiscCategory?;
public string Name
{
get { return (data as DiscCategory?).LongName(); }
}
public bool IsChecked { get; set; }
public DiscCategory? Value
{
get { return data as DiscCategory?; }
}
}
}

View File

@@ -1,35 +0,0 @@
using System.Windows.Media;
using DICUI.Data;
using DICUI.Utilities;
namespace DICUI
{
/// <summary>
/// Represents a single item in the System combo box
/// </summary>
public class KnownSystemComboBoxItem
{
private object data;
public KnownSystemComboBoxItem(KnownSystem? system) => data = system;
public KnownSystemComboBoxItem(KnownSystemCategory? category) => data = category;
public Brush Foreground { get => IsHeader() ? Brushes.Gray : Brushes.Black; }
public bool IsHeader() => data is KnownSystemCategory?;
public bool IsSystem() => data is KnownSystem?;
public static implicit operator KnownSystem? (KnownSystemComboBoxItem item) => item.data as KnownSystem?;
public string Name
{
get
{
if (IsHeader())
return "---------- " + (data as KnownSystemCategory?).LongName() + " ----------";
else
return (data as KnownSystem?).LongName();
}
}
}
}

View File

@@ -1,29 +0,0 @@
using DICUI.Utilities;
using DICUI.Web;
namespace DICUI
{
/// <summary>
/// Represents a single item in the Language combo box
/// </summary>
public class LanguageComboBoxItem
{
private object data;
public LanguageComboBoxItem(Language? region) => data = region;
public static implicit operator Language? (LanguageComboBoxItem item) => item.data as Language?;
public string Name
{
get { return (data as Language?).LongName(); }
}
public bool IsChecked { get; set; }
public Language? Value
{
get { return data as Language?; }
}
}
}

View File

@@ -1,20 +0,0 @@
using DICUI.Data;
using DICUI.Utilities;
namespace DICUI
{
/// <summary>
/// Represents a single item in the MediaType combo box
/// </summary>
public class MediaTypeComboBoxItem
{
private MediaType? data;
public MediaTypeComboBoxItem(MediaType? mediaType) => data = mediaType;
public static implicit operator MediaType? (MediaTypeComboBoxItem item) => item.data;
public string Name { get { return data.LongName(); }
}
}
}

View File

@@ -1,30 +0,0 @@
using DICUI.Utilities;
using DICUI.Web;
namespace DICUI
{
/// <summary>
/// Represents a single item in the Region combo box
/// </summary>
public class RegionComboBoxItem
{
private object data;
public RegionComboBoxItem(Region? region) => data = region;
public static implicit operator Region? (RegionComboBoxItem item) => item.data as Region?;
public string Name
{
get
{
return (data as Region?).LongName();
}
}
public Region? Value
{
get { return data as Region?; }
}
}
}

View File

@@ -1,56 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Media;
using DICUI.Data;
namespace DICUI
{
/// <summary>
/// Variables for UI elements
/// </summary>
public static class Constants
{
public const string StartDumping = "Start Dumping";
public const string StopDumping = "Stop Dumping";
public const int LogWindowMarginFromMainWindow = 10;
// Private lists of known drive speed ranges
private static IReadOnlyList<int> cd { get; } = new List<int> { 1, 2, 3, 4, 6, 8, 12, 16, 20, 24, 32, 40, 44, 48, 52, 56, 72 };
private static IReadOnlyList<int> dvd { get; } = cd.Where(s => s <= 24).ToList();
private static IReadOnlyList<int> bd { get; } = cd.Where(s => s <= 16).ToList();
private static IReadOnlyList<int> unknown { get; } = cd; // TODO: All or {1}? Maybe null?
/// <summary>
/// Get list of all drive speeds for a given MediaType
/// </summary>
/// <param name="type">MediaType? that represents the current item</param>
/// <returns>Read-only list of drive speeds</returns>
public static IReadOnlyList<int> GetSpeedsForMediaType(MediaType? type)
{
switch (type)
{
case MediaType.CDROM:
case MediaType.GDROM:
return cd;
case MediaType.DVD:
case MediaType.HDDVD:
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
return dvd;
case MediaType.BluRay:
return bd;
default:
return unknown;
}
}
// Create collections for UI based on known drive speeds
public static DoubleCollection SpeedsForCDAsCollection { get; } = GetDoubleCollectionFromIntList(cd);
public static DoubleCollection SpeedsForDVDAsCollection { get; } = GetDoubleCollectionFromIntList(dvd);
public static DoubleCollection SpeedsForBDAsCollection { get; } = GetDoubleCollectionFromIntList(bd);
private static DoubleCollection GetDoubleCollectionFromIntList(IReadOnlyList<int> list)
=> new DoubleCollection(list.Select(i => Convert.ToDouble(i)).ToList());
}
}

View File

@@ -1,38 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFrameworks>net472;net48;netcoreapp3.1</TargetFrameworks>
<OutputType>WinExe</OutputType>
<UseWindowsForms>true</UseWindowsForms>
<UseWPF>true</UseWPF>
<ApplicationIcon>Icon.ico</ApplicationIcon>
<Prefer32Bit>true</Prefer32Bit>
<Title>DICUI</Title>
<AssemblyName>DICUI</AssemblyName>
<Description>Frontend for various dumping programs</Description>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2020</Copyright>
<RepositoryUrl>https://github.com/SabreTools/DICUI</RepositoryUrl>
<Version>1.17.0</Version>
<AssemblyVersion>1.17.0</AssemblyVersion>
<FileVersion>1.17.0</FileVersion>
<IncludeSource>true</IncludeSource>
<IncludeSymbols>true</IncludeSymbols>
</PropertyGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.7.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DICUI.Library\DICUI.Library.csproj">
<Project>{51ab0928-13f9-44bf-a407-b6957a43a056}</Project>
<Name>DICUI.Library</Name>
</ProjectReference>
</ItemGroup>
</Project>

View File

@@ -1,32 +0,0 @@
using System;
using System.Globalization;
using System.Windows.Data;
using DICUI.Data;
using DICUI.Utilities;
namespace DICUI
{
/// <summary>
/// Used to provide a converter to XAML files to render comboboxes with enum values
/// </summary>
public class EnumDescriptionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// Common
if (value is MediaType?)
return ((MediaType?)value).LongName();
else if (value is KnownSystem?)
return ((KnownSystem?)value).LongName();
// Default
else
return "";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return string.Empty;
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

View File

@@ -1,122 +0,0 @@
using System.Collections.Generic;
using System.Configuration;
using DICUI.Data;
namespace DICUI
{
public class UIOptions
{
// TODO: Is there any way that this can be made private?
public Options Options { get; set; }
#region Passthrough readonly values
// TODO: Can any of these be removed?
public string DefaultOutputPath { get { return Options.DefaultOutputPath; } }
public bool IgnoreFixedDrives { get { return Options.IgnoreFixedDrives; } }
public bool ResetDriveAfterDump { get { return Options.ResetDriveAfterDump; } }
public bool SkipMediaTypeDetection { get { return Options.SkipMediaTypeDetection; } }
public bool SkipSystemDetection { get { return Options.SkipSystemDetection; } }
public bool OpenLogWindowAtStartup { get { return Options.OpenLogWindowAtStartup; } }
#endregion
/// <summary>
/// Default constructor
/// </summary>
public UIOptions()
{
Load();
}
/// <summary>
/// Save a configuration from internal Options
/// </summary>
public void Save()
{
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
// Loop through all settings in Options and save them, overwriting existing settings
foreach (var kvp in Options)
{
configFile.AppSettings.Settings.Remove(kvp.Key);
configFile.AppSettings.Settings.Add(kvp.Key, kvp.Value);
}
configFile.Save(ConfigurationSaveMode.Modified);
}
/// <summary>
/// Load a configuration into internal Options
/// </summary>
private void Load()
{
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var settings = ConvertToDictionary(configFile);
Options = new Options(settings);
}
/// <summary>
/// Get a setting value from the base Options
/// </summary>
/// <param name="key">Key to retrieve the value for</param>
/// <returns>String value if possible, null otherwise</returns>
public string Get(string key)
{
return Options[key];
}
/// <summary>
/// Set a setting value in the base Options
/// </summary>
/// <param name="key">Key to set the value for</param>
/// <param name="value">Value to set</param>
public void Set(string key, string value)
{
Options[key] = value;
}
/// <summary>
/// Get the preferred dumping speed given a media type
/// </summary>
/// <param name="type">MediaType representing the current selection</param>
/// <returns>Int value representing the dump speed</returns>
public int GetPreferredDumpSpeedForMediaType(MediaType? type)
{
switch (type)
{
case MediaType.CDROM:
case MediaType.GDROM:
return this.Options.PreferredDumpSpeedCD;
case MediaType.DVD:
case MediaType.HDDVD:
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
return this.Options.PreferredDumpSpeedDVD;
case MediaType.BluRay:
return this.Options.PreferredDumpSpeedBD;
default:
return this.Options.PreferredDumpSpeedCD;
}
}
/// <summary>
/// Convert the configuration app settings to a dictionary
/// </summary>
/// <param name="configFile">Configuration to load from</param>
/// <returns>Dictionary with all values from app settings</returns>
private Dictionary<string, string> ConvertToDictionary(Configuration configFile)
{
var settings = configFile.AppSettings.Settings;
var dict = new Dictionary<string, string>();
foreach (string key in settings.AllKeys)
{
dict[key] = settings[key]?.Value ?? string.Empty;
}
return dict;
}
}
}

View File

@@ -1,231 +0,0 @@
using System;
using System.Windows.Media;
using DICUI.Windows;
namespace DICUI
{
public class OptionsViewModel
{
private readonly UIOptions _uiOptions;
#region Internal Program
public string AaruPath
{
get { return _uiOptions.Options.AaruPath; }
set { _uiOptions.Options.AaruPath = value; }
}
public string CreatorPath
{
get { return _uiOptions.Options.CreatorPath; }
set { _uiOptions.Options.CreatorPath = value; }
}
public string DDPath
{
get { return _uiOptions.Options.DDPath; }
set { _uiOptions.Options.DDPath = value; }
}
public string InternalProgram
{
get { return _uiOptions.Options.InternalProgram; }
set { _uiOptions.Options.InternalProgram = value; }
}
#endregion
#region Extra Paths
public string DefaultOutputPath
{
get { return _uiOptions.Options.DefaultOutputPath; }
set { _uiOptions.Options.DefaultOutputPath = value; }
}
public string SubDumpPath
{
get { return _uiOptions.Options.SubDumpPath; }
set { _uiOptions.Options.SubDumpPath = value; }
}
#endregion
#region Dumping Speeds
public int PreferredDumpSpeedCD
{
get { return _uiOptions.Options.PreferredDumpSpeedCD; }
set { _uiOptions.Options.PreferredDumpSpeedCD = value; }
}
public int PreferredDumpSpeedDVD
{
get { return _uiOptions.Options.PreferredDumpSpeedDVD; }
set { _uiOptions.Options.PreferredDumpSpeedDVD = value; }
}
public int PreferredDumpSpeedBD
{
get { return _uiOptions.Options.PreferredDumpSpeedBD; }
set { _uiOptions.Options.PreferredDumpSpeedBD = value; }
}
#endregion
#region Extra Dumping Options
public bool QuietMode
{
get { return _uiOptions.Options.QuietMode; }
set { _uiOptions.Options.QuietMode = value; }
}
public bool ParanoidMode
{
get { return _uiOptions.Options.ParanoidMode; }
set { _uiOptions.Options.ParanoidMode = value; }
}
public bool ScanForProtection
{
get { return _uiOptions.Options.ScanForProtection; }
set { _uiOptions.Options.ScanForProtection = value; }
}
public string RereadAmountForC2
{
get { return Convert.ToString(_uiOptions.Options.RereadAmountForC2); }
set
{
if (Int32.TryParse(value, out int result))
_uiOptions.Options.RereadAmountForC2 = result;
}
}
public bool AddPlaceholders
{
get { return _uiOptions.Options.AddPlaceholders; }
set { _uiOptions.Options.AddPlaceholders = value; }
}
public bool PromptForDiscInformation
{
get { return _uiOptions.Options.PromptForDiscInformation; }
set { _uiOptions.Options.PromptForDiscInformation = value; }
}
public bool IgnoreFixedDrives
{
get { return _uiOptions.Options.IgnoreFixedDrives; }
set { _uiOptions.Options.IgnoreFixedDrives = value; }
}
public bool ResetDriveAfterDump
{
get { return _uiOptions.Options.ResetDriveAfterDump; }
set { _uiOptions.Options.ResetDriveAfterDump = value; }
}
#endregion
#region Skip Options
public bool SkipMediaTypeDetection
{
get { return _uiOptions.Options.SkipMediaTypeDetection; }
set { _uiOptions.Options.SkipMediaTypeDetection = value; }
}
public bool SkipSystemDetection
{
get { return _uiOptions.Options.SkipSystemDetection; }
set { _uiOptions.Options.SkipSystemDetection = value; }
}
#endregion
#region Logging Options
public bool VerboseLogging
{
get { return _uiOptions.Options.VerboseLogging; }
set
{
_uiOptions.Options.VerboseLogging = value;
_uiOptions.Save(); // TODO: Why does this save here?
}
}
public bool OpenLogWindowAtStartup
{
get { return _uiOptions.Options.OpenLogWindowAtStartup; }
set
{
_uiOptions.Options.OpenLogWindowAtStartup = value;
_uiOptions.Save(); // TODO: Why does this save here?
}
}
#endregion
#region Redump Login Information
public string Username
{
get { return _uiOptions.Options.Username; }
set { _uiOptions.Options.Username = value; }
}
public string Password
{
get { return _uiOptions.Options.Password; }
set { _uiOptions.Options.Password = value; }
}
#endregion
public OptionsViewModel(UIOptions uiOptions)
{
this._uiOptions = uiOptions;
}
}
public class LoggerViewModel
{
private LogWindow _logWindow;
public void SetWindow(LogWindow logWindow) => _logWindow = logWindow;
public bool WindowVisible
{
get => _logWindow != null ? _logWindow.IsVisible : false;
set
{
if (value)
{
_logWindow.AdjustPositionToMainWindow();
_logWindow.Show();
}
else
_logWindow.Hide();
}
}
public void VerboseLog(string text)
{
if (ViewModels.OptionsViewModel.VerboseLogging)
_logWindow.AppendToTextBox(text, Brushes.Yellow);
}
public void VerboseLog(string format, params object[] args) => VerboseLog(string.Format(format, args));
public void VerboseLogLn(string format, params object[] args) => VerboseLog(string.Format(format, args) + "\n");
}
public static class ViewModels
{
public static OptionsViewModel OptionsViewModel { get; set; }
public static LoggerViewModel LoggerViewModel { get; set; } = new LoggerViewModel();
}
}

View File

@@ -1,169 +0,0 @@
<Window x:Class="DICUI.Windows.DiscInformationWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DICUI"
mc:Ignorable="d"
Title="Disc Information" Height="733" Width="515.132" ResizeMode="NoResize"
Closed="OnClosed">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="585"/>
<RowDefinition Height="80"/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<GroupBox Grid.Row="0" Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Common Disc Information">
<Grid Margin="10,15,10,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Title" />
<TextBox x:Name="TitleTextBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<Label Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Foreign Title (Non-Latin)" />
<TextBox x:Name="ForeignTitleTextBox" Grid.Row="1" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<Label Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Disc Number / Letter" />
<TextBox x:Name="DiscNumberLetterTextBox" Grid.Row="2" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<Label Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Disc Title" />
<TextBox x:Name="DiscTitleTextBox" Grid.Row="3" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<Label Grid.Row="4" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Category" />
<ComboBox x:Name="CategoryComboBox" Grid.Row="4" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Label Grid.Row="5" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Region" />
<ComboBox x:Name="RegionComboBox" Grid.Row="5" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Label Grid.Row="6" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Languages" />
<ComboBox x:Name="LanguagesComboBox" Grid.Row="6" Grid.Column="1" Height="24" HorizontalAlignment="Stretch" >
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Path=Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Label Grid.Row="7" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Serial" />
<TextBox x:Name="SerialTextBox" Grid.Row="7" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<!-- Layer 0 / Data Side -->
<Label Grid.Row="8" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Data/L0 Mastering Ring" />
<TextBox x:Name="L0MasteringRingTextBox" Grid.Row="8" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" AcceptsTab="True" />
<Label Grid.Row="9" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Data/L0 Mastering SID" />
<TextBox x:Name="L0MasteringSIDTextBox" Grid.Row="9" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<Label Grid.Row="10" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Data/L0 Toolstamp/Mastering Code" />
<TextBox x:Name="L0ToolstampTextBox" Grid.Row="10" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<Label Grid.Row="11" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Data/L0 Mould SID" />
<TextBox x:Name="L0MouldSIDTextBox" Grid.Row="11" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<Label Grid.Row="12" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Data/L0 Additional Mould" />
<TextBox x:Name="L0AdditionalMouldTextBox" Grid.Row="12" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<!-- Layer 1 / Label Side -->
<Label Grid.Row="13" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Label/L1 Mastering Ring" />
<TextBox x:Name="L1MasteringRingTextBox" Grid.Row="13" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" AcceptsTab="True" />
<Label Grid.Row="14" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Label/L1 Mastering SID" />
<TextBox x:Name="L1MasteringSIDTextBox" Grid.Row="14" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<Label Grid.Row="15" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Label/L1 Toolstamp/Mastering Code" />
<TextBox x:Name="L1ToolstampTextBox" Grid.Row="15" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<Label Grid.Row="16" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Label/L1 Mould SID" />
<TextBox x:Name="L1MouldSIDTextBox" Grid.Row="16" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<Label Grid.Row="17" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Label/L1 Additional Mould" />
<TextBox x:Name="L1AdditionalMouldTextBox" Grid.Row="17" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<Label Grid.Row="18" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Barcode" />
<TextBox x:Name="BarcodeTextBox" Grid.Row="18" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<!-- This needs to be a multiline textbox -->
<Label Grid.Row="19" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Comments" />
<TextBox x:Name="CommentsTextBox" Grid.Row="19" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" AcceptsReturn="True" AcceptsTab="True" />
<!-- This needs to be a multiline textbox -->
<Label Grid.Row="20" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Contents" />
<TextBox x:Name="ContentsTextBox" Grid.Row="20" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" AcceptsReturn="True" AcceptsTab="True"/>
</Grid>
</GroupBox>
<GroupBox Grid.Row="1" Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Version and Editions">
<Grid Height="60">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="24"/>
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Version" />
<TextBox x:Name="VersionTextBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<Label Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Edition" />
<TextBox x:Name="EditionTextBox" Grid.Row="1" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
</Grid>
</GroupBox>
<!-- Accept / Cancel -->
<Grid Height="28" Grid.Row="2" Grid.Column="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Button Name="AcceptButton" Grid.Row="0" Grid.Column="1" Height="25" Width="80" Content="Accept" Click="OnAcceptClick" />
<Button Name="CancelButton" Grid.Row="0" Grid.Column="2" Height="25" Width="80" Content="Cancel" Click="OnCancelClick" />
</Grid>
</Grid>
</Window>

View File

@@ -1,231 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using DICUI.Web;
namespace DICUI.Windows
{
/// <summary>
/// Interaction logic for DiscInformationWindow.xaml
/// </summary>
public partial class DiscInformationWindow : Window
{
/// <summary>
/// List of available disc categories
/// </summary>
public List<CategoryComboBoxItem> Categories { get; private set; }
/// <summary>
/// SubmissionInfo object to fill and save
/// </summary>
public SubmissionInfo SubmissionInfo { get; set; }
/// <summary>
/// List of available regions
/// </summary>
public List<RegionComboBoxItem> Regions { get; private set; }
/// <summary>
/// List of available languages
/// </summary>
public List<LanguageComboBoxItem> Languages { get; private set; }
public DiscInformationWindow(SubmissionInfo submissionInfo)
{
InitializeComponent();
SubmissionInfo = submissionInfo;
PopulateCategories();
PopulateRegions();
PopulateLanguages();
DisableFieldsIfNeeded();
}
/// <summary>
/// Disable fields that aren't applicable to the current disc
/// </summary>
private void DisableFieldsIfNeeded()
{
// Only disable for single-layer discs
if (SubmissionInfo.SizeAndChecksums.Layerbreak == default(long))
{
L1MasteringRingTextBox.IsEnabled = false;
L1MasteringRingTextBox.Background = Brushes.Gray;
L1MasteringSIDTextBox.IsEnabled = false;
L1MasteringSIDTextBox.Background = Brushes.Gray;
L1ToolstampTextBox.IsEnabled = false;
L1ToolstampTextBox.Background = Brushes.Gray;
L1MouldSIDTextBox.IsEnabled = false;
L1MouldSIDTextBox.Background = Brushes.Gray;
L1AdditionalMouldTextBox.IsEnabled = false;
L1AdditionalMouldTextBox.Background = Brushes.Gray;
}
}
/// <summary>
/// Load the current contents of the base SubmissionInfo to the UI
/// </summary>
public void Load()
{
TitleTextBox.Text = SubmissionInfo.CommonDiscInfo.Title ?? "";
ForeignTitleTextBox.Text = SubmissionInfo.CommonDiscInfo.ForeignTitleNonLatin ?? "";
DiscNumberLetterTextBox.Text = SubmissionInfo.CommonDiscInfo.DiscNumberLetter ?? "";
DiscTitleTextBox.Text = SubmissionInfo.CommonDiscInfo.DiscTitle ?? "";
CategoryComboBox.SelectedIndex = Categories.FindIndex(r => r == SubmissionInfo.CommonDiscInfo.Category);
RegionComboBox.SelectedIndex = Regions.FindIndex(r => r == SubmissionInfo.CommonDiscInfo.Region);
if (SubmissionInfo.CommonDiscInfo.Languages != null)
{
foreach (var language in SubmissionInfo.CommonDiscInfo.Languages)
Languages.Find(l => l == language).IsChecked = true;
}
SerialTextBox.Text = SubmissionInfo.CommonDiscInfo.Serial ?? "";
L0MasteringRingTextBox.Text = SubmissionInfo.CommonDiscInfo.MasteringRingFirstLayerDataSide ?? "";
L0MasteringSIDTextBox.Text = SubmissionInfo.CommonDiscInfo.MasteringSIDCodeFirstLayerDataSide ?? "";
L0ToolstampTextBox.Text = SubmissionInfo.CommonDiscInfo.ToolstampMasteringCodeFirstLayerDataSide ?? "";
L0MouldSIDTextBox.Text = SubmissionInfo.CommonDiscInfo.MouldSIDCodeFirstLayerDataSide ?? "";
L0AdditionalMouldTextBox.Text = SubmissionInfo.CommonDiscInfo.AdditionalMouldFirstLayerDataSide ?? "";
L1MasteringRingTextBox.Text = SubmissionInfo.CommonDiscInfo.MasteringRingSecondLayerLabelSide ?? "";
L1MasteringSIDTextBox.Text = SubmissionInfo.CommonDiscInfo.MasteringSIDCodeSecondLayerLabelSide ?? "";
L1ToolstampTextBox.Text = SubmissionInfo.CommonDiscInfo.ToolstampMasteringCodeSecondLayerLabelSide ?? "";
L1MouldSIDTextBox.Text = SubmissionInfo.CommonDiscInfo.MouldSIDCodeSecondLayerLabelSide ?? "";
L1AdditionalMouldTextBox.Text = SubmissionInfo.CommonDiscInfo.AdditionalMouldSecondLayerLabelSide ?? "";
BarcodeTextBox.Text = SubmissionInfo.CommonDiscInfo.Barcode ?? "";
CommentsTextBox.Text = SubmissionInfo.CommonDiscInfo.Comments ?? "";
ContentsTextBox.Text = SubmissionInfo.CommonDiscInfo.Contents ?? "";
VersionTextBox.Text = SubmissionInfo.VersionAndEditions.Version ?? "";
EditionTextBox.Text = SubmissionInfo.VersionAndEditions.OtherEditions ?? "";
}
/// <summary>
/// Get a complete list of categories and fill the combo box
/// </summary>
private void PopulateCategories()
{
var categories = Enum.GetValues(typeof(DiscCategory)).OfType<DiscCategory?>().ToList();
ViewModels.LoggerViewModel.VerboseLogLn("Populating categories, {0} categories found.", categories.Count);
Categories = new List<CategoryComboBoxItem>();
foreach (var category in categories)
{
Categories.Add(new CategoryComboBoxItem(category));
}
CategoryComboBox.ItemsSource = Categories;
CategoryComboBox.SelectedIndex = 0;
}
/// <summary>
/// Get a complete list of languages and fill the combo box
/// </summary>
private void PopulateLanguages()
{
var languages = Enum.GetValues(typeof(Language)).OfType<Language?>().ToList();
ViewModels.LoggerViewModel.VerboseLogLn("Populating languages, {0} languages found.", languages.Count);
Languages = new List<LanguageComboBoxItem>();
foreach (var language in languages)
{
Languages.Add(new LanguageComboBoxItem(language));
}
LanguagesComboBox.ItemsSource = Languages;
LanguagesComboBox.SelectedIndex = 0;
}
/// <summary>
/// Get a complete list of regions and fill the combo box
/// </summary>
private void PopulateRegions()
{
var regions = Enum.GetValues(typeof(Region)).OfType<Region?>().ToList();
ViewModels.LoggerViewModel.VerboseLogLn("Populating regions, {0} regions found.", regions.Count);
Regions = new List<RegionComboBoxItem>();
foreach (var region in regions)
{
Regions.Add(new RegionComboBoxItem(region));
}
RegionComboBox.ItemsSource = Regions;
RegionComboBox.SelectedIndex = 0;
}
/// <summary>
/// Save the current contents of the UI to the base SubmissionInfo
/// </summary>
private void Save()
{
SubmissionInfo.CommonDiscInfo.Title = TitleTextBox.Text ?? "";
SubmissionInfo.CommonDiscInfo.ForeignTitleNonLatin = ForeignTitleTextBox.Text ?? "";
SubmissionInfo.CommonDiscInfo.DiscNumberLetter = DiscNumberLetterTextBox.Text ?? "";
SubmissionInfo.CommonDiscInfo.DiscTitle = DiscTitleTextBox.Text ?? "";
SubmissionInfo.CommonDiscInfo.Category = (CategoryComboBox.SelectedItem as CategoryComboBoxItem)?.Value ?? DiscCategory.Games;
SubmissionInfo.CommonDiscInfo.Region = (RegionComboBox.SelectedItem as RegionComboBoxItem)?.Value ?? Region.World;
var languages = new List<Language?>();
foreach (var language in Languages)
{
if (language.IsChecked)
languages.Add(language.Value);
}
if (languages.Count == 0)
languages.Add(null);
SubmissionInfo.CommonDiscInfo.Languages = languages.ToArray();
SubmissionInfo.CommonDiscInfo.Serial = SerialTextBox.Text ?? "";
SubmissionInfo.CommonDiscInfo.MasteringRingFirstLayerDataSide = L0MasteringRingTextBox.Text ?? "";
SubmissionInfo.CommonDiscInfo.MasteringSIDCodeFirstLayerDataSide = L0MasteringSIDTextBox.Text ?? "";
SubmissionInfo.CommonDiscInfo.ToolstampMasteringCodeFirstLayerDataSide = L0ToolstampTextBox.Text ?? "";
SubmissionInfo.CommonDiscInfo.MouldSIDCodeFirstLayerDataSide = L0MouldSIDTextBox.Text ?? "";
SubmissionInfo.CommonDiscInfo.AdditionalMouldFirstLayerDataSide = L0AdditionalMouldTextBox.Text ?? "";
SubmissionInfo.CommonDiscInfo.MasteringRingSecondLayerLabelSide = L1MasteringRingTextBox.Text ?? "";
SubmissionInfo.CommonDiscInfo.MasteringSIDCodeSecondLayerLabelSide = L1MasteringSIDTextBox.Text ?? "";
SubmissionInfo.CommonDiscInfo.ToolstampMasteringCodeSecondLayerLabelSide = L1ToolstampTextBox.Text ?? "";
SubmissionInfo.CommonDiscInfo.MouldSIDCodeSecondLayerLabelSide = L1MouldSIDTextBox.Text ?? "";
SubmissionInfo.CommonDiscInfo.AdditionalMouldSecondLayerLabelSide = L1AdditionalMouldTextBox.Text ?? "";
SubmissionInfo.CommonDiscInfo.Barcode = BarcodeTextBox.Text ?? "";
SubmissionInfo.CommonDiscInfo.Comments = CommentsTextBox.Text ?? "";
SubmissionInfo.CommonDiscInfo.Contents = ContentsTextBox.Text ?? "";
SubmissionInfo.VersionAndEditions.Version = VersionTextBox.Text ?? "";
SubmissionInfo.VersionAndEditions.OtherEditions = EditionTextBox.Text ?? "";
}
#region Event Handlers
/// <summary>
/// Handler for AcceptButton Click event
/// </summary>
private void OnAcceptClick(object sender, RoutedEventArgs e)
{
Save();
Hide();
}
/// <summary>
/// Handler for CancelButton Click event
/// </summary>
private void OnCancelClick(object sender, RoutedEventArgs e)
{
Hide();
}
/// <summary>
/// Handler for DiscInformationWindow Closed event
/// </summary>
private void OnClosed(object sender, EventArgs e)
{
Hide();
}
#endregion
}
}

View File

@@ -1,56 +0,0 @@
<Window x:Class="DICUI.Windows.LogWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DICUI"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
Title="Log Window" Height="350" Width="600" Closed="OnWindowClosed" Loaded="OnWindowLoaded"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="*" />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Height="22" Margin="10 10 10 0">
<ProgressBar x:Name="progressBar" />
<TextBlock x:Name="progressLabel" Grid.Row="0" Height="22" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="0 2 0 0" />
</Grid>
<Border Grid.Row="1" Background="White" BorderBrush="Gainsboro" BorderThickness="1" Margin="10">
<ScrollViewer Name="outputViewer" SizeChanged="ScrollViewer_SizeChanged">
<RichTextBox Name="output" FontFamily="Consolas" Background="#202020" IsReadOnly="true" TextChanged="OnTextChanged" />
</ScrollViewer>
</Border>
<Grid Grid.Row="2">
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition Width="3*"/>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<CheckBox Content="Verbose" Margin="10 0 0 10" Grid.Column="0" VerticalAlignment="Center"
ToolTip="Enable verbose logging of tasks"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=VerboseLogging}"
/>
<CheckBox Content="Open at startup" Margin="10 0 0 10" Grid.Column="1" Grid.ColumnSpan="2" VerticalAlignment="Center"
ToolTip="Open this window at startup"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=OpenLogWindowAtStartup}"
/>
<Button Margin="0 0 10 10" Grid.Column="3" Height="22" Width="60" Content="Clear" HorizontalAlignment="Right" Click="OnClearButton" />
<Button Margin="0 0 10 10" Grid.Column="4" Height="22" Width="60" Content="Hide" HorizontalAlignment="Right" Click="OnHideButton" />
<Button Margin="0 0 10 10" Grid.Column="5" Height="22" Width="60" Content="Save" HorizontalAlignment="Right" Click="OnSaveButton" />
<Button Visibility="Hidden" Name="AbortButton" Margin="0 0 10 10" Grid.Column="2" Height="22" Width="80" Content="Abort" HorizontalAlignment="Right" Click="OnAbortButton" />
</Grid>
</Grid>
</Window>

View File

@@ -1,399 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Interop;
using System.Windows.Media;
namespace DICUI.Windows
{
public partial class LogWindow : Window
{
private const int GWL_STYLE = -16;
private const int WS_SYSMENU = 0x80000;
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
private readonly MainWindow _mainWindow;
private readonly FlowDocument _document;
private readonly Paragraph _paragraph;
private readonly List<Matcher> _matchers;
volatile Process _process;
public LogWindow(MainWindow mainWindow)
{
InitializeComponent();
this._mainWindow = mainWindow;
_document = new FlowDocument();
_paragraph = new Paragraph();
_document.Blocks.Add(_paragraph);
output.Document = _document;
_matchers = new List<Matcher>();
_matchers.Add(new Matcher(
"Descrambling data sector of img (LBA)",
@"\s*(\d+)\/\s*(\d+)$",
match => {
if (UInt32.TryParse(match.Groups[1].Value, out uint current) && UInt32.TryParse(match.Groups[2].Value, out uint total))
{
float percentProgress = (current / (float)total) * 100;
progressBar.Value = percentProgress;
progressLabel.Text = string.Format("Descrambling image.. ({0:##.##}%)", percentProgress);
}
}));
_matchers.Add(new Matcher(
@"Creating .scm (LBA)",
@"\s*(\d+)\/\s*(\d+)$",
match => {
if (UInt32.TryParse(match.Groups[1].Value, out uint current) && UInt32.TryParse(match.Groups[2].Value, out uint total))
{
float percentProgress = (current / (float)total) * 100;
progressBar.Value = percentProgress;
progressLabel.Text = string.Format("Creating scrambled image.. ({0:##.##}%)", percentProgress);
}
}));
_matchers.Add(new Matcher(
"Checking sectors (LBA)",
@"\s*(\d+)\/\s*(\d+)$",
match => {
if (UInt32.TryParse(match.Groups[1].Value, out uint current) && UInt32.TryParse(match.Groups[2].Value, out uint total))
{
float percentProgress = (current / (float)total) * 100;
progressBar.Value = percentProgress;
progressLabel.Text = string.Format("Checking for errors.. ({0:##.##}%)", percentProgress);
}
}));
_matchers.Add(new Matcher(
"Scanning sector (LBA)",
@"\s*(\d+)\/\s*(\d+)$",
match => {
if (UInt32.TryParse(match.Groups[1].Value, out uint current) && UInt32.TryParse(match.Groups[2].Value, out uint total))
{
float percentProgress = (current / (float)total) * 100;
progressBar.Value = percentProgress;
progressLabel.Text = string.Format("Scanning sectors for protection.. ({0:##.##}%)", percentProgress);
}
}));
}
public void StartDump(string args)
{
AppendToTextBox(string.Format("Launching DIC with args: {0}\r\n", args), Brushes.Orange);
Task.Run(() =>
{
_process = new Process()
{
StartInfo = new ProcessStartInfo()
{
FileName = @"Programs/DiscImageCreator.exe",
Arguments = args,
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
},
};
StreamState stdoutState = new StreamState(false);
StreamState stderrState = new StreamState(true);
//_cmd.ErrorDataReceived += (process, text) => Dispatcher.Invoke(() => UpdateConsole(text.Data, Brushes.Red));
_process.Start();
var _1 = ConsumeOutput(_process.StandardOutput, s => Dispatcher.Invoke(() => UpdateConsole(s, stdoutState)));
var _2 = ConsumeOutput(_process.StandardError, s => Dispatcher.Invoke(() => UpdateConsole(s, stderrState)));
_process.EnableRaisingEvents = true;
_process.Exited += OnProcessExit;
});
}
public void AdjustPositionToMainWindow()
{
this.Left = _mainWindow.Left;
this.Top = _mainWindow.Top + _mainWindow.Height + Constants.LogWindowMarginFromMainWindow;
}
private void GracefullyTerminateProcess()
{
if (_process != null)
{
_process.Exited -= OnProcessExit;
bool isForced = !_process.HasExited;
if (isForced)
{
AppendToTextBox("\r\nForcefully Killing the process\r\n", Brushes.Red);
_process.Kill();
_process.WaitForExit();
}
AppendToTextBox(string.Format("\r\nExit Code: {0}\r\n", _process.ExitCode), _process.ExitCode == 0 ? Brushes.Green : Brushes.Red);
if (_process.ExitCode == 0)
{
Dispatcher.Invoke(() =>
{
progressLabel.Text = "Done!";
progressBar.Value = 100;
progressBar.Foreground = Brushes.Green;
});
}
else
{
Dispatcher.Invoke(() =>
{
progressLabel.Text = isForced ? "Aborted by user" : "Error, please check log!";
progressBar.Value = 100;
progressBar.Foreground = Brushes.Red;
});
}
_process.Close();
}
_process = null;
}
private void ScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e)
{
outputViewer.ScrollToBottom();
}
async Task ConsumeOutput(TextReader reader, Action<string> callback)
{
char[] buffer = new char[256];
int cch;
while ((cch = await reader.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
callback(new string(buffer, 0, cch));
}
}
// this is used to optimize the work since we need to process A LOT of text
struct Matcher
{
private readonly string prefix;
private readonly Regex regex;
private readonly int start;
private readonly Action<Match> lambda;
public Matcher(string prefix, string regex, Action<Match> lambda)
{
this.prefix = prefix;
this.regex = new Regex(regex);
this.start = prefix.Length;
this.lambda = lambda;
}
public bool Matches(ref string text) => text.StartsWith(prefix);
public void Apply(ref string text)
{
Match match = regex.Match(text, start);
lambda.Invoke(match);
}
}
private void ProcessStringForProgressBar(string text)
{
foreach (Matcher matcher in _matchers)
{
if (matcher.Matches(ref text))
{
matcher.Apply(ref text);
return;
}
}
}
class StreamState
{
public enum State
{
BEGIN,
READ_CARRIAGE,
};
public State state;
public readonly StringBuilder buffer;
public readonly bool isError;
public StreamState(bool isError)
{
this.state = State.BEGIN;
this.buffer = new StringBuilder();
this.isError = isError;
}
public bool HasData() => buffer.Length > 0;
public string Fetch() => buffer.ToString();
public void Clear() => buffer.Clear();
public void Append(char c) => buffer.Append(c);
public bool Is(State state) => this.state == state;
public void Set(State state) => this.state = state;
}
public void AppendToTextBox(string text, Brush color)
{
if (Application.Current.Dispatcher.CheckAccess())
{
Run run = new Run(text) { Foreground = color };
_paragraph.Inlines.Add(run);
}
else
Dispatcher.Invoke(() =>
{
Run run = new Run(text) { Foreground = color };
_paragraph.Inlines.Add(run);
});
}
private void UpdateConsole(string text, StreamState state)
{
/*if (c == '\r') { output.Inlines.Add(@"\r"); file.Write("\\r"); }
else if (c == '\n') { output.Inlines.Add(@"\n"); file.Write("\\n\n"); }
output.Inlines.Add(""+c);
file.Write(c);
file.Flush();
continue;*/
if (text != null)
{
foreach (char c in text)
{
switch (c)
{
case '\r' when (state.Is(StreamState.State.BEGIN)):
{
state.Set(StreamState.State.READ_CARRIAGE);
break;
}
case '\n' when (state.Is(StreamState.State.READ_CARRIAGE)):
{
if (state.buffer.Length > 0)
{
string buffer = state.Fetch();
AppendToTextBox(buffer, state.isError ? Brushes.Red : Brushes.White);
if (!state.isError)
ProcessStringForProgressBar(buffer);
}
_paragraph.Inlines.Add(new LineBreak());
state.Clear();
state.Set(StreamState.State.BEGIN);
break;
}
default:
if (state.Is(StreamState.State.READ_CARRIAGE) && state.HasData())
{
if (!(_paragraph.Inlines.LastInline is LineBreak))
_paragraph.Inlines.Remove(_paragraph.Inlines.LastInline);
string buffer = state.Fetch();
AppendToTextBox(buffer, state.isError ? Brushes.Red : Brushes.White);
if (!state.isError)
ProcessStringForProgressBar(buffer);
state.Clear();
}
state.Set(StreamState.State.BEGIN);
state.Append(c);
break;
}
}
}
}
#region EventHandlers
private void OnWindowClosed(object sender, EventArgs e)
{
GracefullyTerminateProcess();
}
private void OnWindowLoaded(object sender, EventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
}
void OnProcessExit(object sender, EventArgs e)
{
Dispatcher.Invoke(() => AbortButton.IsEnabled = false);
GracefullyTerminateProcess();
}
private void OnHideButton(object sender, EventArgs e)
{
ViewModels.LoggerViewModel.WindowVisible = false;
//TODO: this should be bound directly to WindowVisible property in two way fashion
// we need to study how to properly do it in XAML
_mainWindow.ShowLogMenuItem.IsChecked = false;
}
private void OnClearButton(object sender, EventArgs e)
{
output.Document.Blocks.Clear();
}
private void OnSaveButton(object sender, EventArgs e)
{
using (StreamWriter tw = new StreamWriter(File.OpenWrite("console.log")))
{
foreach (var inline in _paragraph.Inlines)
{
if (inline is Run run)
{
tw.Write(run.Text);
}
}
}
}
private void OnAbortButton(object sender, EventArgs args)
{
GracefullyTerminateProcess();
}
private void OnStartButton(object sender, EventArgs args)
{
StartDump("cd e Gam.iso 16");
}
private void OnTextChanged(object sender, TextChangedEventArgs e)
{
outputViewer.ScrollToBottom();
}
#endregion
}
}

View File

@@ -1,131 +0,0 @@
<Window x:Class="DICUI.Windows.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DICUI"
mc:Ignorable="d"
Title="DICUI" Height="450" Width="600" WindowStartupLocation="CenterScreen" ResizeMode="CanMinimize"
LocationChanged="MainWindowLocationChanged" Activated="MainWindowActivated" Closing="MainWindowClosing">
<Window.Resources>
<local:EnumDescriptionConverter x:Key="enumConverter" />
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*"/>
<ColumnDefinition Width="13*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="4*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<StackPanel VerticalAlignment="Top" Grid.ColumnSpan="4">
<Menu Width="Auto" Height="20" >
<MenuItem Header="_File">
<MenuItem x:Name="AppExit" Header="E_xit" HorizontalAlignment="Left" Width="185" Click="AppExitClick" />
</MenuItem>
<MenuItem Header="_Tools">
<MenuItem x:Name="OptionsMenuItem" Header="_Options" HorizontalAlignment="Left" Width="185" Click="OptionsMenuItemClick" />
<MenuItem x:Name="ShowLogMenuItem" Header="Show _Log Window" IsCheckable="true" Width="185" HorizontalAlignment="Left"
DataContext="{Binding Source={x:Static local:ViewModels.LoggerViewModel}}"
IsChecked="{Binding Path=WindowVisible}"
/>
</MenuItem>
<MenuItem Header="_Help">
<MenuItem x:Name="About" Header="_About" HorizontalAlignment="Left" Width="185" Click="AboutClick" />
<MenuItem x:Name="CheckForUpdatesMenuItem" Header="_Check for Updates" HorizontalAlignment="Left" Width="185" Click="CheckForUpdatesClick" />
</MenuItem>
</Menu>
</StackPanel>
<GroupBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="5,5,5.2,5.4" HorizontalAlignment="Stretch" Header="Settings"/>
<GroupBox Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="5,4.6,5.2,4.8" HorizontalAlignment="Stretch" Header="Controls"/>
<GroupBox Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Margin="5,5.2,5.2,4.8" HorizontalAlignment="Stretch" Header="Status"/>
<Grid Grid.Row="1" Grid.Column="0" Margin="15,25,15.2,10.4" Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="2.5*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Content="System/Media Type" />
<ComboBox x:Name="SystemTypeComboBox" Grid.Row="0" Grid.Column="1" Height="22" Width="250" HorizontalAlignment="Left" SelectionChanged="SystemTypeComboBoxSelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" Foreground="{Binding Path=Foreground}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ComboBox x:Name="MediaTypeComboBox" Grid.Row="0" Grid.Column="1" Height="22" Width="140" HorizontalAlignment="Right" SelectionChanged="MediaTypeComboBoxSelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource enumConverter}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Label Grid.Row="1" Grid.Column="0" VerticalAlignment="Center">Output Filename</Label>
<TextBox x:Name="OutputFilenameTextBox" Grid.Row="1" Grid.Column="1" Height="22" TextChanged="OutputFilenameTextBoxTextChanged" />
<Label Grid.Row="2" Grid.Column="0" VerticalAlignment="Center">Output Directory</Label>
<TextBox x:Name="OutputDirectoryTextBox" Grid.Row="2" Grid.Column="1" Height="22" Width="345" HorizontalAlignment="Left" TextChanged="OutputDirectoryTextBoxTextChanged" />
<Button x:Name="OutputDirectoryBrowseButton" Grid.Row="2" Grid.Column="1" Height="22" Width="50" HorizontalAlignment="Right" Content="Browse" Click="OutputDirectoryBrowseButtonClick"/>
<Label Grid.Row="3" Grid.Column="0" VerticalAlignment="Center">Drive Letter</Label>
<ComboBox x:Name="DriveLetterComboBox" Grid.Row="3" Grid.Column="1" Height="22" Width="60" HorizontalAlignment="Left" SelectionChanged="DriveLetterComboBoxSelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Letter}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Label Grid.Row="4" Grid.Column="0" VerticalAlignment="Center">Drive Speed</Label>
<ComboBox x:Name="DriveSpeedComboBox" Grid.Row="4" Grid.Column="1" Height="22" Width="60" HorizontalAlignment="Left" SelectionChanged="DriveSpeedComboBoxSelectionChanged" />
<Label Grid.Row="5" Grid.Column="0" VerticalAlignment="Center">Parameters</Label>
<TextBox x:Name="ParametersTextBox" Grid.Row="5" Grid.Column="1" Height="22" Width="370" HorizontalAlignment="Left" IsEnabled="False" />
<CheckBox x:Name="EnableParametersCheckBox" Grid.Row="5" Grid.Column="1" Height="22" HorizontalAlignment="Right" IsChecked="False" Click="EnableParametersCheckBoxClick" />
</Grid>
<Grid Grid.Row="2" Grid.Column="0" Margin="15,19.6,15.2,9.8" Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Button x:Name="StartStopButton" Grid.Row="0" Grid.Column="0" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Start Dumping" Click="StartStopButtonClick" IsEnabled="False" />
<Button x:Name="MediaScanButton" Grid.Row="0" Grid.Column="1" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Scan for disks" Click="MediaScanButtonClick" />
<Button x:Name="CopyProtectScanButton" Grid.Row="0" Grid.Column="2" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Scan for protection" Click="CopyProtectScanButtonClick" />
<CheckBox x:Name="EjectWhenDoneCheckBox" Grid.Row="0" Grid.Column="3" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Eject When Done" IsChecked="False" />
</Grid>
<Grid Grid.Row="3" Grid.Column="0" Margin="15,20.2,15.2,9.8" Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Label x:Name="StatusLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Waiting for media..." />
</Grid>
</Grid>
</Window>

View File

@@ -1,890 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using WinForms = System.Windows.Forms;
using BurnOutSharp;
using DICUI.Data;
using DICUI.Utilities;
using DICUI.Web;
namespace DICUI.Windows
{
public partial class MainWindow : Window
{
#region Fields
/// <summary>
/// Currently selected or detected media type
/// </summary>
public MediaType? CurrentMediaType { get; private set; }
/// <summary>
/// Current list of drives
/// </summary>
public List<Drive> Drives { get; private set; }
/// <summary>
/// Current dumping environment
/// </summary>
public DumpEnvironment Env { get; private set; }
/// <summary>
/// Current list of supported media types
/// </summary>
public List<MediaType?> MediaTypes { get; private set; } = new List<MediaType?>();
/// <summary>
/// Current list of supported system profiles
/// </summary>
public List<KnownSystemComboBoxItem> Systems { get; private set; }
/// <summary>
/// Current UI options
/// </summary>
public UIOptions UIOptions { get; private set; } = new UIOptions();
#endregion
#region Private Instance Variables
/// <summary>
/// Determines if the window is already shown or not
/// </summary>
private bool alreadyShown;
/// <summary>
/// Current attached DiscInformationWindow
/// </summary>
private DiscInformationWindow discInformationWindow;
/// <summary>
/// Current attached LogWindow
/// </summary>
private readonly LogWindow logWindow;
/// <summary>
/// Currently attached OptionsWindow
/// </summary>
private OptionsWindow optionsWindow;
#endregion
public MainWindow()
{
InitializeComponent();
// Load the options
ViewModels.OptionsViewModel = new OptionsViewModel(UIOptions);
// Load the log window
logWindow = new LogWindow(this);
ViewModels.LoggerViewModel.SetWindow(logWindow);
// Disable buttons until we load fully
StartStopButton.IsEnabled = false;
MediaScanButton.IsEnabled = false;
CopyProtectScanButton.IsEnabled = false;
if (UIOptions.OpenLogWindowAtStartup)
{
this.WindowStartupLocation = WindowStartupLocation.Manual;
double combinedHeight = this.Height + logWindow.Height + Constants.LogWindowMarginFromMainWindow;
Rectangle bounds = GetScaledCoordinates(WinForms.Screen.PrimaryScreen.WorkingArea);
this.Left = bounds.Left + (bounds.Width - this.Width) / 2;
this.Top = bounds.Top + (bounds.Height - combinedHeight) / 2;
}
}
#region Helpers
/// <summary>
/// Browse for an output folder
/// </summary>
private void BrowseFolder()
{
WinForms.FolderBrowserDialog folderDialog = new WinForms.FolderBrowserDialog { ShowNewFolderButton = false, SelectedPath = System.AppDomain.CurrentDomain.BaseDirectory };
WinForms.DialogResult result = folderDialog.ShowDialog();
if (result == WinForms.DialogResult.OK)
{
OutputDirectoryTextBox.Text = folderDialog.SelectedPath;
}
}
/// <summary>
/// Cache the current disc type to internal variable
/// </summary>
private void CacheCurrentDiscType()
{
// Get the drive letter from the selected item
if (DriveLetterComboBox.SelectedItem is Drive drive)
{
// Get the current media type
if (!UIOptions.SkipMediaTypeDetection)
{
ViewModels.LoggerViewModel.VerboseLog("Trying to detect media type for drive {0}.. ", drive.Letter);
CurrentMediaType = Validators.GetMediaType(drive);
ViewModels.LoggerViewModel.VerboseLogLn(CurrentMediaType == null ? "unable to detect." : ("detected " + CurrentMediaType.LongName() + "."));
}
}
}
/// <summary>
/// Create a DumpEnvironment with all current settings
/// </summary>
/// <returns>Filled DumpEnvironment instance</returns>
private DumpEnvironment DetermineEnvironment()
{
// Populate the new environment
var env = new DumpEnvironment(UIOptions.Options,
OutputDirectoryTextBox.Text,
OutputFilenameTextBox.Text,
DriveLetterComboBox.SelectedItem as Drive,
SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem,
MediaTypeComboBox.SelectedItem as MediaType?,
ParametersTextBox.Text);
// Disable automatic reprocessing of the textboxes until we're done
OutputDirectoryTextBox.TextChanged -= OutputDirectoryTextBoxTextChanged;
OutputFilenameTextBox.TextChanged -= OutputFilenameTextBoxTextChanged;
OutputDirectoryTextBox.Text = env.OutputDirectory;
OutputFilenameTextBox.Text = env.OutputFilename;
OutputDirectoryTextBox.TextChanged += OutputDirectoryTextBoxTextChanged;
OutputFilenameTextBox.TextChanged += OutputFilenameTextBoxTextChanged;
return env;
}
/// <summary>
/// Ensure information is consistent with the currently selected disc type
/// </summary>
private void EnsureDiscInformation()
{
// Get the current environment information
Env = DetermineEnvironment();
// Take care of null cases
if (Env.System == null)
Env.System = KnownSystem.NONE;
if (Env.Type == null)
Env.Type = MediaType.NONE;
// Get the status to write out
Result result = Validators.GetSupportStatus(Env.System, Env.Type);
StatusLabel.Content = result.Message;
// Set the index for the current disc type
SetCurrentDiscType();
StartStopButton.IsEnabled = result && (Drives != null && Drives.Count > 0 ? true : false);
// If we're in a type that doesn't support drive speeds
DriveSpeedComboBox.IsEnabled = Env.Type.DoesSupportDriveSpeed();
// If input params are not enabled, generate the full parameters from the environment
if (!ParametersTextBox.IsEnabled)
{
string generated = Env.GetFullParameters((int?)DriveSpeedComboBox.SelectedItem);
if (generated != null)
ParametersTextBox.Text = generated;
}
}
/// <summary>
/// Get the default output directory name from the currently selected drive
/// </summary>
/// <param name="driveChanged">Force an updated name if the drive letter changes</param>
private void GetOutputNames(bool driveChanged)
{
Drive drive = DriveLetterComboBox.SelectedItem as Drive;
KnownSystem? systemType = SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem;
MediaType? mediaType = MediaTypeComboBox.SelectedItem as MediaType?;
// Set the output directory, if we changed drives or it's not already
if (driveChanged || string.IsNullOrEmpty(OutputDirectoryTextBox.Text))
OutputDirectoryTextBox.Text = Path.Combine(UIOptions.DefaultOutputPath, drive?.VolumeLabel ?? string.Empty);
// Get the extension for the file for the next two statements
string extension = Env.GetExtension(mediaType);
// Set the output filename, if we changed drives or it's not already
if (driveChanged || string.IsNullOrEmpty(OutputFilenameTextBox.Text))
OutputFilenameTextBox.Text = (drive?.VolumeLabel ?? systemType.LongName()) + (extension ?? ".bin");
// If the extension for the file changed, update that automatically
else if (Path.GetExtension(OutputFilenameTextBox.Text) != extension)
OutputFilenameTextBox.Text = Path.GetFileNameWithoutExtension(OutputFilenameTextBox.Text) + (extension ?? ".bin");
}
/// <summary>
/// Get a complete list of active disc drives and fill the combo box
/// </summary>
/// <remarks>TODO: Find a way for this to periodically run, or have it hook to a "drive change" event</remarks>
private void PopulateDrives()
{
ViewModels.LoggerViewModel.VerboseLogLn("Scanning for drives..");
// Always enable the media scan
MediaScanButton.IsEnabled = true;
// Populate the list of drives and add it to the combo box
Drives = Validators.CreateListOfDrives(UIOptions.IgnoreFixedDrives);
DriveLetterComboBox.ItemsSource = Drives;
if (DriveLetterComboBox.Items.Count > 0)
{
// Check for active optical drives first
int index = Drives.FindIndex(d => d.MarkedActive && d.InternalDriveType == InternalDriveType.Optical);
// Then we check for floppy drives
if (index == -1)
index = Drives.FindIndex(d => d.MarkedActive && d.InternalDriveType == InternalDriveType.Floppy);
// Then we try all other drive types
if (index == -1)
index = Drives.FindIndex(d => d.MarkedActive);
// Set the selected index
DriveLetterComboBox.SelectedIndex = (index != -1 ? index : 0);
StatusLabel.Content = "Valid drive found! Choose your Media Type";
CopyProtectScanButton.IsEnabled = true;
// Get the current media type
if (!UIOptions.SkipSystemDetection && index != -1)
{
ViewModels.LoggerViewModel.VerboseLog("Trying to detect system for drive {0}.. ", Drives[index].Letter);
var currentSystem = Validators.GetKnownSystem(Drives[index]);
ViewModels.LoggerViewModel.VerboseLogLn(currentSystem == null || currentSystem == KnownSystem.NONE ? "unable to detect." : ("detected " + currentSystem.LongName() + "."));
if (currentSystem != null && currentSystem != KnownSystem.NONE)
{
int sysIndex = Systems.FindIndex(s => s == currentSystem);
SystemTypeComboBox.SelectedIndex = sysIndex;
}
}
// Only enable the start/stop if we don't have the default selected
StartStopButton.IsEnabled = (SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem) != KnownSystem.NONE;
ViewModels.LoggerViewModel.VerboseLogLn("Found {0} drives: {1}", Drives.Count, string.Join(", ", Drives.Select(d => d.Letter)));
}
else
{
DriveLetterComboBox.SelectedIndex = -1;
StatusLabel.Content = "No valid drive found!";
StartStopButton.IsEnabled = false;
CopyProtectScanButton.IsEnabled = false;
ViewModels.LoggerViewModel.VerboseLogLn("Found no drives");
}
}
/// <summary>
/// Populate media type according to system type
/// </summary>
private void PopulateMediaType()
{
KnownSystem? currentSystem = SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem;
if (currentSystem != null)
{
MediaTypes = Validators.GetValidMediaTypes(currentSystem);
MediaTypeComboBox.ItemsSource = MediaTypes;
MediaTypeComboBox.IsEnabled = MediaTypes.Count > 1;
MediaTypeComboBox.SelectedIndex = (MediaTypes.IndexOf(CurrentMediaType) >= 0 ? MediaTypes.IndexOf(CurrentMediaType) : 0);
}
else
{
MediaTypeComboBox.IsEnabled = false;
MediaTypeComboBox.ItemsSource = null;
MediaTypeComboBox.SelectedIndex = -1;
}
}
/// <summary>
/// Get a complete list of supported systems and fill the combo box
/// </summary>
private void PopulateSystems()
{
var knownSystems = Validators.CreateListOfSystems();
ViewModels.LoggerViewModel.VerboseLogLn("Populating systems, {0} systems found.", knownSystems.Count);
Dictionary<KnownSystemCategory, List<KnownSystem?>> mapping = knownSystems
.GroupBy(s => s.Category())
.ToDictionary(
k => k.Key,
v => v
.OrderBy(s => s.LongName())
.ToList()
);
Systems = new List<KnownSystemComboBoxItem>()
{
new KnownSystemComboBoxItem(KnownSystem.NONE),
};
foreach (var group in mapping)
{
Systems.Add(new KnownSystemComboBoxItem(group.Key));
group.Value.ForEach(system => Systems.Add(new KnownSystemComboBoxItem(system)));
}
SystemTypeComboBox.ItemsSource = Systems;
SystemTypeComboBox.SelectedIndex = 0;
StartStopButton.IsEnabled = false;
}
/// <summary>
/// Process the current custom parameters back into UI values
/// </summary>
private void ProcessCustomParameters()
{
Env.SetParameters(ParametersTextBox.Text);
if (Env.Parameters == null)
return;
int driveIndex = Drives.Select(d => d.Letter).ToList().IndexOf(Env.Parameters.InputPath()[0]);
if (driveIndex > -1)
DriveLetterComboBox.SelectedIndex = driveIndex;
int driveSpeed = Env.Parameters.GetSpeed() ?? -1;
if (driveSpeed > 0)
DriveSpeedComboBox.SelectedValue = driveSpeed;
else
Env.Parameters.SetSpeed((int?)DriveSpeedComboBox.SelectedValue);
string trimmedPath = Env.Parameters.OutputPath()?.Trim('"') ?? string.Empty;
string outputDirectory = Path.GetDirectoryName(trimmedPath);
string outputFilename = Path.GetFileName(trimmedPath);
if (!string.IsNullOrWhiteSpace(outputDirectory))
OutputDirectoryTextBox.Text = outputDirectory;
else
outputDirectory = OutputDirectoryTextBox.Text;
if (!string.IsNullOrWhiteSpace(outputFilename))
OutputFilenameTextBox.Text = outputFilename;
else
outputFilename = OutputFilenameTextBox.Text;
MediaType? mediaType = Env.Parameters.GetMediaType();
int mediaTypeIndex = MediaTypes.IndexOf(mediaType);
if (mediaTypeIndex > -1)
MediaTypeComboBox.SelectedIndex = mediaTypeIndex;
}
/// <summary>
/// Scan and show copy protection for the current disc
/// </summary>
private async void ScanAndShowProtection()
{
if (Env == null)
Env = DetermineEnvironment();
if (Env.Drive.Letter != default(char))
{
ViewModels.LoggerViewModel.VerboseLogLn("Scanning for copy protection in {0}", Env.Drive.Letter);
var tempContent = StatusLabel.Content;
StatusLabel.Content = "Scanning for copy protection... this might take a while!";
StartStopButton.IsEnabled = false;
MediaScanButton.IsEnabled = false;
CopyProtectScanButton.IsEnabled = false;
var progress = new Progress<FileProtection>();
progress.ProgressChanged += ProgressUpdated;
string protections = await Validators.RunProtectionScanOnPath(Env.Drive.Letter + ":\\", progress);
// If SmartE is detected on the current disc, remove `/sf` from the flags for DIC only
if (Env.InternalProgram == InternalProgram.DiscImageCreator && protections.Contains("SmartE"))
{
((DiscImageCreator.Parameters)Env.Parameters)[DiscImageCreator.Flag.ScanFileProtect] = false;
ViewModels.LoggerViewModel.VerboseLogLn($"SmartE detected, removing {DiscImageCreator.FlagStrings.ScanFileProtect} from parameters");
}
if (!ViewModels.LoggerViewModel.WindowVisible)
MessageBox.Show(protections, "Detected Protection", MessageBoxButton.OK, MessageBoxImage.Information);
ViewModels.LoggerViewModel.VerboseLog("Detected the following protections in {0}:\r\n\r\n{1}", Env.Drive.Letter, protections);
StatusLabel.Content = tempContent;
StartStopButton.IsEnabled = true;
MediaScanButton.IsEnabled = true;
CopyProtectScanButton.IsEnabled = true;
}
}
/// <summary>
/// Set the current disc type in the combo box
/// </summary>
private void SetCurrentDiscType()
{
// If we have an invalid current type, we don't care and return
if (CurrentMediaType == null || CurrentMediaType == MediaType.NONE)
return;
// Now set the selected item, if possible
int index = MediaTypes.FindIndex(kvp => kvp.Value == CurrentMediaType);
if (index != -1)
MediaTypeComboBox.SelectedIndex = index;
else
StatusLabel.Content = $"Disc of type '{Converters.LongName(CurrentMediaType)}' found, but the current system does not support it!";
}
/// <summary>
/// Set the drive speed based on reported maximum and user-defined option
/// </summary>
private void SetSupportedDriveSpeed()
{
// Set the drive speed list that's appropriate
var values = Constants.GetSpeedsForMediaType(CurrentMediaType);
DriveSpeedComboBox.ItemsSource = values;
ViewModels.LoggerViewModel.VerboseLogLn("Supported media speeds: {0}", string.Join(",", values));
// Set the selected speed
int speed = UIOptions.GetPreferredDumpSpeedForMediaType(CurrentMediaType);
ViewModels.LoggerViewModel.VerboseLogLn("Setting drive speed to: {0}", speed);
DriveSpeedComboBox.SelectedValue = speed;
}
/// <summary>
/// Begin the dumping process using the given inputs
/// </summary>
private async void StartDumping()
{
// One last check to determine environment, just in case
Env = DetermineEnvironment();
// If still in custom parameter mode, check that users meant to continue or not
if (EnableParametersCheckBox.IsChecked == true)
{
MessageBoxResult result = MessageBox.Show("It looks like you have custom parameters that have not been saved. Would you like to apply those changes before starting to dump?", "Custom Changes", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
EnableParametersCheckBox.IsChecked = false;
ParametersTextBox.IsEnabled = false;
ProcessCustomParameters();
}
else if (result == MessageBoxResult.Cancel)
return;
// If "No", then we continue with the current known environment
}
// Fix the output paths
Env.FixOutputPaths();
try
{
// Validate that the user explicitly wants an inactive drive to be considered for dumping
if (!Env.Drive.MarkedActive)
{
MessageBoxResult mbresult = MessageBox.Show("The currently selected drive does not appear to contain a disc! Are you sure you want to continue?", "Missing Disc", MessageBoxButton.YesNo, MessageBoxImage.Exclamation);
if (mbresult == MessageBoxResult.No || mbresult == MessageBoxResult.Cancel || mbresult == MessageBoxResult.None)
{
ViewModels.LoggerViewModel.VerboseLogLn("Dumping aborted!");
return;
}
}
// If a complete dump already exists
if (Env.FoundAllFiles())
{
MessageBoxResult mbresult = MessageBox.Show("A complete dump already exists! Are you sure you want to overwrite?", "Overwrite?", MessageBoxButton.YesNo, MessageBoxImage.Exclamation);
if (mbresult == MessageBoxResult.No || mbresult == MessageBoxResult.Cancel || mbresult == MessageBoxResult.None)
{
ViewModels.LoggerViewModel.VerboseLogLn("Dumping aborted!");
return;
}
}
StartStopButton.Content = Constants.StopDumping;
CopyProtectScanButton.IsEnabled = false;
StatusLabel.Content = "Beginning dumping process";
ViewModels.LoggerViewModel.VerboseLogLn("Starting dumping process..");
// Get progress indicators
var resultProgress = new Progress<Result>();
resultProgress.ProgressChanged += ProgressUpdated;
var protectionProgress = new Progress<FileProtection>();
protectionProgress.ProgressChanged += ProgressUpdated;
// Run the program with the parameters
Result result = await Env.Run(resultProgress);
// If we didn't execute a dumping command we cannot get submission output
if (!Env.Parameters.IsDumpingCommand())
{
ViewModels.LoggerViewModel.VerboseLogLn("No dumping command was run, submission information will not be gathered.");
StatusLabel.Content = "Execution complete!";
StartStopButton.Content = Constants.StartDumping;
CopyProtectScanButton.IsEnabled = true;
return;
}
if (result)
{
// Verify dump output and save it
result = await Env.VerifyAndSaveDumpOutput(resultProgress,
protectionProgress,
EjectWhenDoneCheckBox.IsChecked,
UIOptions.ResetDriveAfterDump,
(si) =>
{
// lazy initialization
if (discInformationWindow == null)
{
discInformationWindow = new DiscInformationWindow(si);
discInformationWindow.Closed += delegate
{
discInformationWindow = null;
};
}
discInformationWindow.Owner = this;
discInformationWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
discInformationWindow.Load();
return discInformationWindow.ShowDialog();
}
);
}
}
catch
{
// No-op, we don't care what it was
}
finally
{
StartStopButton.Content = Constants.StartDumping;
CopyProtectScanButton.IsEnabled = true;
}
}
#endregion
#region Event Handlers
/// <summary>
/// Handler for AboutMenuItem Click event
/// </summary>
private void AboutClick(object sender, RoutedEventArgs e)
{
MessageBox.Show($"darksabre76 - Project Lead / Backend Design"
+ $"{Environment.NewLine}ReignStumble - Former Project Lead / UI Design"
+ $"{Environment.NewLine}Jakz - Primary Feature Contributor"
+ $"{Environment.NewLine}NHellFire - Feature Contributor", "About", MessageBoxButton.OK, MessageBoxImage.Information);
}
/// <summary>
/// Handler for AppExitMenuItem Click event
/// </summary>
private void AppExitClick(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
/// <summary>
/// Handler for CheckForUpdatesMenuItem Click event
/// </summary>
private void CheckForUpdatesClick(object sender, RoutedEventArgs e)
{
(bool different, string message, string url) = Tools.CheckForNewVersion();
// If we have a new version, put it in the clipboard
if (different)
Clipboard.SetText(url);
MessageBox.Show(message, "Version Update Check", MessageBoxButton.OK, different ? MessageBoxImage.Exclamation : MessageBoxImage.Information);
}
/// <summary>
/// Handler for CopyProtectScanButton Click event
/// </summary>
private void CopyProtectScanButtonClick(object sender, RoutedEventArgs e)
{
ScanAndShowProtection();
}
/// <summary>
/// Handler for DriveLetterComboBox SelectionChanged event
/// </summary>
private void DriveLetterComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
CacheCurrentDiscType();
SetCurrentDiscType();
GetOutputNames(true);
SetSupportedDriveSpeed();
}
/// <summary>
/// Handler for DriveSpeedComboBox SelectionChanged event
/// </summary>
private void DriveSpeedComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
EnsureDiscInformation();
}
/// <summary>
/// Handler for EnableParametersCheckBox Click event
/// </summary>
private void EnableParametersCheckBoxClick(object sender, RoutedEventArgs e)
{
if (EnableParametersCheckBox.IsChecked == true)
ParametersTextBox.IsEnabled = true;
else
{
ParametersTextBox.IsEnabled = false;
ProcessCustomParameters();
}
}
/// <summary>
/// Handler for MediaTypeComboBox SelectionChanged event
/// </summary>
private void MediaTypeComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Only change the media type if the selection and not the list has changed
if (e.RemovedItems.Count == 1 && e.AddedItems.Count == 1)
{
CurrentMediaType = MediaTypeComboBox.SelectedItem as MediaType?;
SetSupportedDriveSpeed();
}
GetOutputNames(false);
EnsureDiscInformation();
}
/// <summary>
/// Handler for MediaScanButton Click event
/// </summary>
private void MediaScanButtonClick(object sender, RoutedEventArgs e)
{
PopulateDrives();
}
/// <summary>
/// Handler for MainWindow Activated event
/// </summary>
private void MainWindowActivated(object sender, EventArgs e)
{
if (logWindow.IsVisible && !this.Topmost)
{
logWindow.Topmost = true;
logWindow.Topmost = false;
}
}
/// <summary>
/// Handler for MainWindow Closing event
/// </summary>
private void MainWindowClosing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (logWindow.IsVisible)
logWindow.Close();
}
/// <summary>
/// Handler for MainWindow PositionChanged event
/// </summary>
private void MainWindowLocationChanged(object sender, EventArgs e)
{
if (logWindow.IsVisible)
logWindow.AdjustPositionToMainWindow();
}
/// <summary>
/// Handler for MainWindow OnContentRendered event
/// </summary>
/// <param name="e"></param>
protected override void OnContentRendered(EventArgs e)
{
base.OnContentRendered(e);
if (alreadyShown)
return;
alreadyShown = true;
if (UIOptions.OpenLogWindowAtStartup)
{
//TODO: this should be bound directly to WindowVisible property in two way fashion
// we need to study how to properly do it in XAML
ShowLogMenuItem.IsChecked = true;
ViewModels.LoggerViewModel.WindowVisible = true;
}
// Populate the list of systems
StatusLabel.Content = "Creating system list, please wait!";
PopulateSystems();
// Populate the list of drives
StatusLabel.Content = "Creating drive list, please wait!";
PopulateDrives();
}
/// <summary>
/// Handler for OptionsWindow OnUpdated event
/// </summary>
public void OnOptionsUpdated()
{
PopulateDrives();
GetOutputNames(false);
SetSupportedDriveSpeed();
EnsureDiscInformation();
}
/// <summary>
/// Handler for OptionsMenuItem Click event
/// </summary>
/// TODO: Re-evaluate this based on Avalonia code
private void OptionsMenuItemClick(object sender, RoutedEventArgs e)
{
// lazy initialization
if (optionsWindow == null)
{
optionsWindow = new OptionsWindow(this, UIOptions);
optionsWindow.Closed += delegate
{
optionsWindow = null;
};
}
optionsWindow.Owner = this;
optionsWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
optionsWindow.Refresh();
optionsWindow.Show();
}
/// <summary>
/// Handler for OutputDirectoryBrowseButton Click event
/// </summary>
private void OutputDirectoryBrowseButtonClick(object sender, RoutedEventArgs e)
{
BrowseFolder();
EnsureDiscInformation();
}
/// <summary>
/// Handler for OutputFilenameTextBox TextInput event
/// </summary>
private void OutputDirectoryTextBoxTextChanged(object sender, TextChangedEventArgs e)
{
EnsureDiscInformation();
}
/// <summary>
/// Handler for OutputFilenameTextBox TextInput event
/// </summary>
private void OutputFilenameTextBoxTextChanged(object sender, TextChangedEventArgs e)
{
EnsureDiscInformation();
}
/// <summary>
/// Handler for Result ProgressChanged event
/// </summary>
private void ProgressUpdated(object sender, Result value)
{
StatusLabel.Content = value.Message;
ViewModels.LoggerViewModel.VerboseLogLn(value.Message);
}
/// <summary>
/// Handler for FileProtection ProgressChanged event
/// </summary>
private void ProgressUpdated(object sender, FileProtection value)
{
string message = $"{value.Percentage * 100:N2}%: {value.Filename} - {value.Protection}";
StatusLabel.Content = message;
ViewModels.LoggerViewModel.VerboseLogLn(message);
}
/// <summary>
/// Handler for StartStopButton Click event
/// </summary>
private void StartStopButtonClick(object sender, RoutedEventArgs e)
{
// Dump or stop the dump
if ((string)StartStopButton.Content == Constants.StartDumping)
{
StartDumping();
}
else if ((string)StartStopButton.Content == Constants.StopDumping)
{
ViewModels.LoggerViewModel.VerboseLogLn("Canceling dumping process...");
Env.CancelDumping();
CopyProtectScanButton.IsEnabled = true;
if (EjectWhenDoneCheckBox.IsChecked == true)
{
ViewModels.LoggerViewModel.VerboseLogLn($"Ejecting disc in drive {Env.Drive.Letter}");
Env.EjectDisc();
}
if (UIOptions.ResetDriveAfterDump)
{
ViewModels.LoggerViewModel.VerboseLogLn($"Resetting drive {Env.Drive.Letter}");
Env.ResetDrive();
}
}
}
/// <summary>
/// Handler for SystemTypeComboBox SelectionChanged event
/// </summary>
private void SystemTypeComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
// If we're on a separator, go to the next item and return
if ((SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem).IsHeader())
{
SystemTypeComboBox.SelectedIndex++;
return;
}
ViewModels.LoggerViewModel.VerboseLogLn("Changed system to: {0}", (SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem).Name);
PopulateMediaType();
GetOutputNames(false);
EnsureDiscInformation();
}
#endregion
#region UI Helpers
/// <summary>
/// Get pixel coordinates based on DPI scaling
/// </summary>
/// <param name="bounds">Rectangle representing the bounds to transform</param>
/// <returns>Rectangle representing the scaled bounds</returns>
private Rectangle GetScaledCoordinates(Rectangle bounds)
{
using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
{
return new Rectangle(
TransformCoordinate(bounds.Left, g.DpiX),
TransformCoordinate(bounds.Top, g.DpiY),
TransformCoordinate(bounds.Width, g.DpiX),
TransformCoordinate(bounds.Height, g.DpiY));
}
}
/// <summary>
/// Transform an individual coordinate using DPI scaling
/// </summary>
/// <param name="coord">Current integer coordinate</param>
/// <param name="dpi">DPI scaling factor</param>
/// <returns>Scaled integer coordinate</returns>
private int TransformCoordinate(int coord, float dpi)
{
return (int)(coord / ((double)dpi / 96));
}
#endregion
}
}

View File

@@ -1,221 +0,0 @@
<Window x:Class="DICUI.Windows.OptionsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DICUI"
mc:Ignorable="d"
Title="Options" Width="515.132" Height="605">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="150"/>
<RowDefinition Height="150"/>
<RowDefinition Height="150"/>
<RowDefinition Height="80"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<GroupBox Grid.Column="0" Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Paths" />
<Grid Margin="10,15,10,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="2.0*" />
<ColumnDefinition Width="0.2*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Aaru Path" />
<TextBox x:Name="AaruPathTextBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=AaruPath}" />
<Button x:Name="AaruPathButton" Grid.Row="0" Grid.Column="2" Height="22" Width="22" Content="..." Click="BrowseForPathClick" />
<Label Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="DiscImageCreator Path" />
<TextBox x:Name="CreatorPathTextBox" Grid.Row="1" Grid.Column="1" Height="22" HorizontalAlignment="Stretch"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=CreatorPath}" />
<Button x:Name="CreatorPathButton" Grid.Row="1" Grid.Column="2" Height="22" Width="22" Content="..." Click="BrowseForPathClick" />
<!--
<Label Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="DD Path" />
<TextBox x:Name="DDPathTextBox" Grid.Row="1" Grid.Column="1" Height="22" HorizontalAlignment="Stretch"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=DDPath}" />
<Button x:Name="DDPathButton" Grid.Row="1" Grid.Column="2" Height="22" Width="22" Content="..." Click="BrowseForPathClick" />
-->
<Label Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="subdump Path" />
<TextBox x:Name="SubDumpPathTextBox" Grid.Row="2" Grid.Column="1" Height="22" HorizontalAlignment="Stretch"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=SubDumpPath}" />
<Button x:Name="SubDumpPathButton" Grid.Row="2" Grid.Column="2" Height="22" Width="22" Content="..." Click="BrowseForPathClick"/>
<Label Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Default Output Path" />
<TextBox x:Name="DefaultOutputPathTextBox" Grid.Row="3" Grid.Column="1" Height="22" HorizontalAlignment="Stretch"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=DefaultOutputPath}" />
<Button x:Name="DefaultOutputPathButton" Grid.Row="3" Grid.Column="2" Height="22" Width="22" Content="..." Click="BrowseForPathClick" />
</Grid>
<GroupBox Grid.Row="1" Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Preferred Dump Speed">
<Grid Height="100">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="2.0*"/>
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="CD-ROM" />
<Slider x:Name="DumpSpeedCDSlider" Grid.Row="0" Grid.Column="1" Minimum="1" Maximum="72" IsSnapToTickEnabled="True" TickPlacement="BottomRight"
Ticks="{Binding Source={x:Static local:Constants.SpeedsForCDAsCollection}}"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Value="{Binding Path=PreferredDumpSpeedCD}" />
<TextBox x:Name="DumpSpeedCDTextBox" Grid.Row="0" Grid.Column="2" Width="22" Height="22" TextAlignment="Center" IsReadOnly="True" IsReadOnlyCaretVisible="False" VerticalAlignment="Center"
Text="{Binding ElementName=DumpSpeedCDSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}" Background="LightGray" Foreground="Gray"/>
<Label Grid.Row="1" Grid.Column="0" Content="DVD-ROM" />
<Slider x:Name="DumpSpeedDVDSlider" Grid.Row="1" Grid.Column="1" Minimum="1" Maximum="24" IsSnapToTickEnabled="True" TickPlacement="BottomRight"
Ticks="{Binding Source={x:Static local:Constants.SpeedsForDVDAsCollection}}"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Value="{Binding Path=PreferredDumpSpeedDVD}" />
<TextBox x:Name="DumpSpeedDVDTextBox" Grid.Row="1" Grid.Column="2" Width="22" Height="22" TextAlignment="Center" IsReadOnly="True" IsReadOnlyCaretVisible="False" VerticalAlignment="Center"
Text="{Binding ElementName=DumpSpeedDVDSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}" Background="LightGray" Foreground="Gray"/>
<Label Grid.Row="2" Grid.Column="0" Content="BD-ROM" />
<Slider x:Name="DumpSpeedBDSlider" Grid.Row="2" Grid.Column="1" Minimum="1" Maximum="16" IsSnapToTickEnabled="True" TickPlacement="BottomRight"
Ticks="{Binding Source={x:Static local:Constants.SpeedsForBDAsCollection}}"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Value="{Binding Path=PreferredDumpSpeedBD}" />
<TextBox x:Name="DumpSpeedBDTextBox" Grid.Row="2" Grid.Column="2" Width="22" Height="22" TextAlignment="Center" IsReadOnly="True" IsReadOnlyCaretVisible="False" VerticalAlignment="Center"
Text="{Binding ElementName=DumpSpeedBDSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}" Background="LightGray" Foreground="Gray"/>
</Grid>
</GroupBox>
<GroupBox Grid.Row="2" Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Options" Padding="10">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<CheckBox Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Content="Quiet Mode"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=QuietMode}"
ToolTip="Disable DiscImageCreator sounds" Margin="0,4"
/>
<CheckBox Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" Content="Paranoid Mode"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=ParanoidMode}"
ToolTip="Enable pedantic and super-safe flags" Margin="0,4"
/>
<Label Grid.Row="0" Grid.Column="2" Content="Reread Tries:" VerticalAlignment="Center" HorizontalAlignment="Right"/>
<TextBox Grid.Row="0" Grid.Column="3" VerticalAlignment="Center"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=RereadAmountForC2}"
ToolTip="Specifies how many rereads are attempted on C2 error"
/>
<CheckBox Grid.Column="0" Grid.Row="1" VerticalAlignment="Center" Content="Protection Scan"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=ScanForProtection}"
ToolTip="Enable automatic checking for copy protection on dumped media" Margin="0,4,0,0"
/>
<CheckBox Grid.Column="1" Grid.Row="1" VerticalAlignment="Center" Content="Skip Type Detect"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=SkipMediaTypeDetection}"
ToolTip="Disable trying to guess media type inserted (may improve performance at startup)" Margin="0,4"
/>
<CheckBox Grid.Row="1" Grid.Column="2" VerticalAlignment="Center" Content="Add Placeholders"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=AddPlaceholders}"
ToolTip="Enable adding placeholder text in the submissioninfo output for required and optional fields" Margin="0,4"
/>
<CheckBox Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Content="Show Disc Info"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=PromptForDiscInformation}"
ToolTip="Enable showing the disc information output after dumping" Margin="0,4"
/>
<CheckBox Grid.Row="2" Grid.Column="1" VerticalAlignment="Center" Content="No Fixed Drives"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=IgnoreFixedDrives}"
ToolTip="Ignore hard drives and other fixed drives" Margin="0,4"
/>
<CheckBox Grid.Row="2" Grid.Column="2" VerticalAlignment="Center" Content="Reset After Dump"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
IsChecked="{Binding Path=ResetDriveAfterDump}"
ToolTip="Reset disc drives after dumping; useful for some older machines" Margin="0,4"
/>
</Grid>
</GroupBox>
<GroupBox Grid.Row="3" Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Redump Login" Padding="10">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1.2*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Username" />
<TextBox x:Name="RedumpUsernameTextBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=Username}" />
<Label Grid.Row="0" Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Password" />
<PasswordBox x:Name="RedumpPasswordBox" Grid.Row="0" Grid.Column="3" Height="22" HorizontalAlignment="Stretch" PasswordChar="*" />
<Button x:Name="RedumpLoginTestButton" Grid.Row="0" Grid.Column="5" Height="22" Width="80" Content="Test Login" Click="OnRedumpTestClick" />
</Grid>
</GroupBox>
<Grid Height="22" Grid.Row="4" Grid.Column="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Button x:Name="AcceptButton" Grid.Row="0" Grid.Column="1" Height="22" Width="80" Content="Accept" Click="OnAcceptClick" />
<Button x:Name="CancelButton" Grid.Row="0" Grid.Column="2" Height="22" Width="80" Content="Cancel" Click="OnCancelClick" />
</Grid>
</Grid>
</Window>

View File

@@ -1,137 +0,0 @@
using System;
using System.IO;
using System.Windows;
using System.Windows.Forms;
using DICUI.Web;
using Button = System.Windows.Controls.Button;
using TextBox = System.Windows.Controls.TextBox;
namespace DICUI.Windows
{
/// <summary>
/// Interaction logic for OptionsWindow.xaml
/// </summary>
public partial class OptionsWindow : Window
{
private readonly MainWindow _mainWindow;
private readonly UIOptions _uiOptions;
public OptionsWindow(MainWindow mainWindow, UIOptions options)
{
InitializeComponent();
_mainWindow = mainWindow;
_uiOptions = options;
}
private OpenFileDialog CreateOpenFileDialog()
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.InitialDirectory = AppDomain.CurrentDomain.BaseDirectory;
dialog.Filter = "Executables (*.exe)|*.exe";
dialog.FilterIndex = 0;
dialog.RestoreDirectory = true;
return dialog;
}
private FolderBrowserDialog CreateFolderBrowserDialog()
{
FolderBrowserDialog dialog = new FolderBrowserDialog();
return dialog;
}
private TextBox TextBoxForPathSetting(string name)
{
return FindName(name + "TextBox") as TextBox;
}
private void BrowseForPathClick(object sender, EventArgs e)
{
Button button = sender as Button;
// strips button prefix to obtain the setting name
string pathSettingName = button.Name.Substring(0, button.Name.IndexOf("Button"));
// TODO: hack for now, then we'll see
bool shouldBrowseForPath = pathSettingName == "DefaultOutputPath";
CommonDialog dialog = shouldBrowseForPath ? (CommonDialog)CreateFolderBrowserDialog() : CreateOpenFileDialog();
using (dialog)
{
DialogResult result = dialog.ShowDialog();
if (result == System.Windows.Forms.DialogResult.OK)
{
string path;
bool exists;
if (shouldBrowseForPath)
{
path = (dialog as FolderBrowserDialog).SelectedPath;
exists = Directory.Exists(path);
}
else
{
path = (dialog as OpenFileDialog).FileName;
exists = File.Exists(path);
}
if (exists)
{
TextBoxForPathSetting(pathSettingName).Text = path;
}
else
{
System.Windows.MessageBox.Show(
"Specified path doesn't exists!",
"Error",
MessageBoxButton.OK,
MessageBoxImage.Error
);
}
}
}
}
public void Refresh()
{
// Handle non-bindable fields
RedumpPasswordBox.Password = _uiOptions.Options.Password;
}
#region Event Handlers
private void OnAcceptClick(object sender, EventArgs e)
{
// Handle non-bindable fields
_uiOptions.Options.Password = RedumpPasswordBox.Password;
_uiOptions.Save();
Hide();
_mainWindow.OnOptionsUpdated();
}
private void OnCancelClick(object sender, EventArgs e)
{
// just hide the window and don't care
Hide();
}
/// <summary>
/// Test Redump credentials for validity
/// </summary>
private void OnRedumpTestClick(object sender, EventArgs e)
{
using (RedumpWebClient wc = new RedumpWebClient())
{
if (wc.Login(RedumpUsernameTextBox.Text, RedumpPasswordBox.Password))
System.Windows.MessageBox.Show("Redump login credentials accepted!", "Success", MessageBoxButton.OK, MessageBoxImage.Information);
else
System.Windows.MessageBox.Show("Redump login credentials denied!", "Failure", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
#endregion
}
}

View File

@@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
DICUI Copyright (C) 2018 ReignStumble
MPF Copyright (C) 2018 ReignStumble
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.

View File

@@ -0,0 +1,51 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;netcoreapp3.1</TargetFrameworks>
<PlatformTarget>x86</PlatformTarget>
<OutputType>Exe</OutputType>
<Title>MPF Check</Title>
<AssemblyName>MPF.Check</AssemblyName>
<Description>Validator for various dumping programs</Description>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2021</Copyright>
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
<Version>2.1</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<FileVersion>$(Version)</FileVersion>
<IncludeSource>true</IncludeSource>
<IncludeSymbols>true</IncludeSymbols>
</PropertyGroup>
<PropertyGroup>
<NrtRevisionFormat>$(Version)-{chash:8}</NrtRevisionFormat>
<NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes>
<NrtShowRevision>false</NrtShowRevision>
</PropertyGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="1.7.0" GeneratePathProperty="true">
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Content Include="$(PkgBurnOutSharp)\content\**" PackagePath="contentFiles\any\any;content" CopyToOutputDirectory="Always" PackageCopyToOutput="true" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj">
<Project>{51ab0928-13f9-44bf-a407-b6957a43a056}</Project>
<Name>MPF.Library</Name>
</ProjectReference>
</ItemGroup>
</Project>

View File

@@ -1,11 +1,11 @@
using System;
using System.IO;
using BurnOutSharp;
using DICUI.Data;
using DICUI.Utilities;
using DICUI.Web;
using MPF.Data;
using MPF.Redump;
using MPF.Utilities;
namespace DICUI.Check
namespace MPF.Check
{
public class Program
{
@@ -65,7 +65,7 @@ namespace DICUI.Check
string username = null, password = null;
string internalProgram = "DiscImageCreator";
string path = string.Empty;
bool scan = false;
bool scan = false, compress = false;
// Loop through and process options
int startIndex = 2;
@@ -113,6 +113,12 @@ namespace DICUI.Check
scan = true;
}
// Compress log and extraneous files
else if (args[startIndex].StartsWith("-z") || args[startIndex].StartsWith("--zip"))
{
compress = true;
}
// Default, we fall out
else
{
@@ -123,7 +129,7 @@ namespace DICUI.Check
// Make new Progress objects
var resultProgress = new Progress<Result>();
resultProgress.ProgressChanged += ProgressUpdated;
var protectionProgress = new Progress<FileProtection>();
var protectionProgress = new Progress<ProtectionProgress>();
protectionProgress.ProgressChanged += ProgressUpdated;
// If credentials are invalid, alert the user
@@ -131,10 +137,13 @@ namespace DICUI.Check
{
using (RedumpWebClient wc = new RedumpWebClient())
{
if (wc.Login(username, password))
bool? loggedIn = wc.Login(username, password);
if (loggedIn == true)
Console.WriteLine("Redump username and password accepted!");
else
else if (loggedIn == false)
Console.WriteLine("Redump username and password denied!");
else
Console.WriteLine("An error occurred validating your crendentials!");
}
}
@@ -152,15 +161,15 @@ namespace DICUI.Check
string filepath = Path.GetFullPath(args[i].Trim('"'));
// Now populate an environment
// TODO: Replace this with Dictionary constructor
var options = new Options
{
InternalProgram = internalProgram,
InternalProgram = Converters.ToInternalProgram(internalProgram),
ScanForProtection = scan && !string.IsNullOrWhiteSpace(path),
PromptForDiscInformation = false,
CompressLogFiles = compress,
Username = username,
Password = password,
RedumpUsername = username,
RedumpPassword = password,
};
Drive drive = null;
@@ -168,7 +177,6 @@ namespace DICUI.Check
drive = new Drive(null, new DriveInfo(path));
var env = new DumpEnvironment(options, "", filepath, drive, knownSystem, mediaType, null);
env.FixOutputPaths();
// Finally, attempt to do the output dance
var result = env.VerifyAndSaveDumpOutput(resultProgress, protectionProgress).ConfigureAwait(false).GetAwaiter().GetResult();
@@ -177,7 +185,7 @@ namespace DICUI.Check
}
/// <summary>
/// Display help for DICUI.Check
/// Display help for MPF.Check
/// </summary>
/// <param name="error">Error string to prefix the help text with</param>
private static void DisplayHelp(string error = null)
@@ -186,7 +194,7 @@ namespace DICUI.Check
Console.WriteLine(error);
Console.WriteLine("Usage:");
Console.WriteLine("DICUI.Check.exe <mediatype> <system> [options] </path/to/output.bin> ...");
Console.WriteLine("MPF.Check.exe <mediatype> <system> [options] </path/to/output.bin> ...");
Console.WriteLine();
Console.WriteLine("Standalone Options:");
Console.WriteLine("-h, -? Show this help text");
@@ -199,6 +207,7 @@ namespace DICUI.Check
Console.WriteLine("-u, --use <program> Dumping program output type");
Console.WriteLine("-p, --path <drivepath> Physical drive path for additional checks");
Console.WriteLine("-s, --scan Enable copy protection scan (requires --path)");
Console.WriteLine("-z, --zip Enable log file compression");
Console.WriteLine();
}
@@ -258,7 +267,7 @@ namespace DICUI.Check
/// <summary>
/// Simple process counter to write to console
/// </summary>
private static void ProgressUpdated(object sender, FileProtection value)
private static void ProgressUpdated(object sender, ProtectionProgress value)
{
Console.WriteLine($"{value.Percentage * 100:N2}%: {value.Filename} - {value.Protection}");
}

View File

@@ -1,6 +1,6 @@
{
"profiles": {
"DICUI.Check": {
"MPF.Check": {
"commandName": "Project"
}
}

View File

@@ -1,10 +1,12 @@
namespace DICUI.Aaru
namespace MPF.Aaru
{
/// <summary>
/// Top-level commands for Aaru
/// </summary>
public static class CommandStrings
{
public const string NONE = "";
// Database Family
public const string DatabasePrefixShort = "db";
public const string DatabasePrefixLong = "database";

View File

@@ -0,0 +1,22 @@
using MPF.Data;
namespace MPF.Aaru
{
public static class Converters
{
#region Cross-enumeration conversions
/// <summary>
/// Get the default extension for a given disc type
/// </summary>
/// <param name="type">MediaType value to check</param>
/// <returns>Valid extension (with leading '.'), null on error</returns>
public static string Extension(MediaType? type)
{
// Aaru has a single, unified output format by default
return ".aaruf";
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
using System.Runtime.CompilerServices;
// Anything marked as internal can be used by the test methods
[assembly: InternalsVisibleTo("DICUI.Test")]
[assembly: InternalsVisibleTo("MPF.Test")]

View File

@@ -1,166 +1,62 @@
using System;
using System.Collections.Generic;
using System.IO;
using DICUI.Data;
using DICUI.Utilities;
using DICUI.Web;
using System.Linq;
using System.Text.RegularExpressions;
using MPF.Data;
namespace DICUI.CleanRip
namespace MPF.CleanRip
{
/// <summary>
/// Represents a generic set of CleanRip parameters
/// </summary>
public class Parameters : BaseParameters
{
/// <summary>
/// Populate a Parameters object from a param string
/// </summary>
/// <param name="parameters">String possibly representing a set of parameters</param>
public Parameters(string parameters)
: base(parameters)
{
this.InternalProgram = InternalProgram.CleanRip;
}
#region Metadata
/// <summary>
/// Generate parameters based on a set of known inputs
/// </summary>
/// <param name="system">KnownSystem value to use</param>
/// <param name="type">MediaType value to use</param>
/// <param name="driveLetter">Drive letter to use</param>
/// <param name="filename">Filename to use</param>
/// <param name="driveSpeed">Drive speed to use</param>
/// <param name="paranoid">Enable paranoid mode (safer dumping)</param>
/// <param name="quietMode">Enable quiet mode (no beeps)</param>
/// <param name="retryCount">User-defined reread count</param>
public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, bool paranoid, bool quietMode, int retryCount)
: base(system, type, driveLetter, filename, driveSpeed, paranoid, quietMode, retryCount)
/// <inheritdoc/>
public override InternalProgram InternalProgram => InternalProgram.CleanRip;
#endregion
/// <inheritdoc/>
public Parameters(string parameters) : base(parameters) { }
/// <inheritdoc/>
public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
: base(system, type, driveLetter, filename, driveSpeed, options)
{
}
/// <summary>
/// Blindly generate a parameter string based on the inputs
/// </summary>
/// <returns>Correctly formatted parameter string, null on error</returns>
public override string GenerateParameters() => null;
#region BaseParameters Implementations
/// <summary>
/// Get the input path from the implementation
/// </summary>
/// <returns>String representing the path, null on error</returns>
public override string InputPath() => null;
/// <summary>
/// Get the output path from the implementation
/// </summary>
/// <returns>String representing the path, null on error</returns>
public override string OutputPath() => null;
/// <summary>
/// Get the processing speed from the implementation
/// </summary>
/// <returns>int? representing the speed, null on error</returns>
public override int? GetSpeed() => null;
/// <summary>
/// Set the processing speed int the implementation
/// </summary>
/// <param name="speed">int? representing the speed</param>
public override void SetSpeed(int? speed) { }
/// <summary>
/// Get the MediaType from the current set of parameters
/// </summary>
/// <returns>MediaType value if successful, null on error</returns>
public override MediaType? GetMediaType() => null;
/// <summary>
/// Gets if the current command is considered a dumping command or not
/// </summary>
/// <returns>True if it's a dumping command, false otherwise</returns>
public override bool IsDumpingCommand() => true;
/// <summary>
/// Reset all special variables to have default values
/// </summary>
protected override void ResetValues() { }
/// <summary>
/// Set default parameters for a given system and media type
/// </summary>
/// <param name="system">KnownSystem value to use</param>
/// <param name="type">MediaType value to use</param>
/// <param name="driveLetter">Drive letter to use</param>
/// <param name="filename">Filename to use</param>
/// <param name="driveSpeed">Drive speed to use</param>
/// <param name="paranoid">Enable paranoid mode (safer dumping)</param>
/// <param name="retryCount">User-defined reread count</param>
protected override void SetDefaultParameters(
KnownSystem? system,
MediaType? type,
char driveLetter,
string filename,
int? driveSpeed,
bool paranoid,
int retryCount)
/// <inheritdoc/>
public override (bool, List<string>) CheckAllOutputFilesExist(string basePath, bool preCheck)
{
}
/// <summary>
/// Scan a possible parameter string and populate whatever possible
/// </summary>
/// <param name="parameters">String possibly representing parameters</param>
/// <returns></returns>
protected override bool ValidateAndSetParameters(string parameters) => true;
/// <summary>
/// Validate if all required output files exist
/// </summary>
/// <param name="basePath">Base filename and path to use for checking</param>
/// <param name="system">KnownSystem type representing the media</param>
/// <param name="type">MediaType type representing the media</param>
/// <param name="progress">Optional result progress callback</param>
/// <returns></returns>
public override bool CheckAllOutputFilesExist(string basePath, KnownSystem? system, MediaType? type, IProgress<Result> progress = null)
{
string missingFiles = string.Empty;
switch (type)
List<string> missingFiles = new List<string>();
switch (this.Type)
{
case MediaType.DVD: // Only added here to help users; not strictly correct
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
if (!File.Exists($"{basePath}-dumpinfo.txt"))
missingFiles += $";{basePath}-dumpinfo.txt";
if (!File.Exists($"{basePath}.bca"))
missingFiles += $";{basePath}.bca";
if (!File.Exists($"{basePath}_logs.zip") || !preCheck)
{
if (!File.Exists($"{basePath}-dumpinfo.txt"))
missingFiles.Add($"{basePath}-dumpinfo.txt");
if (!File.Exists($"{basePath}.bca"))
missingFiles.Add($"{basePath}.bca");
}
break;
default:
return false;
return (false, missingFiles);
}
// Use the missing files list as an indicator
if (string.IsNullOrEmpty(missingFiles))
{
return true;
}
else
{
progress?.Report(Result.Failure($"The following files were missing: {missingFiles.TrimStart(';')}"));
return false;
}
return (!missingFiles.Any(), missingFiles);
}
/// <summary>
/// Generate a SubmissionInfo for the output files
/// </summary>
/// <param name="info">Base submission info to fill in specifics for</param>
/// <param name="basePath">Base filename and path to use for checking</param>
/// <param name="system">KnownSystem type representing the media</param>
/// <param name="type">MediaType type representing the media</param>
/// <param name="drive">Drive representing the disc to get information from</param>
/// <returns></returns>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, KnownSystem? system, MediaType? type, Drive drive)
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive, bool includeArtifacts)
{
info.TracksAndWriteOffsets.ClrMameProData = GetCleanripDatfile(basePath + ".iso", basePath + "-dumpinfo.txt");
@@ -178,15 +74,15 @@ namespace DICUI.CleanRip
}
// Extract info based generically on MediaType
switch (type)
switch (this.Type)
{
case MediaType.DVD: // Only added here to help users; not strictly correct
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
if (File.Exists(basePath + ".bca"))
info.Extras.BCA = GetFullFile(basePath + ".bca", true);
info.Extras.BCA = GetBCA(basePath + ".bca");
if (GetGameCubeWiiInformation(basePath + "-dumpinfo.txt", out Region? gcRegion, out string gcVersion))
if (GetGameCubeWiiInformation(basePath + "-dumpinfo.txt", out RedumpRegion? gcRegion, out string gcVersion))
{
info.CommonDiscInfo.Region = gcRegion ?? info.CommonDiscInfo.Region;
info.VersionAndEditions.Version = gcVersion ?? info.VersionAndEditions.Version;
@@ -194,10 +90,65 @@ namespace DICUI.CleanRip
break;
}
// Fill in any artifacts that exist, Base64-encoded, if we need to
if (includeArtifacts)
{
if (File.Exists(basePath + ".bca"))
info.Artifacts["bca"] = GetBase64(GetFullFile(basePath + ".bca", binary: true));
if (File.Exists(basePath + "-dumpinfo.txt"))
info.Artifacts["dumpinfo"] = GetBase64(GetFullFile(basePath + "-dumpinfo.txt"));
}
}
/// <inheritdoc/>
public override List<string> GetLogFilePaths(string basePath)
{
List<string> logFiles = new List<string>();
switch (this.Type)
{
case MediaType.DVD: // Only added here to help users; not strictly correct
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
if (File.Exists($"{basePath}-dumpinfo.txt"))
logFiles.Add($"{basePath}-dumpinfo.txt");
if (File.Exists($"{basePath}.bca"))
logFiles.Add($"{basePath}.bca");
break;
}
return logFiles;
}
#endregion
#region Information Extraction Methods
/// <summary>
/// Get the hex contents of the BCA file
/// </summary>
/// <param name="bcaPath">Path to the BCA file associated with the dump</param>
/// <returns>BCA data as a hex string if possible, null on error</returns>
/// <remarks>https://stackoverflow.com/questions/9932096/add-separator-to-string-at-every-n-characters</remarks>
private static string GetBCA(string bcaPath)
{
// If the file doesn't exist, we can't get the info
if (!File.Exists(bcaPath))
return null;
try
{
string hex = GetFullFile(bcaPath, true);
return Regex.Replace(hex, ".{32}", "$0\n");
}
catch
{
// We don't care what the error was right now
return null;
}
}
/// <summary>
/// Get a formatted datfile from the cleanrip output, if possible
/// </summary>
@@ -252,7 +203,7 @@ namespace DICUI.CleanRip
/// <param name="region">Output region, if possible</param>
/// <param name="version">Output internal version of the game</param>
/// <returns></returns>
private static bool GetGameCubeWiiInformation(string dumpinfo, out Region? region, out string version)
private static bool GetGameCubeWiiInformation(string dumpinfo, out RedumpRegion? region, out string version)
{
region = null; version = null;
@@ -287,49 +238,49 @@ namespace DICUI.CleanRip
switch (serial[3])
{
case 'A':
region = Region.World;
region = RedumpRegion.World;
break;
case 'D':
region = Region.Germany;
region = RedumpRegion.Germany;
break;
case 'E':
region = Region.USA;
region = RedumpRegion.USA;
break;
case 'F':
region = Region.France;
region = RedumpRegion.France;
break;
case 'I':
region = Region.Italy;
region = RedumpRegion.Italy;
break;
case 'J':
region = Region.Japan;
region = RedumpRegion.Japan;
break;
case 'K':
region = Region.Korea;
region = RedumpRegion.Korea;
break;
case 'L':
region = Region.Europe; // Japanese import to Europe
region = RedumpRegion.Europe; // Japanese import to Europe
break;
case 'M':
region = Region.Europe; // American import to Europe
region = RedumpRegion.Europe; // American import to Europe
break;
case 'N':
region = Region.USA; // Japanese import to USA
region = RedumpRegion.USA; // Japanese import to USA
break;
case 'P':
region = Region.Europe;
region = RedumpRegion.Europe;
break;
case 'R':
region = Region.Russia;
region = RedumpRegion.Russia;
break;
case 'S':
region = Region.Spain;
region = RedumpRegion.Spain;
break;
case 'Q':
region = Region.Korea; // Korea with Japanese language
region = RedumpRegion.Korea; // Korea with Japanese language
break;
case 'T':
region = Region.Korea; // Korea with English language
region = RedumpRegion.Korea; // Korea with English language
break;
case 'X':
region = null; // Not a real region code

View File

@@ -0,0 +1,238 @@
using System;
using System.Collections.Generic;
using System.IO;
/// <remarks>
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
/// </remarks>
namespace MPF.CueSheets
{
/// <summary>
/// The audio or data files filetype
/// </summary>
public enum CueFileType
{
/// <summary>
/// Intel binary file (least significant byte first). Use for data files.
/// </summary>
BINARY,
/// <summary>
/// Motorola binary file (most significant byte first). Use for data files.
/// </summary>
MOTOROLA,
/// <summary>
/// Audio AIFF file (44.1KHz 16-bit stereo)
/// </summary>
AIFF,
/// <summary>
/// Audio WAVE file (44.1KHz 16-bit stereo)
/// </summary>
WAVE,
/// <summary>
/// Audio MP3 file (44.1KHz 16-bit stereo)
/// </summary>
MP3,
}
/// <summary>
/// Represents a single FILE in a cuesheet
/// </summary>
public class CueFile
{
/// <summary>
/// filename
/// </summary>
public string FileName { get; set; }
/// <summary>
/// filetype
/// </summary>
public CueFileType FileType { get; set; }
/// <summary>
/// List of TRACK in FILE
/// </summary>
public List<CueTrack> Tracks { get; set; }
/// <summary>
/// Create an empty FILE
/// </summary>
public CueFile()
{
}
/// <summary>
/// Fill a FILE from an array of lines
/// </summary>
/// <param name="fileName">File name to set</param>
/// <param name="fileType">File type to set</param>
/// <param name="cueLines">Lines array to pull from</param>
/// <param name="i">Reference to index in array</param>
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
public CueFile(string fileName, string fileType, string[] cueLines, ref int i, bool throwOnError = false)
{
if (cueLines == null)
{
if (throwOnError)
throw new ArgumentNullException(nameof(cueLines));
return;
}
else if (i < 0 || i > cueLines.Length)
{
if (throwOnError)
throw new IndexOutOfRangeException();
return;
}
// Set the current fields
this.FileName = fileName.Trim('"');
this.FileType = GetFileType(fileType);
// Increment to start
i++;
for (; i < cueLines.Length; i++)
{
string line = cueLines[i].Trim();
string[] splitLine = line.Split(' ');
// If we have an empty line, we skip
if (string.IsNullOrWhiteSpace(line))
continue;
switch (splitLine[0])
{
// Read comments
case "REM":
// We ignore all comments for now
break;
// Read track information
case "TRACK":
if (splitLine.Length < 3)
{
if (throwOnError)
throw new FormatException($"TRACK line malformed: {line}");
continue;
}
if (this.Tracks == null)
this.Tracks = new List<CueTrack>();
var track = new CueTrack(splitLine[1], splitLine[2], cueLines, ref i);
if (track == default)
{
if (throwOnError)
throw new FormatException($"TRACK line malformed: {line}");
continue;
}
this.Tracks.Add(track);
break;
// Default means return
default:
i--;
return;
}
}
}
/// <summary>
/// Write the FILE out to a stream
/// </summary>
/// <param name="sw">StreamWriter to write to</param>
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
public void Write(StreamWriter sw, bool throwOnError = false)
{
// If we don't have any tracks, it's invalid
if (this.Tracks == null)
{
if (throwOnError)
throw new ArgumentNullException(nameof(this.Tracks));
return;
}
else if (this.Tracks.Count == 0)
{
if (throwOnError)
throw new ArgumentException("No tracks provided to write");
return;
}
sw.WriteLine($"FILE \"{this.FileName}\" {FromFileType(this.FileType)}");
foreach (var track in Tracks)
{
track.Write(sw);
}
}
/// <summary>
/// Get the file type from a given string
/// </summary>
/// <param name="fileType">String to get value from</param>
/// <returns>CueFileType, if possible</returns>
private CueFileType GetFileType(string fileType)
{
switch (fileType.ToLowerInvariant())
{
case "binary":
return CueFileType.BINARY;
case "motorola":
return CueFileType.MOTOROLA;
case "aiff":
return CueFileType.AIFF;
case "wave":
return CueFileType.WAVE;
case "mp3":
return CueFileType.MP3;
default:
return CueFileType.BINARY;
}
}
/// <summary>
/// Get the string from a given file type
/// </summary>
/// <param name="fileType">CueFileType to get value from</param>
/// <returns>String, if possible (default BINARY)</returns>
private string FromFileType(CueFileType fileType)
{
switch (fileType)
{
case CueFileType.BINARY:
return "BINARY";
case CueFileType.MOTOROLA:
return "MOTOROLA";
case CueFileType.AIFF:
return "AIFF";
case CueFileType.WAVE:
return "WAVE";
case CueFileType.MP3:
return "MP3";
default:
return string.Empty;
}
}
}
}

View File

@@ -0,0 +1,163 @@
using System;
using System.IO;
using System.Linq;
/// <remarks>
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
/// </remarks>
namespace MPF.CueSheets
{
/// <summary>
/// Represents a single INDEX in a TRACK
/// </summary>
public class CueIndex
{
/// <summary>
/// INDEX number, between 0 and 99
/// </summary>
public int Index { get; set; }
/// <summary>
/// Starting time of INDEX in minutes
/// </summary>
public int Minutes { get; set; }
/// <summary>
/// Starting time of INDEX in seconds
/// </summary>
/// <remarks>There are 60 seconds in a minute</remarks>
public int Seconds { get; set; }
/// <summary>
/// Starting time of INDEX in frames.
/// </summary>
/// <remarks>There are 75 frames per second</remarks>
public int Frames { get; set; }
/// <summary>
/// Create an empty INDEX
/// </summary>
public CueIndex()
{
}
/// <summary>
/// Fill a INDEX from an array of lines
/// </summary>
/// <param name="index">Index to set</param>
/// <param name="startTime">Start time to set</param>
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
public CueIndex(string index, string startTime, bool throwOnError = false)
{
// Set the current fields
if (!int.TryParse(index, out int parsedIndex))
{
if (throwOnError)
throw new ArgumentException($"Index was not a number: {index}");
return;
}
else if (parsedIndex < 0 || parsedIndex > 99)
{
if (throwOnError)
throw new IndexOutOfRangeException($"Index must be between 0 and 99: {parsedIndex}");
return;
}
// Ignore empty lines
if (string.IsNullOrWhiteSpace(startTime))
{
if (throwOnError)
throw new ArgumentException("Start time was null or whitespace");
return;
}
// Ignore lines that don't contain the correct information
if (startTime.Length != 8 || startTime.Count(c => c == ':') != 2)
{
if (throwOnError)
throw new FormatException($"Start time was not in a recognized format: {startTime}");
return;
}
// Split the line
string[] splitTime = startTime.Split(':');
if (splitTime.Length != 3)
{
if (throwOnError)
throw new FormatException($"Start time was not in a recognized format: {startTime}");
return;
}
// Parse the lengths
int[] lengthSegments = new int[3];
// Minutes
if (!int.TryParse(splitTime[0], out lengthSegments[0]))
{
if (throwOnError)
throw new FormatException($"Minutes segment was not a number: {splitTime[0]}");
return;
}
else if (lengthSegments[0] < 0)
{
if (throwOnError)
throw new IndexOutOfRangeException($"Minutes segment must be 0 or greater: {lengthSegments[0]}");
return;
}
// Seconds
if (!int.TryParse(splitTime[1], out lengthSegments[1]))
{
if (throwOnError)
throw new FormatException($"Seconds segment was not a number: {splitTime[1]}");
return;
}
else if (lengthSegments[1] < 0 || lengthSegments[1] > 60)
{
if (throwOnError)
throw new IndexOutOfRangeException($"Seconds segment must be between 0 and 60: {lengthSegments[1]}");
return;
}
// Frames
if (!int.TryParse(splitTime[2], out lengthSegments[2]))
{
if (throwOnError)
throw new FormatException($"Frames segment was not a number: {splitTime[2]}");
return;
}
else if (lengthSegments[2] < 0 || lengthSegments[2] > 75)
{
if (throwOnError)
throw new IndexOutOfRangeException($"Frames segment must be between 0 and 75: {lengthSegments[2]}");
return;
}
// Set the values
this.Index = parsedIndex;
this.Minutes = lengthSegments[0];
this.Seconds = lengthSegments[1];
this.Frames = lengthSegments[2];
}
/// <summary>
/// Write the INDEX out to a stream
/// </summary>
/// <param name="sw">StreamWriter to write to</param>
public void Write(StreamWriter sw)
{
sw.WriteLine($" INDEX {this.Index:D2} {this.Minutes:D2}:{this.Seconds:D2}:{this.Frames:D2}");
}
}
}

View File

@@ -0,0 +1,250 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
/// <remarks>
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
/// </remarks>
namespace MPF.CueSheets
{
/// <summary>
/// Represents a single cuesheet
/// </summary>
public class CueSheet
{
/// <summary>
/// CATALOG
/// </summary>
public string Catalog { get; set; }
/// <summary>
/// CDTEXTFILE
/// </summary>
public string CdTextFile { get; set; }
/// <summary>
/// PERFORMER
/// </summary>
public string Performer { get; set; }
/// <summary>
/// SONGWRITER
/// </summary>
public string Songwriter { get; set; }
/// <summary>
/// TITLE
/// </summary>
public string Title { get; set; }
/// <summary>
/// List of FILE in cuesheet
/// </summary>
public List<CueFile> Files { get; set; }
/// <summary>
/// Create an empty cuesheet
/// </summary>
public CueSheet()
{
}
/// <summary>
/// Create a cuesheet from a file, if possible
/// </summary>
/// <param name="filename"></param>
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
public CueSheet(string filename, bool throwOnError = false)
{
// Check that the file exists
if (!File.Exists(filename))
return;
// Check the extension
string ext = Path.GetExtension(filename).TrimStart('.');
if (!string.Equals(ext, "cue", StringComparison.OrdinalIgnoreCase)
&& !string.Equals(ext, "txt", StringComparison.OrdinalIgnoreCase))
{
return;
}
// Open the file and begin reading
string[] cueLines = File.ReadAllLines(filename);
for (int i = 0; i < cueLines.Length; i++)
{
string line = cueLines[i].Trim();
// http://stackoverflow.com/questions/554013/regular-expression-to-split-on-spaces-unless-in-quotes
string[] splitLine = Regex
.Matches(line, @"[^\s""]+|""[^""]*""")
.Cast<Match>()
.Select(m => m.Groups[0].Value)
.ToArray();
// If we have an empty line, we skip
if (string.IsNullOrWhiteSpace(line))
continue;
switch (splitLine[0])
{
// Read comments
case "REM":
// We ignore all comments for now
break;
// Read MCN
case "CATALOG":
if (splitLine.Length < 2)
{
if (throwOnError)
throw new FormatException($"CATALOG line malformed: {line}");
continue;
}
this.Catalog = splitLine[1];
break;
// Read external CD-Text file path
case "CDTEXTFILE":
if (splitLine.Length < 2)
{
if (throwOnError)
throw new FormatException($"CDTEXTFILE line malformed: {line}");
continue;
}
this.CdTextFile = splitLine[1];
break;
// Read CD-Text enhanced performer
case "PERFORMER":
if (splitLine.Length < 2)
{
if (throwOnError)
throw new FormatException($"PERFORMER line malformed: {line}");
continue;
}
this.Performer = splitLine[1];
break;
// Read CD-Text enhanced songwriter
case "SONGWRITER":
if (splitLine.Length < 2)
{
if (throwOnError)
throw new FormatException($"SONGWRITER line malformed: {line}");
continue;
}
this.Songwriter = splitLine[1];
break;
// Read CD-Text enhanced title
case "TITLE":
if (splitLine.Length < 2)
{
if (throwOnError)
throw new FormatException($"TITLE line malformed: {line}");
continue;
}
this.Title = splitLine[1];
break;
// Read file information
case "FILE":
if (splitLine.Length < 3)
{
if (throwOnError)
throw new FormatException($"FILE line malformed: {line}");
continue;
}
if (this.Files == null)
this.Files = new List<CueFile>();
var file = new CueFile(splitLine[1], splitLine[2], cueLines, ref i);
if (file == default)
{
if (throwOnError)
throw new FormatException($"FILE line malformed: {line}");
continue;
}
this.Files.Add(file);
break;
}
}
}
/// <summary>
/// Write the cuesheet out to a file
/// </summary>
/// <param name="filename">File path to write to</param>
public void Write(string filename)
{
using (var fs = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
{
Write(fs);
}
}
/// <summary>
/// Write the cuesheet out to a stream
/// </summary>
/// <param name="stream">Stream to write to</param>
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
public void Write(Stream stream, bool throwOnError = false)
{
// If we don't have any files, it's invalid
if (this.Files == null)
{
if (throwOnError)
throw new ArgumentNullException(nameof(this.Files));
return;
}
else if (this.Files.Count == 0)
{
if (throwOnError)
throw new ArgumentException("No files provided to write");
return;
}
using (var sw = new StreamWriter(stream, Encoding.ASCII, 1024, true))
{
if (!string.IsNullOrEmpty(this.Catalog))
sw.WriteLine($"CATALOG {this.Catalog}");
if (!string.IsNullOrEmpty(this.CdTextFile))
sw.WriteLine($"CDTEXTFILE {this.CdTextFile}");
if (!string.IsNullOrEmpty(this.Performer))
sw.WriteLine($"PERFORMER {this.Performer}");
if (!string.IsNullOrEmpty(this.Songwriter))
sw.WriteLine($"SONGWRITER {this.Songwriter}");
if (!string.IsNullOrEmpty(this.Title))
sw.WriteLine($"TITLE {this.Title}");
foreach (var file in Files)
{
file.Write(sw);
}
}
}
}
}

View File

@@ -0,0 +1,554 @@
using System;
using System.Collections.Generic;
using System.IO;
/// <remarks>
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
/// </remarks>
namespace MPF.CueSheets
{
/// <summary>
/// Track datatype
/// </summary>
public enum CueTrackDataType
{
/// <summary>
/// AUDIO, Audio/Music (2352)
/// </summary>
AUDIO,
/// <summary>
/// CDG, Karaoke CD+G (2448)
/// </summary>
CDG,
/// <summary>
/// MODE1/2048, CD-ROM Mode1 Data (cooked)
/// </summary>
MODE1_2048,
/// <summary>
/// MODE1/2352 CD-ROM Mode1 Data (raw)
/// </summary>
MODE1_2352,
/// <summary>
/// MODE2/2336, CD-ROM XA Mode2 Data
/// </summary>
MODE2_2336,
/// <summary>
/// MODE2/2352, CD-ROM XA Mode2 Data
/// </summary>
MODE2_2352,
/// <summary>
/// CDI/2336, CD-I Mode2 Data
/// </summary>
CDI_2336,
/// <summary>
/// CDI/2352, CD-I Mode2 Data
/// </summary>
CDI_2352,
}
/// <summary>
/// Special subcode flags within a track
/// </summary>
[Flags]
public enum CueTrackFlag
{
/// <summary>
/// DCP, Digital copy permitted
/// </summary>
DCP = 1 << 0,
/// <summary>
/// 4CH, Four channel audio
/// </summary>
FourCH = 1 << 1,
/// <summary>
/// PRE, Pre-emphasis enabled (audio tracks only)
/// </summary>
PRE = 1 << 2,
/// <summary>
/// SCMS, Serial Copy Management System (not supported by all recorders)
/// </summary>
SCMS = 1 << 3,
/// <summary>
/// DATA, set for data files. This flag is set automatically based on the tracks filetype
/// </summary>
DATA = 1 << 4,
}
/// <summary>
/// Represents a single TRACK in a FILE
/// </summary>
public class CueTrack
{
/// <summary>
/// Track number. The range is 1 to 99.
/// </summary>
public int Number { get; set; }
/// <summary>
/// Track datatype
/// </summary>
public CueTrackDataType DataType { get; set; }
/// <summary>
/// FLAGS
/// </summary>
public CueTrackFlag Flags { get; set; }
/// <summary>
/// ISRC
/// </summary>
/// <remarks>12 characters in length</remarks>
public string ISRC { get; set; }
/// <summary>
/// PERFORMER
/// </summary>
public string Performer { get; set; }
/// <summary>
/// SONGWRITER
/// </summary>
public string Songwriter { get; set; }
/// <summary>
/// TITLE
/// </summary>
public string Title { get; set; }
/// <summary>
/// PREGAP
/// </summary>
public PreGap PreGap { get; set; }
/// <summary>
/// List of INDEX in TRACK
/// </summary>
/// <remarks>Must start with 0 or 1 and then sequential</remarks>
public List<CueIndex> Indices { get; set; }
/// <summary>
/// POSTGAP
/// </summary>
public PostGap PostGap { get; set; }
/// <summary>
/// Create an empty TRACK
/// </summary>
public CueTrack()
{
}
/// <summary>
/// Fill a TRACK from an array of lines
/// </summary>
/// <param name="number">Number to set</param>
/// <param name="dataType">Data type to set</param>
/// <param name="cueLines">Lines array to pull from</param>
/// <param name="i">Reference to index in array</param>
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
public CueTrack(string number, string dataType, string[] cueLines, ref int i, bool throwOnError = false)
{
if (cueLines == null)
{
if (throwOnError)
throw new ArgumentNullException(nameof(cueLines));
return;
}
else if (i < 0 || i > cueLines.Length)
{
if (throwOnError)
throw new IndexOutOfRangeException();
return;
}
// Set the current fields
if (!int.TryParse(number, out int parsedNumber))
{
if (throwOnError)
throw new ArgumentException($"Number was not a number: {number}");
return;
}
else if (parsedNumber < 1 || parsedNumber > 99)
{
if (throwOnError)
throw new IndexOutOfRangeException($"Index must be between 1 and 99: {parsedNumber}");
return;
}
this.Number = parsedNumber;
this.DataType = GetDataType(dataType);
// Increment to start
i++;
for (; i < cueLines.Length; i++)
{
string line = cueLines[i].Trim();
string[] splitLine = line.Split(' ');
// If we have an empty line, we skip
if (string.IsNullOrWhiteSpace(line))
continue;
switch (splitLine[0])
{
// Read comments
case "REM":
// We ignore all comments for now
break;
// Read flag information
case "FLAGS":
if (splitLine.Length < 2)
{
if (throwOnError)
throw new FormatException($"FLAGS line malformed: {line}");
continue;
}
this.Flags = GetFlags(splitLine);
break;
// Read International Standard Recording Code
case "ISRC":
if (splitLine.Length < 2)
{
if (throwOnError)
throw new FormatException($"ISRC line malformed: {line}");
continue;
}
this.ISRC = splitLine[1];
break;
// Read CD-Text enhanced performer
case "PERFORMER":
if (splitLine.Length < 2)
{
if (throwOnError)
throw new FormatException($"PERFORMER line malformed: {line}");
continue;
}
this.Performer = splitLine[1];
break;
// Read CD-Text enhanced songwriter
case "SONGWRITER":
if (splitLine.Length < 2)
{
if (throwOnError)
throw new FormatException($"SONGWRITER line malformed: {line}");
continue;
}
this.Songwriter = splitLine[1];
break;
// Read CD-Text enhanced title
case "TITLE":
if (splitLine.Length < 2)
{
if (throwOnError)
throw new FormatException($"TITLE line malformed: {line}");
continue;
}
this.Title = splitLine[1];
break;
// Read pregap information
case "PREGAP":
if (splitLine.Length < 2)
{
if (throwOnError)
throw new FormatException($"PREGAP line malformed: {line}");
continue;
}
var pregap = new PreGap(splitLine[1]);
if (pregap == default)
{
if (throwOnError)
throw new FormatException($"PREGAP line malformed: {line}");
continue;
}
this.PreGap = pregap;
break;
// Read index information
case "INDEX":
if (splitLine.Length < 3)
{
if (throwOnError)
throw new FormatException($"INDEX line malformed: {line}");
continue;
}
if (this.Indices == null)
this.Indices = new List<CueIndex>();
var index = new CueIndex(splitLine[1], splitLine[2]);
if (index == default)
{
if (throwOnError)
throw new FormatException($"INDEX line malformed: {line}");
continue;
}
this.Indices.Add(index);
break;
// Read postgap information
case "POSTGAP":
if (splitLine.Length < 2)
{
if (throwOnError)
throw new FormatException($"POSTGAP line malformed: {line}");
continue;
}
var postgap = new PostGap(splitLine[1]);
if (postgap == default)
{
if (throwOnError)
throw new FormatException($"POSTGAP line malformed: {line}");
continue;
}
this.PostGap = postgap;
break;
// Default means return
default:
i--;
return;
}
}
}
/// <summary>
/// Write the TRACK out to a stream
/// </summary>
/// <param name="sw">StreamWriter to write to</param
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
public void Write(StreamWriter sw, bool throwOnError = false)
{
// If we don't have any indices, it's invalid
if (this.Indices == null)
{
if (throwOnError)
throw new ArgumentNullException(nameof(this.Indices));
return;
}
else if (this.Indices.Count == 0)
{
if (throwOnError)
throw new ArgumentException("No indices provided to write");
return;
}
sw.WriteLine($" TRACK {this.Number:D2} {FromDataType(this.DataType)}");
if (this.Flags != 0)
sw.WriteLine($" FLAGS {FromFlags(this.Flags)}");
if (!string.IsNullOrEmpty(this.ISRC))
sw.WriteLine($"ISRC {this.ISRC}");
if (!string.IsNullOrEmpty(this.Performer))
sw.WriteLine($"PERFORMER {this.Performer}");
if (!string.IsNullOrEmpty(this.Songwriter))
sw.WriteLine($"SONGWRITER {this.Songwriter}");
if (!string.IsNullOrEmpty(this.Title))
sw.WriteLine($"TITLE {this.Title}");
if (this.PreGap != null)
this.PreGap.Write(sw);
foreach (var index in Indices)
{
index.Write(sw);
}
if (this.PostGap != null)
this.PostGap.Write(sw);
}
/// <summary>
/// Get the data type from a given string
/// </summary>
/// <param name="dataType">String to get value from</param>
/// <returns>CueTrackDataType, if possible (default AUDIO)</returns>
private CueTrackDataType GetDataType(string dataType)
{
switch (dataType.ToLowerInvariant())
{
case "audio":
return CueTrackDataType.AUDIO;
case "cdg":
return CueTrackDataType.CDG;
case "mode1/2048":
return CueTrackDataType.MODE1_2048;
case "mode1/2352":
return CueTrackDataType.MODE1_2352;
case "mode2/2336":
return CueTrackDataType.MODE2_2336;
case "mode2/2352":
return CueTrackDataType.MODE2_2352;
case "cdi/2336":
return CueTrackDataType.CDI_2336;
case "cdi/2352":
return CueTrackDataType.CDI_2352;
default:
return CueTrackDataType.AUDIO;
}
}
/// <summary>
/// Get the string from a given data type
/// </summary>
/// <param name="dataType">CueTrackDataType to get value from</param>
/// <returns>string, if possible</returns>
private string FromDataType(CueTrackDataType dataType)
{
switch (dataType)
{
case CueTrackDataType.AUDIO:
return "AUDIO";
case CueTrackDataType.CDG:
return "CDG";
case CueTrackDataType.MODE1_2048:
return "MODE1/2048";
case CueTrackDataType.MODE1_2352:
return "MODE1/2352";
case CueTrackDataType.MODE2_2336:
return "MODE2/2336";
case CueTrackDataType.MODE2_2352:
return "MODE2/2352";
case CueTrackDataType.CDI_2336:
return "CDI/2336";
case CueTrackDataType.CDI_2352:
return "CDI/2352";
default:
return string.Empty;
}
}
/// <summary>
/// Get the flag value for an array of strings
/// </summary>
/// <param name="flagStrings">Possible flags as strings</param>
/// <returns>CueTrackFlag value representing the strings, if possible</returns>
private CueTrackFlag GetFlags(string[] flagStrings)
{
CueTrackFlag flag = 0;
foreach (string flagString in flagStrings)
{
switch (flagString.ToLowerInvariant())
{
case "flags":
// No-op since this is the start of the line
break;
case "dcp":
flag |= CueTrackFlag.DCP;
break;
case "4ch":
flag |= CueTrackFlag.FourCH;
break;
case "pre":
flag |= CueTrackFlag.PRE;
break;
case "scms":
flag |= CueTrackFlag.SCMS;
break;
case "data":
flag |= CueTrackFlag.DATA;
break;
}
}
return flag;
}
/// <summary>
/// Get the string value for a set of track flags
/// </summary>
/// <param name="flags">CueTrackFlag to get value from</param>
/// <returns>String value representing the CueTrackFlag, if possible</returns>
private string FromFlags(CueTrackFlag flags)
{
string outputFlagString = string.Empty;
if (flags.HasFlag(CueTrackFlag.DCP))
outputFlagString += "DCP ";
if (flags.HasFlag(CueTrackFlag.FourCH))
outputFlagString += "4CH ";
if (flags.HasFlag(CueTrackFlag.PRE))
outputFlagString += "PRE ";
if (flags.HasFlag(CueTrackFlag.SCMS))
outputFlagString += "SCMS ";
if (flags.HasFlag(CueTrackFlag.DATA))
outputFlagString += "DATA ";
return outputFlagString.Trim();
}
}
}

View File

@@ -0,0 +1,139 @@
using System;
using System.IO;
using System.Linq;
/// <remarks>
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
/// </remarks>
namespace MPF.CueSheets
{
/// <summary>
/// Represents POSTGAP information of a track
/// </summary>
public class PostGap
{
/// <summary>
/// Length of POSTGAP in minutes
/// </summary>
public int Minutes { get; set; }
/// <summary>
/// Length of POSTGAP in seconds
/// </summary>
/// <remarks>There are 60 seconds in a minute</remarks>
public int Seconds { get; set; }
/// <summary>
/// Length of POSTGAP in frames.
/// </summary>
/// <remarks>There are 75 frames per second</remarks>
public int Frames { get; set; }
/// Create an empty POSTGAP
/// </summary>
public PostGap()
{
}
/// <summary>
/// Create a POSTGAP from a mm:ss:ff length
/// </summary>
/// <param name="length">String to get length information from</param>
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
public PostGap(string length, bool throwOnError = false)
{
// Ignore empty lines
if (string.IsNullOrWhiteSpace(length))
{
if (throwOnError)
throw new ArgumentException("Length was null or whitespace");
return;
}
// Ignore lines that don't contain the correct information
if (length.Length != 8 || length.Count(c => c == ':') != 2)
{
if (throwOnError)
throw new FormatException($"Length was not in a recognized format: {length}");
return;
}
// Split the line
string[] splitLength = length.Split(':');
if (splitLength.Length != 3)
{
if (throwOnError)
throw new FormatException($"Length was not in a recognized format: {length}");
return;
}
// Parse the lengths
int[] lengthSegments = new int[3];
// Minutes
if (!int.TryParse(splitLength[0], out lengthSegments[0]))
{
if (throwOnError)
throw new FormatException($"Minutes segment was not a number: {splitLength[0]}");
return;
}
else if (lengthSegments[0] < 0)
{
if (throwOnError)
throw new IndexOutOfRangeException($"Minutes segment must be 0 or greater: {lengthSegments[0]}");
return;
}
// Seconds
if (!int.TryParse(splitLength[1], out lengthSegments[1]))
{
if (throwOnError)
throw new FormatException($"Seconds segment was not a number: {splitLength[1]}");
return;
}
else if (lengthSegments[1] < 0 || lengthSegments[1] > 60)
{
if (throwOnError)
throw new IndexOutOfRangeException($"Seconds segment must be between 0 and 60: {lengthSegments[1]}");
return;
}
// Frames
if (!int.TryParse(splitLength[2], out lengthSegments[2]))
{
if (throwOnError)
throw new FormatException($"Frames segment was not a number: {splitLength[2]}");
return;
}
else if (lengthSegments[2] < 0 || lengthSegments[2] > 75)
{
if (throwOnError)
throw new IndexOutOfRangeException($"Frames segment must be between 0 and 75: {lengthSegments[2]}");
return;
}
// Set the values
this.Minutes = lengthSegments[0];
this.Seconds = lengthSegments[1];
this.Frames = lengthSegments[2];
}
/// <summary>
/// Write the POSTGAP out to a stream
/// </summary>
/// <param name="sw">StreamWriter to write to</param>
public void Write(StreamWriter sw)
{
sw.WriteLine($" POSTGAP {this.Minutes:D2}:{this.Seconds:D2}:{this.Frames:D2}");
}
}
}

View File

@@ -0,0 +1,140 @@
using System;
using System.IO;
using System.Linq;
/// <remarks>
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
/// </remarks>
namespace MPF.CueSheets
{
/// <summary>
/// Represents PREGAP information of a track
/// </summary>
public class PreGap
{
/// <summary>
/// Length of PREGAP in minutes
/// </summary>
public int Minutes { get; set; }
/// <summary>
/// Length of PREGAP in seconds
/// </summary>
/// <remarks>There are 60 seconds in a minute</remarks>
public int Seconds { get; set; }
/// <summary>
/// Length of PREGAP in frames.
/// </summary>
/// <remarks>There are 75 frames per second</remarks>
public int Frames { get; set; }
/// <summary>
/// Create an empty PREGAP
/// </summary>
public PreGap()
{
}
/// <summary>
/// Create a PREGAP from a mm:ss:ff length
/// </summary>
/// <param name="length">String to get length information from</param>
/// <param name="throwOnError">True if errors throw an exception, false otherwise</param>
public PreGap(string length, bool throwOnError = false)
{
// Ignore empty lines
if (string.IsNullOrWhiteSpace(length))
{
if (throwOnError)
throw new ArgumentException("Length was null or whitespace");
return;
}
// Ignore lines that don't contain the correct information
if (length.Length != 8 || length.Count(c => c == ':') != 2)
{
if (throwOnError)
throw new FormatException($"Length was not in a recognized format: {length}");
return;
}
// Split the line
string[] splitLength = length.Split(':');
if (splitLength.Length != 3)
{
if (throwOnError)
throw new FormatException($"Length was not in a recognized format: {length}");
return;
}
// Parse the lengths
int[] lengthSegments = new int[3];
// Minutes
if (!int.TryParse(splitLength[0], out lengthSegments[0]))
{
if (throwOnError)
throw new FormatException($"Minutes segment was not a number: {splitLength[0]}");
return;
}
else if (lengthSegments[0] < 0)
{
if (throwOnError)
throw new IndexOutOfRangeException($"Minutes segment must be 0 or greater: {lengthSegments[0]}");
return;
}
// Seconds
if (!int.TryParse(splitLength[1], out lengthSegments[1]))
{
if (throwOnError)
throw new FormatException($"Seconds segment was not a number: {splitLength[1]}");
return;
}
else if (lengthSegments[1] < 0 || lengthSegments[1] > 60)
{
if (throwOnError)
throw new IndexOutOfRangeException($"Seconds segment must be between 0 and 60: {lengthSegments[1]}");
return;
}
// Frames
if (!int.TryParse(splitLength[2], out lengthSegments[2]))
{
if (throwOnError)
throw new FormatException($"Frames segment was not a number: {splitLength[2]}");
return;
}
else if (lengthSegments[2] < 0 || lengthSegments[2] > 75)
{
if (throwOnError)
throw new IndexOutOfRangeException($"Frames segment must be between 0 and 75: {lengthSegments[2]}");
return;
}
// Set the values
this.Minutes = lengthSegments[0];
this.Seconds = lengthSegments[1];
this.Frames = lengthSegments[2];
}
/// <summary>
/// Write the PREGAP out to a stream
/// </summary>
/// <param name="sw">StreamWriter to write to</param>
public void Write(StreamWriter sw)
{
sw.WriteLine($" PREGAP {this.Minutes:D2}:{this.Seconds:D2}:{this.Frames:D2}");
}
}
}

View File

@@ -1,10 +1,11 @@
namespace DICUI.DD
namespace MPF.DD
{
/// <summary>
/// Top-level commands for DD
/// </summary>
public static class CommandStrings
{
public const string NONE = "";
public const string List = "--list";
}

View File

@@ -0,0 +1,22 @@
using MPF.Data;
namespace MPF.DD
{
public static class Converters
{
#region Cross-enumeration conversions
/// <summary>
/// Get the default extension for a given disc type
/// </summary>
/// <param name="type">MediaType value to check</param>
/// <returns>Valid extension (with leading '.'), null on error</returns>
public static string Extension(MediaType? type)
{
// DD has a single, unified output format by default
return ".bin";
}
#endregion
}
}

View File

@@ -0,0 +1,401 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using MPF.Data;
namespace MPF.DD
{
/// <summary>
/// Represents a generic set of DD parameters
/// </summary>
public class Parameters : BaseParameters
{
#region Generic Dumping Information
/// <inheritdoc/>
public override string InputPath => InputFileValue?.TrimStart('\\', '?');
/// <inheritdoc/>
public override string OutputPath => OutputFileValue;
/// <inheritdoc/>
/// <inheritdoc/>
public override int? Speed
{
get { return 1; }
set { }
}
#endregion
#region Metadata
/// <inheritdoc/>
public override InternalProgram InternalProgram => InternalProgram.DD;
#endregion
#region Flag Values
public long? BlockSizeValue { get; set; }
public long? CountValue { get; set; }
// fixed, removable, disk, partition
public string FilterValue { get; set; }
public string InputFileValue { get; set; }
public string OutputFileValue { get; set; }
public long? SeekValue { get; set; }
public long? SkipValue { get; set; }
#endregion
/// <inheritdoc/>
public Parameters(string parameters) : base(parameters) { }
/// <inheritdoc/>
public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
: base(system, type, driveLetter, filename, driveSpeed, options)
{
}
#region BaseParameters Implementations
/// <inheritdoc/>
public override (bool, List<string>) CheckAllOutputFilesExist(string basePath, bool preCheck)
{
// TODO: Figure out what sort of output files are expected... just `.bin`?
return (true, new List<string>());
}
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive, bool includeArtifacts)
{
// TODO: Fill in submission info specifics for DD
string outputDirectory = Path.GetDirectoryName(basePath);
switch (this.Type)
{
// Determine type-specific differences
}
switch (this.System)
{
case KnownSystem.KonamiPython2:
if (GetPlayStationExecutableInfo(drive?.Letter, out string pythonTwoSerial, out RedumpRegion? pythonTwoRegion, out string pythonTwoDate))
{
info.CommonDiscInfo.Comments += $"Internal Disc Serial: {pythonTwoSerial}\n";
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? pythonTwoRegion;
info.CommonDiscInfo.EXEDateBuildDate = pythonTwoDate;
}
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? "";
break;
case KnownSystem.SonyPlayStation:
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationSerial, out RedumpRegion? playstationRegion, out string playstationDate))
{
info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationSerial}\n";
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationRegion;
info.CommonDiscInfo.EXEDateBuildDate = playstationDate;
}
info.CopyProtection.AntiModchip = GetPlayStationAntiModchipDetected(drive?.Letter) ? YesNo.Yes : YesNo.No;
break;
case KnownSystem.SonyPlayStation2:
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationTwoSerial, out RedumpRegion? playstationTwoRegion, out string playstationTwoDate))
{
info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationTwoSerial}\n";
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationTwoRegion;
info.CommonDiscInfo.EXEDateBuildDate = playstationTwoDate;
}
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? "";
break;
case KnownSystem.SonyPlayStation4:
info.VersionAndEditions.Version = GetPlayStation4Version(drive?.Letter) ?? "";
break;
case KnownSystem.SonyPlayStation5:
info.VersionAndEditions.Version = GetPlayStation5Version(drive?.Letter) ?? "";
break;
}
}
/// <inheritdoc/>
public override string GenerateParameters()
{
List<string> parameters = new List<string>();
if (BaseCommand == null)
BaseCommand = CommandStrings.NONE;
if (!string.IsNullOrEmpty(BaseCommand))
parameters.Add(BaseCommand);
#region Boolean flags
// Progress
if (IsFlagSupported(FlagStrings.Progress))
{
if (this[FlagStrings.Progress] == true)
parameters.Add($"{FlagStrings.Progress}");
}
// Size
if (IsFlagSupported(FlagStrings.Size))
{
if (this[FlagStrings.Size] == true)
parameters.Add($"{FlagStrings.Size}");
}
#endregion
#region Int64 flags
// Block Size
if (IsFlagSupported(FlagStrings.BlockSize))
{
if (this[FlagStrings.BlockSize] == true && BlockSizeValue != null)
parameters.Add($"{FlagStrings.BlockSize}={BlockSizeValue}");
}
// Count
if (IsFlagSupported(FlagStrings.Count))
{
if (this[FlagStrings.Count] == true && CountValue != null)
parameters.Add($"{FlagStrings.Count}={CountValue}");
}
// Seek
if (IsFlagSupported(FlagStrings.Seek))
{
if (this[FlagStrings.Seek] == true && SeekValue != null)
parameters.Add($"{FlagStrings.Seek}={SeekValue}");
}
// Skip
if (IsFlagSupported(FlagStrings.Skip))
{
if (this[FlagStrings.Skip] == true && SkipValue != null)
parameters.Add($"{FlagStrings.Skip}={SkipValue}");
}
#endregion
#region String flags
// Filter
if (IsFlagSupported(FlagStrings.Filter))
{
if (this[FlagStrings.Filter] == true && FilterValue != null)
parameters.Add($"{FlagStrings.Filter}={FilterValue}");
}
// Input File
if (IsFlagSupported(FlagStrings.InputFile))
{
if (this[FlagStrings.InputFile] == true && InputFileValue != null)
parameters.Add($"{FlagStrings.InputFile}=\"{InputFileValue}\"");
else
return null;
}
// Output File
if (IsFlagSupported(FlagStrings.OutputFile))
{
if (this[FlagStrings.OutputFile] == true && OutputFileValue != null)
parameters.Add($"{FlagStrings.OutputFile}=\"{OutputFileValue}\"");
else
return null;
}
#endregion
return string.Join(" ", parameters);
}
/// <inheritdoc/>
public override Dictionary<string, List<string>> GetCommandSupport()
{
return new Dictionary<string, List<string>>()
{
[CommandStrings.NONE] = new List<string>()
{
FlagStrings.BlockSize,
FlagStrings.Count,
FlagStrings.Filter,
FlagStrings.InputFile,
FlagStrings.OutputFile,
FlagStrings.Progress,
FlagStrings.Seek,
FlagStrings.Size,
FlagStrings.Skip,
},
[CommandStrings.List] = new List<string>()
{
},
};
}
/// <inheritdoc/>
public override string GetDefaultExtension(MediaType? mediaType) => Converters.Extension(mediaType);
/// <inheritdoc/>
public override bool IsDumpingCommand()
{
switch (this.BaseCommand)
{
case CommandStrings.List:
return false;
default:
return true;
}
}
/// <inheritdoc/>
protected override void ResetValues()
{
BaseCommand = CommandStrings.NONE;
flags = new Dictionary<string, bool?>();
BlockSizeValue = null;
CountValue = null;
InputFileValue = null;
OutputFileValue = null;
SeekValue = null;
SkipValue = null;
}
/// <inheritdoc/>
protected override void SetDefaultParameters(char driveLetter, string filename, int? driveSpeed, Options options)
{
BaseCommand = CommandStrings.NONE;
this[FlagStrings.InputFile] = true;
InputFileValue = $"\\\\?\\{driveLetter}:";
this[FlagStrings.OutputFile] = true;
OutputFileValue = filename;
// TODO: Add more common block sizes
this[FlagStrings.BlockSize] = true;
switch (this.Type)
{
case MediaType.FloppyDisk:
BlockSizeValue = 1440 * 1024;
break;
default:
BlockSizeValue = 1024 * 1024 * 1024;
break;
}
this[FlagStrings.Progress] = true;
this[FlagStrings.Size] = true;
}
/// <inheritdoc/>
protected override bool ValidateAndSetParameters(string parameters)
{
BaseCommand = CommandStrings.NONE;
// The string has to be valid by itself first
if (string.IsNullOrWhiteSpace(parameters))
return false;
// Now split the string into parts for easier validation
// https://stackoverflow.com/questions/14655023/split-a-string-that-has-white-spaces-unless-they-are-enclosed-within-quotes
parameters = parameters.Trim();
List<string> parts = Regex.Matches(parameters, @"[\""].+?[\""]|[^ ]+")
.Cast<Match>()
.Select(m => m.Value)
.ToList();
// Determine what the commandline should look like given the first item
int start = 0;
if (parts[0] == CommandStrings.List)
{
BaseCommand = parts[0];
start = 1;
}
// Loop through all auxilary flags, if necessary
for (int i = start; i < parts.Count; i++)
{
// Flag read-out values
long? longValue = null;
string stringValue = null;
// Keep a count of keys to determine if we should break out to filename handling or not
int keyCount = Keys.Count();
#region Boolean flags
// Progress
ProcessFlagParameter(parts, FlagStrings.Progress, ref i);
// Size
ProcessFlagParameter(parts, FlagStrings.Size, ref i);
#endregion
#region Int64 flags
// Block Size
longValue = ProcessInt64Parameter(parts, FlagStrings.BlockSize, ref i);
if (longValue != null)
BlockSizeValue = longValue;
// Count
longValue = ProcessInt64Parameter(parts, FlagStrings.Count, ref i);
if (longValue != null)
CountValue = longValue;
// Seek
longValue = ProcessInt64Parameter(parts, FlagStrings.Seek, ref i);
if (longValue != null)
SeekValue = longValue;
// Skip
longValue = ProcessInt64Parameter(parts, FlagStrings.Skip, ref i);
if (longValue != null)
SkipValue = longValue;
#endregion
#region String flags
// Filter (fixed, removable, disk, partition)
stringValue = ProcessStringParameter(parts, FlagStrings.Filter, ref i);
if (!string.IsNullOrEmpty(stringValue))
FilterValue = stringValue;
// Input File
stringValue = ProcessStringParameter(parts, FlagStrings.InputFile, ref i);
if (!string.IsNullOrEmpty(stringValue))
InputFileValue = stringValue;
// Output File
stringValue = ProcessStringParameter(parts, FlagStrings.OutputFile, ref i);
if (!string.IsNullOrEmpty(stringValue))
OutputFileValue = stringValue;
#endregion
}
return true;
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,51 @@
namespace DICUI.Data
using System.Collections.Generic;
using System.Linq;
namespace MPF.Data
{
/// <summary>
/// Constant values for UI
/// </summary>
public static class Interface
{
// Button values
public const string StartDumping = "Start Dumping";
public const string StopDumping = "Stop Dumping";
// Byte arrays for signatures
public static readonly byte[] SaturnSectorZeroStart = new byte[] { 0x53, 0x45, 0x47, 0x41, 0x20, 0x53, 0x45, 0x47, 0x41, 0x53, 0x41, 0x54, 0x55, 0x52, 0x4E, 0x20 };
// Private lists of known drive speed ranges
private static IReadOnlyList<int> cd { get; } = new List<int> { 1, 2, 3, 4, 6, 8, 12, 16, 20, 24, 32, 40, 44, 48, 52, 56, 72 };
private static IReadOnlyList<int> dvd { get; } = cd.Where(s => s <= 24).ToList();
private static IReadOnlyList<int> bd { get; } = cd.Where(s => s <= 16).ToList();
private static IReadOnlyList<int> unknown { get; } = new List<int> { 1 };
/// <summary>
/// Get list of all drive speeds for a given MediaType
/// </summary>
/// <param name="type">MediaType? that represents the current item</param>
/// <returns>Read-only list of drive speeds</returns>
public static IReadOnlyList<int> GetSpeedsForMediaType(MediaType? type)
{
switch (type)
{
case MediaType.CDROM:
case MediaType.GDROM:
return cd;
case MediaType.DVD:
case MediaType.HDDVD:
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
return dvd;
case MediaType.BluRay:
return bd;
default:
return unknown;
}
}
}
/// <summary>
/// Template field values for submission info
/// </summary>

106
MPF.Library/Data/Drive.cs Normal file
View File

@@ -0,0 +1,106 @@
using System.IO;
namespace MPF.Data
{
/// <summary>
/// Represents information for a single drive
/// </summary>
public class Drive
{
/// <summary>
/// Represents drive type
/// </summary>
public InternalDriveType? InternalDriveType { get; set; }
/// <summary>
/// Drive partition format
/// </summary>
public string DriveFormat { get { return driveInfo.DriveFormat; } }
/// <summary>
/// Windows drive letter
/// </summary>
public char Letter { get { return driveInfo?.Name[0] ?? '\0'; } }
/// <summary>
/// Represents if Windows has marked the drive as active
/// </summary>
public bool MarkedActive { get { return driveInfo.IsReady; } }
/// <summary>
/// Media label as read by Windows
/// </summary>
public string VolumeLabel
{
get
{
string volumeLabel = Template.DiscNotDetected;
if (driveInfo.IsReady)
{
if (string.IsNullOrWhiteSpace(driveInfo.VolumeLabel))
volumeLabel = "track";
else
volumeLabel = driveInfo.VolumeLabel;
}
foreach (char c in Path.GetInvalidFileNameChars())
volumeLabel = volumeLabel.Replace(c, '_');
return volumeLabel;
}
}
/// <summary>
/// DriveInfo object representing the drive, if possible
/// </summary>
private readonly DriveInfo driveInfo;
public Drive(InternalDriveType? driveType, DriveInfo driveInfo)
{
this.InternalDriveType = driveType;
this.driveInfo = driveInfo;
}
/// <summary>
/// Read a sector with a specified size from the drive
/// </summary>
/// <param name="num">Sector number, non-negative</param>
/// <param name="size">Size of a sector in bytes</param>
/// <returns>Byte array representing the sector, null on error</returns>
public byte[] ReadSector(long num, int size = 2048)
{
// Missing drive leter is not supported
if (string.IsNullOrEmpty(this.driveInfo?.Name))
return null;
// We don't support negative sectors
if (num < 0)
return null;
// Wrap the following in case of device access errors
Stream fs = null;
try
{
// Open the drive as a device
fs = File.OpenRead($"\\\\?\\{this.Letter}:");
// Seek to the start of the sector, if possible
long start = num * size;
fs.Seek(start, SeekOrigin.Begin);
// Read and return the sector
byte[] buffer = new byte[size];
fs.Read(buffer, 0, size);
return buffer;
}
catch
{
return null;
}
finally
{
fs?.Dispose();
}
}
}
}

View File

@@ -1,7 +1,25 @@
using System;
namespace DICUI.Data
namespace MPF.Data
{
/// <summary>
/// Available hashing types
/// </summary>
[Flags]
public enum Hash
{
CRC = 1 << 0,
MD5 = 1 << 1,
SHA1 = 1 << 2,
SHA256 = 1 << 3,
SHA384 = 1 << 4,
SHA512 = 1 << 5,
// Special combinations
Standard = CRC | MD5 | SHA1,
All = CRC | MD5 | SHA1 | SHA256 | SHA384 | SHA512,
}
/// <summary>
/// Drive type for dumping
/// </summary>
@@ -56,6 +74,7 @@ namespace DICUI.Data
MicrosoftXBOX,
MicrosoftXBOX360,
MicrosoftXBOXOne,
MicrosoftXboxSeriesXS,
NECPCEngineTurboGrafxCD,
NECPCFX,
NintendoGameCube,
@@ -73,6 +92,7 @@ namespace DICUI.Data
SonyPlayStation2,
SonyPlayStation3,
SonyPlayStation4,
SonyPlayStation5,
SonyPlayStationPortable,
TandyMemorexVisualInformationSystem,
VMLabsNuon,
@@ -226,7 +246,6 @@ namespace DICUI.Data
HDDVDVideo,
NavisoftNaviken21,
PalmOS,
PhilipsCDiDigitalVideo,
PhotoCD,
PlayStationGameSharkUpdates,
RainbowDisc,
@@ -387,6 +406,272 @@ namespace DICUI.Data
TapeDSTLarge = 66,
}
/// <summary>
/// Redump disc category
/// </summary>
public enum RedumpDiscCategory
{
Games = 1,
Demos = 2,
Video = 3,
Audio = 4,
Multimedia = 5,
Applications = 6,
Coverdiscs = 7,
Educational = 8,
BonusDiscs = 9,
Preproduction = 10,
AddOns = 11,
}
/// <summary>
/// Redump dump status
/// </summary>
public enum RedumpDumpStatus
{
BadDumpRed = 2,
PossibleBadDumpYellow = 3,
OriginalMediaBlue = 4,
TwoOrMoreDumpsGreen = 5,
}
/// <summary>
/// Redump supported langauge
/// </summary>
public enum RedumpLanguage
{
Afrikaans,
Albanian,
Arabic,
Basque,
Bulgarian,
Catalan,
Chinese,
Croatian,
Czech,
Danish,
Dutch,
English,
Estonian,
Finnish,
French,
Gaelic,
German,
Greek,
Hebrew,
Hindi,
Hungarian,
Indonesian,
Icelandic,
Italian,
Japanese,
Korean,
Latin,
Latvian,
Lithuanian,
Macedonian,
Norwegian,
Polish,
Portuguese,
Punjabi,
Romanian,
Russian,
Serbian,
Slovak,
Slovenian,
Spanish,
Swedish,
Tamil,
Thai,
Turkish,
Ukrainian,
}
/// <summary>
/// Redump PS2 language selection via
/// </summary>
public enum RedumpLanguageSelection
{
BiosSettings,
LanguageSelector,
OptionsMenu,
}
/// <summary>
/// Supported Redump region
/// </summary>
public enum RedumpRegion
{
Argentina,
Asia,
AsiaEurope,
AsiaUSA,
Australia,
AustraliaGermany,
AustraliaNewZealand,
Austria,
AustriaSwitzerland,
Belgium,
BelgiumNetherlands,
Brazil,
Bulgaria,
Canada,
China,
Croatia,
Czech,
Denmark,
Estonia,
Europe,
EuropeAsia,
EuropeAustralia,
EuropeCanada,
EuropeGermany,
Export,
Finland,
France,
FranceSpain,
Germany,
GreaterChina,
Greece,
Hungary,
Iceland,
India,
Ireland,
Israel,
Italy,
Japan,
JapanAsia,
JapanEurope,
JapanKorea,
JapanUSA,
Korea,
LatinAmerica,
Lithuania,
Netherlands,
NewZealand,
Norway,
Poland,
Portugal,
Romania,
Russia,
Scandinavia,
Serbia,
Singapore,
Slovakia,
SouthAfrica,
Spain,
SpainPortugal,
Sweden,
Switzerland,
Taiwan,
Thailand,
Turkey,
UnitedArabEmirates,
UK,
UKAustralia,
Ukraine,
USA,
USAAsia,
USAAustralia,
USABrazil,
USACanada,
USAEurope,
USAGermany,
USAJapan,
USAKorea,
World,
}
/// <summary>
/// List of all known Redump systems
/// </summary>
public enum RedumpSystem
{
// Special BIOS sets
MicrosoftXboxBIOS,
NintendoGameCubeBIOS,
SonyPlayStationBIOS,
SonyPlayStation2BIOS,
// Regular systems
AcornArchimedes,
AppleMacintosh,
AtariJaguarCDInteractiveMultimediaSystem,
AudioCD,
BandaiPippin,
BandaiPlaydiaQuickInteractiveSystem,
BDVideo,
CommodoreAmigaCD,
CommodoreAmigaCD32,
CommodoreAmigaCDTV,
DVDVideo,
EnhancedCD,
FujitsuFMTownsseries,
funworldPhotoPlay,
HasbroVideoNow,
HasbroVideoNowColor,
HasbroVideoNowJr,
HasbroVideoNowXP,
IBMPCcompatible,
IncredibleTechnologiesEagle,
KonamieAmusement,
KonamiFireBeat,
KonamiM2,
KonamiSystem573,
KonamiSystemGV,
KonamiTwinkle,
MattelFisherPriceiXL,
MattelHyperScan,
MemorexVisualInformationSystem,
MicrosoftXbox,
MicrosoftXbox360,
MicrosoftXboxOne,
MicrosoftXboxSeriesXS,
NamcoSegaNintendoTriforce,
NamcoSystem12,
NamcoSystem246,
NavisoftNaviken21,
NECPCEngineCDTurboGrafxCD,
NECPC88series,
NECPC98series,
NECPCFXPCFXGA,
NintendoGameCube,
NintendoWii,
NintendoWiiU,
PalmOS,
Panasonic3DOInteractiveMultiplayer,
PanasonicM2,
PhilipsCDi,
PhotoCD,
PlayStationGameSharkUpdates,
SegaChihiro,
SegaDreamcast,
SegaLindbergh,
SegaMegaCDSegaCD,
SegaNaomi,
SegaNaomi2,
SegaPrologue21,
SegaRingEdge,
SegaRingEdge2,
SegaSaturn,
SegaTitanVideo,
SharpX68000,
SNKNeoGeoCD,
SonyPlayStation,
SonyPlayStation2,
SonyPlayStation3,
SonyPlayStation4,
SonyPlayStation5,
SonyPlayStationPortable,
TABAustriaQuizard,
TaoiKTV,
TomyKissSite,
VideoCD,
VMLabsNUON,
VTechVFlashVSmilePro,
ZAPiTGamesGameWaveFamilyEntertainmentSystem,
}
/// <summary>
/// Generic yes/no values for Redump
/// </summary>
@@ -467,7 +752,7 @@ namespace DICUI.Data
SupportsRemoteStorage = 256,
SupportsLongNames = 16384,
VolumeIsCompressed = 32768,
ReadOnlyVolume = 524289, // TODO: Invesitgate, as this value seems wrong
ReadOnlyVolume = 524288,
SupportsObjectIDS = 65536,
SupportsEncryption = 131072,
SupportsNamedStreams = 262144,

View File

@@ -4,7 +4,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace DICUI.Utilities
namespace MPF.Data
{
public class IniFile : IDictionary<string, string>
{

569
MPF.Library/Data/Options.cs Normal file
View File

@@ -0,0 +1,569 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using MPF.Utilities;
namespace MPF.Data
{
public class Options : IDictionary<string, string>, ICloneable
{
private Dictionary<string, string> _settings;
#region Internal Program
/// <summary>
/// Path to Aaru
/// </summary>
public string AaruPath
{
get { return GetStringSetting(_settings, "AaruPath", "Programs\\Aaru\\Aaru.exe"); }
set { _settings["AaruPath"] = value; }
}
/// <summary>
/// Path to DiscImageCreator
/// </summary>
public string DiscImageCreatorPath
{
get { return GetStringSetting(_settings, "DiscImageCreatorPath", "Programs\\Creator\\DiscImageCreator.exe"); }
set { _settings["DiscImageCreatorPath"] = value; }
}
/// <summary>
/// Path to dd for Windows
/// </summary>
public string DDPath
{
get { return GetStringSetting(_settings, "DDPath", "Programs\\DD\\dd.exe"); }
set { _settings["DDPath"] = value; }
}
/// <summary>
/// Currently selected dumping program
/// </summary>
public InternalProgram InternalProgram
{
get
{
string valueString = GetStringSetting(_settings, "InternalProgram", InternalProgram.DiscImageCreator.ToString());
var valueEnum = Converters.ToInternalProgram(valueString);
return valueEnum == InternalProgram.NONE ? InternalProgram.DiscImageCreator : valueEnum;
}
set
{
_settings["InternalProgram"] = value.ToString();
}
}
#endregion
#region UI Defaults
/// <summary>
/// Enable dark mode for UI elements
/// </summary>
public bool EnableDarkMode
{
get { return GetBooleanSetting(_settings, "EnableDarkMode", false); }
set { _settings["EnableDarkMode"] = value.ToString(); }
}
/// <summary>
/// Default output path for dumps
/// </summary>
public string DefaultOutputPath
{
get { return GetStringSetting(_settings, "DefaultOutputPath", "ISO"); }
set { _settings["DefaultOutputPath"] = value; }
}
/// <summary>
/// Default system if none can be detected
/// </summary>
public KnownSystem DefaultSystem
{
get
{
string valueString = GetStringSetting(_settings, "DefaultSystem", KnownSystem.NONE.ToString());
var valueEnum = Converters.ToKnownSystem(valueString);
return valueEnum ?? KnownSystem.NONE;
}
set
{
_settings["DefaultSystem"] = Converters.GetLongName(value);
}
}
#endregion
#region Dumping Speeds
/// <summary>
/// Default CD dumping speed
/// </summary>
public int PreferredDumpSpeedCD
{
get { return GetInt32Setting(_settings, "PreferredDumpSpeedCD", 72); }
set { _settings["PreferredDumpSpeedCD"] = value.ToString(); }
}
/// <summary>
/// Default DVD dumping speed
/// </summary>
public int PreferredDumpSpeedDVD
{
get { return GetInt32Setting(_settings, "PreferredDumpSpeedDVD", 24); }
set { _settings["PreferredDumpSpeedDVD"] = value.ToString(); }
}
/// <summary>
/// Default BD dumping speed
/// </summary>
public int PreferredDumpSpeedBD
{
get { return GetInt32Setting(_settings, "PreferredDumpSpeedBD", 16); }
set { _settings["PreferredDumpSpeedBD"] = value.ToString(); }
}
#endregion
#region Aaru
/// <summary>
/// Enable debug output while dumping by default
/// </summary>
public bool AaruEnableDebug
{
get { return GetBooleanSetting(_settings, "AaruEnableDebug", false); }
set { _settings["AaruEnableDebug"] = value.ToString(); }
}
/// <summary>
/// Enable verbose output while dumping by default
/// </summary>
public bool AaruEnableVerbose
{
get { return GetBooleanSetting(_settings, "AaruEnableVerbose", false); }
set { _settings["AaruEnableVerbose"] = value.ToString(); }
}
/// <summary>
/// Enable force dumping of media by default
/// </summary>
public bool AaruForceDumping
{
get { return GetBooleanSetting(_settings, "AaruForceDumping", true); }
set { _settings["AaruForceDumping"] = value.ToString(); }
}
/// <summary>
/// Default number of sector/subchannel rereads
/// </summary>
public int AaruRereadCount
{
get { return GetInt32Setting(_settings, "AaruRereadCount", 5); }
set { _settings["AaruRereadCount"] = value.ToString(); }
}
/// <summary>
/// Strip personal data information from Aaru metadata by default
/// </summary>
public bool AaruStripPersonalData
{
get { return GetBooleanSetting(_settings, "AaruStripPersonalData", false); }
set { _settings["AaruStripPersonalData"] = value.ToString(); }
}
#endregion
#region DiscImageCreator
/// <summary>
/// Enable overly-secure dumping flags by default
/// </summary>
/// <remarks>
/// Split this into component parts later. Currently does:
/// - Scan sector protection and set subchannel read level to 2 for CD
/// - Set scan file protect flag for DVD
/// </remarks>
public bool DICParanoidMode
{
get { return GetBooleanSetting(_settings, "DICParanoidMode", false); }
set { _settings["DICParanoidMode"] = value.ToString(); }
}
/// <summary>
/// Enable the Quiet flag by default
/// </summary>
public bool DICQuietMode
{
get { return GetBooleanSetting(_settings, "DICQuietMode", false); }
set { _settings["DICQuietMode"] = value.ToString(); }
}
/// <summary>
/// Default number of C2 rereads
/// </summary>
public int DICRereadCount
{
get { return GetInt32Setting(_settings, "DICRereadCount", 20); }
set { _settings["DICRereadCount"] = value.ToString(); }
}
/// <summary>
/// Reset drive after dumping (useful for older drives)
/// </summary>
public bool DICResetDriveAfterDump
{
get { return GetBooleanSetting(_settings, "DICResetDriveAfterDump", false); }
set { _settings["DICResetDriveAfterDump"] = value.ToString(); }
}
/// <summary>
/// Use the CMI flag for supported disc types
/// </summary>
public bool DICUseCMIFlag
{
get { return GetBooleanSetting(_settings, "DICUseCMIFlag", false); }
set { _settings["DICUseCMIFlag"] = value.ToString(); }
}
#endregion
#region Extra Dumping Options
/// <summary>
/// Scan the disc for protection after dumping
/// </summary>
public bool ScanForProtection
{
get { return GetBooleanSetting(_settings, "ScanForProtection", true); }
set { _settings["ScanForProtection"] = value.ToString(); }
}
/// <summary>
/// Add placeholder values in the submission info
/// </summary>
public bool AddPlaceholders
{
get { return GetBooleanSetting(_settings, "AddPlaceholders", true); }
set { _settings["AddPlaceholders"] = value.ToString(); }
}
/// <summary>
/// Show the disc information window after dumping
/// </summary>
public bool PromptForDiscInformation
{
get { return GetBooleanSetting(_settings, "PromptForDiscInformation", true); }
set { _settings["PromptForDiscInformation"] = value.ToString(); }
}
/// <summary>
/// Eject the disc after dumping
/// </summary>
public bool EjectAfterDump
{
get { return GetBooleanSetting(_settings, "EjectAfterDump", false); }
set { _settings["EjectAfterDump"] = value.ToString(); }
}
/// <summary>
/// Ignore fixed drives when populating the list
/// </summary>
public bool IgnoreFixedDrives
{
get { return GetBooleanSetting(_settings, "IgnoreFixedDrives", true); }
set { _settings["IgnoreFixedDrives"] = value.ToString(); }
}
/// <summary>
/// Show dumping tools in their own window instead of in the log
/// </summary>
public bool ToolsInSeparateWindow
{
get { return GetBooleanSetting(_settings, "ToolsInSeparateWindow", true); }
set { _settings["ToolsInSeparateWindow"] = value.ToString(); }
}
/// <summary>
/// Output the compressed JSON version of the submission info
/// </summary>
public bool OutputSubmissionJSON
{
get { return GetBooleanSetting(_settings, "OutputSubmissionJSON", false); }
set { _settings["OutputSubmissionJSON"] = value.ToString(); }
}
/// <summary>
/// Include log files in serialized JSON data
/// </summary>
public bool IncludeArtifacts
{
get { return GetBooleanSetting(_settings, "IncludeArtifacts", false); }
set { _settings["IncludeArtifacts"] = value.ToString(); }
}
/// <summary>
/// Compress output log files to reduce space
/// </summary>
public bool CompressLogFiles
{
get { return GetBooleanSetting(_settings, "CompressLogFiles", true); }
set { _settings["CompressLogFiles"] = value.ToString(); }
}
#endregion
#region Skip Options
/// <summary>
/// Skip detecting media type on disc scan
/// </summary>
public bool SkipMediaTypeDetection
{
get { return GetBooleanSetting(_settings, "SkipMediaTypeDetection", false); }
set { _settings["SkipMediaTypeDetection"] = value.ToString(); }
}
/// <summary>
/// Skip detecting known system on disc scan
/// </summary>
public bool SkipSystemDetection
{
get { return GetBooleanSetting(_settings, "SkipSystemDetection", false); }
set { _settings["SkipSystemDetection"] = value.ToString(); }
}
#endregion
#region Protection Scanning Options
/// <summary>
/// Scan archive contents during protection scanning
/// </summary>
public bool ScanArchivesForProtection
{
get { return GetBooleanSetting(_settings, "ScanArchivesForProtection", true); }
set { _settings["ScanArchivesForProtection"] = value.ToString(); }
}
/// <summary>
/// Scan for executable packers during protection scanning
/// </summary>
public bool ScanPackersForProtection
{
get { return GetBooleanSetting(_settings, "ScanPackersForProtection", false); }
set { _settings["ScanPackersForProtection"] = value.ToString(); }
}
/// <summary>
/// Force scanning all files for protection
/// </summary>
public bool ForceScanningForProtection
{
get { return GetBooleanSetting(_settings, "ForceScanningForProtection", false); }
set { _settings["ForceScanningForProtection"] = value.ToString(); }
}
/// <summary>
/// Include debug information with scan results
/// </summary>
public bool IncludeDebugProtectionInformation
{
get { return GetBooleanSetting(_settings, "IncludeDebugProtectionInformation", false); }
set { _settings["IncludeDebugProtectionInformation"] = value.ToString(); }
}
#endregion
#region Logging Options
/// <summary>
/// Enable verbose and debug logs to be written
/// </summary>
public bool VerboseLogging
{
get { return GetBooleanSetting(_settings, "VerboseLogging", true); }
set { _settings["VerboseLogging"] = value.ToString(); }
}
/// <summary>
/// Have the log panel expanded by default on startup
/// </summary>
public bool OpenLogWindowAtStartup
{
get { return GetBooleanSetting(_settings, "OpenLogWindowAtStartup", true); }
set { _settings["OpenLogWindowAtStartup"] = value.ToString(); }
}
/// <summary>
/// Enable fancy formatting of log statements
/// Disables EnableProgressProcessing if disabled
/// </summary>
/// <remarks>
/// This is mainly for outputting redirected console outputs. Not many
/// other bits of the logs include any specially handled outputs.
/// </remarks>
public bool EnableLogFormatting
{
get { return GetBooleanSetting(_settings, "EnableLogFormatting", false); }
set { _settings["EnableLogFormatting"] = value.ToString(); }
}
/// <summary>
/// Enable progress bar updating based on log text
/// Disabled if EnableLogFormatting is disabled
/// </summary>
public bool EnableProgressProcessing
{
get { return GetBooleanSetting(_settings, "EnableProgressProcessing", false); }
set { _settings["EnableProgressProcessing"] = value.ToString(); }
}
#endregion
#region Redump Login Information
public string RedumpUsername
{
get { return GetStringSetting(_settings, "RedumpUsername", ""); }
set { _settings["RedumpUsername"] = value; }
}
// TODO: Figure out a way to keep this encrypted in some way, BASE64 to start?
public string RedumpPassword
{
get { return GetStringSetting(_settings, "RedumpPassword", ""); }
set { _settings["RedumpPassword"] = value; }
}
/// <summary>
/// Determine if a complete set of Redump credentials might exist
/// </summary>
public bool HasRedumpLogin { get => !string.IsNullOrWhiteSpace(RedumpUsername) && !string.IsNullOrWhiteSpace(RedumpPassword); }
#endregion
/// <summary>
/// Constructor taking a dictionary for settings
/// </summary>
/// <param name="settings"></param>
public Options(Dictionary<string, string> settings = null)
{
this._settings = settings ?? new Dictionary<string, string>();
}
/// <summary>
/// Create a clone of the object
/// </summary>
public object Clone()
{
return new Options(new Dictionary<string, string>(_settings));
}
#region Helpers
/// <summary>
/// Get a Boolean setting from a settings, dictionary
/// </summary>
/// <param name="settings">Dictionary representing the settings</param>
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
private bool GetBooleanSetting(Dictionary<string, string> settings, string key, bool defaultValue)
{
if (settings.ContainsKey(key))
{
if (Boolean.TryParse(settings[key], out bool value))
return value;
else
return defaultValue;
}
else
{
return defaultValue;
}
}
/// <summary>
/// Get an Int32 setting from a settings, dictionary
/// </summary>
/// <param name="settings">Dictionary representing the settings</param>
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
private int GetInt32Setting(Dictionary<string, string> settings, string key, int defaultValue)
{
if (settings.ContainsKey(key))
{
if (Int32.TryParse(settings[key], out int value))
return value;
else
return defaultValue;
}
else
{
return defaultValue;
}
}
/// <summary>
/// Get a String setting from a settings, dictionary
/// </summary>
/// <param name="settings">Dictionary representing the settings</param>
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
private string GetStringSetting(Dictionary<string, string> settings, string key, string defaultValue)
{
if (settings.ContainsKey(key))
return settings[key];
else
return defaultValue;
}
#endregion
#region IDictionary implementations
public ICollection<string> Keys => _settings.Keys;
public ICollection<string> Values => _settings.Values;
public int Count => _settings.Count;
public bool IsReadOnly => ((IDictionary<string, string>)_settings).IsReadOnly;
public string this[string key]
{
get { return (_settings.ContainsKey(key) ? _settings[key] : null); }
set { _settings[key] = value; }
}
public bool ContainsKey(string key) => _settings.ContainsKey(key);
public void Add(string key, string value) => _settings.Add(key, value);
public bool Remove(string key) => _settings.Remove(key);
public bool TryGetValue(string key, out string value) => _settings.TryGetValue(key, out value);
public void Add(KeyValuePair<string, string> item) => _settings.Add(item.Key, item.Value);
public void Clear() => _settings.Clear();
public bool Contains(KeyValuePair<string, string> item) => ((IDictionary<string, string>)_settings).Contains(item);
public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex) => ((IDictionary<string, string>)_settings).CopyTo(array, arrayIndex);
public bool Remove(KeyValuePair<string, string> item) => ((IDictionary<string, string>)_settings).Remove(item);
public IEnumerator<KeyValuePair<string, string>> GetEnumerator() => _settings.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _settings.GetEnumerator();
#endregion
}
}

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