Compare commits

..

286 Commits
1.17.1 ... 2.0

Author SHA1 Message Date
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
142 changed files with 13918 additions and 23404 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,81 @@
### 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

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,27 +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 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();
// 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.1</Version>
<AssemblyVersion>1.17.1</AssemblyVersion>
<FileVersion>1.17.1</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,270 +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(new SubmissionInfo())
{
}
public DiscInformationWindow(SubmissionInfo submissionInfo)
{
this.SubmissionInfo = submissionInfo;
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,826 +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.Options.OpenLogWindowAtStartup)
{
//TODO: this should be bound directly to WindowVisible property in two way fashion
// we need to study how to properly do it in XAML
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.Options.SkipMediaTypeDetection)
{
ViewModels.LoggerViewModel.VerboseLog("Trying to detect media type for drive {0}.. ", drive.Letter);
CurrentMediaType = Validators.GetMediaType(drive);
ViewModels.LoggerViewModel.VerboseLogLn(CurrentMediaType == null ? "unable to detect." : ("detected " + CurrentMediaType.LongName() + "."));
}
}
}
/// <summary>
/// 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.Options.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.Options.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.Options.SkipSystemDetection && index != -1)
{
ViewModels.LoggerViewModel.VerboseLog("Trying to detect system for drive {0}.. ", Drives[index].Letter);
var currentSystem = Validators.GetKnownSystem(Drives[index]);
ViewModels.LoggerViewModel.VerboseLogLn(currentSystem == null || currentSystem == KnownSystem.NONE ? "unable to detect." : ("detected " + currentSystem.LongName() + "."));
if (currentSystem != null && currentSystem != KnownSystem.NONE)
{
int sysIndex = Systems.FindIndex(s => s == currentSystem);
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 = Interface.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>
/// Show the disc information window
/// </summary>
/// <param name="submissionInfo">SubmissionInfo object to display and possibly change</param>
/// <returns>Dialog open result</returns>
private bool? ShowDiscInformationWindow(SubmissionInfo submissionInfo)
{
var discInformationWindow = new DiscInformationWindow(submissionInfo);
discInformationWindow.Load();
discInformationWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
discInformationWindow.ShowDialog(this).ConfigureAwait(false).GetAwaiter().GetResult();
return true;
}
/// <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 = Interface.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 = Interface.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.Options.ResetDriveAfterDump,
ShowDiscInformationWindow
);
}
}
catch
{
// No-op, we don't care what it was
}
finally
{
this.Find<Button>("StartStopButton").Content = Interface.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 == Interface.StartDumping)
{
StartDumping();
}
else if ((string)this.Find<Button>("StartStopButton").Content == Interface.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.Options.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,110 +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; }
/// <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.1</Version>
<AssemblyVersion>1.17.1</AssemblyVersion>
<FileVersion>1.17.1</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>

File diff suppressed because it is too large Load Diff

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.1</Version>
<AssemblyVersion>1.17.1</AssemblyVersion>
<FileVersion>1.17.1</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,290 +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>();
}
#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
}
}

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,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,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,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.1</Version>
<AssemblyVersion>1.17.1</AssemblyVersion>
<FileVersion>1.17.1</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,110 +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; }
/// <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,235 +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
{
#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(SubmissionInfo submissionInfo)
{
this.SubmissionInfo = submissionInfo;
InitializeComponent();
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,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

@@ -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,48 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;netcoreapp3.1</TargetFrameworks>
<OutputType>Exe</OutputType>
<Prefer32Bit>true</Prefer32Bit>
<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.0</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.6.1" GeneratePathProperty="true">
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.0" />
</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,4 +1,4 @@
namespace DICUI.Aaru
namespace MPF.Aaru
{
/// <summary>
/// Top-level commands for Aaru

View File

@@ -1,6 +1,6 @@
using DICUI.Data;
using MPF.Data;
namespace DICUI.Aaru
namespace MPF.Aaru
{
public static class Converters
{
@@ -14,7 +14,7 @@ namespace DICUI.Aaru
public static string Extension(MediaType? type)
{
// Aaru has a single, unified output format by default
return ".aif";
return ".aaruf";
}
#endregion

View File

@@ -1,4 +1,4 @@
namespace DICUI.Aaru
namespace MPF.Aaru
{
/// <summary>
/// Supported Aaru commands

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,60 @@
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;
using MPF.Utilities;
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)
{
}
/// <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";
missingFiles.Add($"{basePath}-dumpinfo.txt");
if (!File.Exists($"{basePath}.bca"))
missingFiles += $";{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 +72,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 +88,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 +201,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 +236,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,201 @@
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>
public CueFile(string fileName, string fileType, string[] cueLines, ref int i)
{
if (cueLines == null || i < 0 || i > cueLines.Length)
return; // TODO: Make this throw an exception
// 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)
continue; // TODO: Make this throw an exception
if (this.Tracks == null)
this.Tracks = new List<CueTrack>();
var track = new CueTrack(splitLine[1], splitLine[2], cueLines, ref i);
if (track == default)
continue; // TODO: Make this throw an exception
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>
public void Write(StreamWriter sw)
{
// If we don't have any tracks, it's invalid
if (this.Tracks == null || this.Tracks.Count == 0)
return; // TODO: Make this throw an exception
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,106 @@
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>
public CueIndex(string index, string startTime)
{
// Set the current fields
if (!int.TryParse(index, out int parsedIndex))
return; // TODO: Make this throw an exception
else if (parsedIndex < 0 || parsedIndex > 99)
return; // TODO: Make this throw an exception
// Ignore empty lines
if (string.IsNullOrWhiteSpace(startTime))
return; // TODO: Make this throw an exception
// Ignore lines that don't contain the correct information
if (startTime.Length != 8 || startTime.Count(c => c == ':') != 2)
return; // TODO: Make this throw an exception
// Split the line
string[] splitTime = startTime.Split(':');
if (splitTime.Length != 3)
return; // TODO: Make this throw an exception
// Parse the lengths
int[] lengthSegments = new int[3];
// Minutes
if (!int.TryParse(splitTime[0], out lengthSegments[0]))
return; // TODO: Make this throw an exception
else if (lengthSegments[0] < 0)
return; // TODO: Make this throw an exception
// Seconds
if (!int.TryParse(splitTime[1], out lengthSegments[1]))
return; // TODO: Make this throw an exception
else if (lengthSegments[1] < 0 || lengthSegments[1] > 60)
return; // TODO: Make this throw an exception
// Frames
if (!int.TryParse(splitTime[2], out lengthSegments[2]))
return; // TODO: Make this throw an exception
else if (lengthSegments[2] < 0 || lengthSegments[2] > 75)
return; // TODO: Make this throw an exception
// 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,201 @@
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>
public CueSheet(string filename)
{
// 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)
continue; // TODO: Make this throw an exception
this.Catalog = splitLine[1];
break;
// Read external CD-Text file path
case "CDTEXTFILE":
if (splitLine.Length < 2)
continue; // TODO: Make this throw an exception
this.CdTextFile = splitLine[1];
break;
// Read CD-Text enhanced performer
case "PERFORMER":
if (splitLine.Length < 2)
continue; // TODO: Make this throw an exception
this.Performer = splitLine[1];
break;
// Read CD-Text enhanced songwriter
case "SONGWRITER":
if (splitLine.Length < 2)
continue; // TODO: Make this throw an exception
this.Songwriter = splitLine[1];
break;
// Read CD-Text enhanced title
case "TITLE":
if (splitLine.Length < 2)
continue; // TODO: Make this throw an exception
this.Title = splitLine[1];
break;
// Read file information
case "FILE":
if (splitLine.Length < 3)
continue; // TODO: Make this throw an exception
if (this.Files == null)
this.Files = new List<CueFile>();
var file = new CueFile(splitLine[1], splitLine[2], cueLines, ref i);
if (file == default)
continue; // TODO: Make this throw an exception
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>
public void Write(Stream stream)
{
// If we don't have any files, it's invalid
if (this.Files == null || this.Files.Count == 0)
return; // TODO: Make this throw an exception
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,464 @@
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>
public CueTrack(string number, string dataType, string[] cueLines, ref int i)
{
if (cueLines == null || i < 0 || i > cueLines.Length)
return; // TODO: Make this throw an exception
// Set the current fields
if (!int.TryParse(number, out int parsedNumber))
return; // TODO: Make this throw an exception
else if (parsedNumber < 1 || parsedNumber > 99)
return; // TODO: Make this throw an exception
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)
continue; // TODO: Make this throw an exception
this.Flags = GetFlags(splitLine);
break;
// Read International Standard Recording Code
case "ISRC":
if (splitLine.Length < 2)
continue; // TODO: Make this throw an exception
this.ISRC = splitLine[1];
break;
// Read CD-Text enhanced performer
case "PERFORMER":
if (splitLine.Length < 2)
continue; // TODO: Make this throw an exception
this.Performer = splitLine[1];
break;
// Read CD-Text enhanced songwriter
case "SONGWRITER":
if (splitLine.Length < 2)
continue; // TODO: Make this throw an exception
this.Songwriter = splitLine[1];
break;
// Read CD-Text enhanced title
case "TITLE":
if (splitLine.Length < 2)
continue; // TODO: Make this throw an exception
this.Title = splitLine[1];
break;
// Read pregap information
case "PREGAP":
if (splitLine.Length < 2)
continue; // TODO: Make this throw an exception
var pregap = new PreGap(splitLine[1]);
if (pregap == default)
continue; // TODO: Make this throw an exception
this.PreGap = pregap;
break;
// Read index information
case "INDEX":
if (splitLine.Length < 3)
continue; // TODO: Make this throw an exception
if (this.Indices == null)
this.Indices = new List<CueIndex>();
var index = new CueIndex(splitLine[1], splitLine[2]);
if (index == default)
continue; // TODO: Make this throw an exception
this.Indices.Add(index);
break;
// Read postgap information
case "POSTGAP":
if (splitLine.Length < 2)
continue; // TODO: Make this throw an exception
var postgap = new PostGap(splitLine[1]);
if (postgap == default)
continue; // TODO: Make this throw an exception
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>
public void Write(StreamWriter sw)
{
// If we don't have any indices, it's invalid
if (this.Indices == null || this.Indices.Count == 0)
return; // TODO: Make this throw an exception
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)
{
// TODO: Make default throw an exception
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,92 @@
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>
public PostGap(string length)
{
// Ignore empty lines
if (string.IsNullOrWhiteSpace(length))
return; // TODO: Make this throw an exception
// Ignore lines that don't contain the correct information
if (length.Length != 8 || length.Count(c => c == ':') != 2)
return; // TODO: Make this throw an exception
// Split the line
string[] splitLength = length.Split(':');
if (splitLength.Length != 3)
return; // TODO: Make this throw an exception
// Parse the lengths
int[] lengthSegments = new int[3];
// Minutes
if (!int.TryParse(splitLength[0], out lengthSegments[0]))
return; // TODO: Make this throw an exception
else if (lengthSegments[0] < 0)
return; // TODO: Make this throw an exception
// Seconds
if (!int.TryParse(splitLength[1], out lengthSegments[1]))
return; // TODO: Make this throw an exception
else if (lengthSegments[1] < 0 || lengthSegments[1] > 60)
return; // TODO: Make this throw an exception
// Frames
if (!int.TryParse(splitLength[2], out lengthSegments[2]))
return; // TODO: Make this throw an exception
else if (lengthSegments[2] < 0 || lengthSegments[2] > 75)
return; // TODO: Make this throw an exception
// 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,93 @@
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>
public PreGap(string length)
{
// Ignore empty lines
if (string.IsNullOrWhiteSpace(length))
return; // TODO: Make this throw an exception
// Ignore lines that don't contain the correct information
if (length.Length != 8 || length.Count(c => c == ':') != 2)
return; // TODO: Make this throw an exception
// Split the line
string[] splitLength = length.Split(':');
if (splitLength.Length != 3)
return; // TODO: Make this throw an exception
// Parse the lengths
int[] lengthSegments = new int[3];
// Minutes
if (!int.TryParse(splitLength[0], out lengthSegments[0]))
return; // TODO: Make this throw an exception
else if (lengthSegments[0] < 0)
return; // TODO: Make this throw an exception
// Seconds
if (!int.TryParse(splitLength[1], out lengthSegments[1]))
return; // TODO: Make this throw an exception
else if (lengthSegments[1] < 0 || lengthSegments[1] > 60)
return; // TODO: Make this throw an exception
// Frames
if (!int.TryParse(splitLength[2], out lengthSegments[2]))
return; // TODO: Make this throw an exception
else if (lengthSegments[2] < 0 || lengthSegments[2] > 75)
return; // TODO: Make this throw an exception
// 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,4 +1,4 @@
namespace DICUI.DD
namespace MPF.DD
{
/// <summary>
/// Top-level commands for DD

View File

@@ -1,6 +1,6 @@
using DICUI.Data;
using MPF.Data;
namespace DICUI.DD
namespace MPF.DD
{
public static class Converters
{

View File

@@ -1,4 +1,4 @@
namespace DICUI.DD
namespace MPF.DD
{
/// <summary>
/// Supported DD commands

View File

@@ -3,22 +3,46 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using DICUI.Data;
using DICUI.Utilities;
using DICUI.Web;
using MPF.Data;
using MPF.Utilities;
namespace DICUI.DD
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;
/// <inheritdoc/>
public override string OutputPath => OutputFileValue;
/// <inheritdoc/>
/// <inheritdoc/>
public override int? Speed
{
get { return 1; }
set { }
}
#endregion
#region Metadata
/// <summary>
/// Base command to run
/// </summary>
public Command BaseCommand { get; set; }
/// <inheritdoc/>
public override InternalProgram InternalProgram => InternalProgram.DD;
#endregion
/// <summary>
/// Set of flags to pass to the executable
/// </summary>
@@ -58,36 +82,81 @@ namespace DICUI.DD
#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;
}
/// <inheritdoc/>
public Parameters(string parameters) : base(parameters) { }
/// <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 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>
#region BaseParameters Implementations
/// <inheritdoc/>
public override (bool, List<string>) CheckAllOutputFilesExist(string basePath)
{
// 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>();
@@ -177,45 +246,10 @@ namespace DICUI.DD
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;
/// <inheritdoc/>
public override string GetDefaultExtension(MediaType? mediaType) => Converters.Extension(mediaType);
/// <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>
/// <inheritdoc/>
public override bool IsDumpingCommand()
{
switch (this.BaseCommand)
@@ -227,9 +261,7 @@ namespace DICUI.DD
}
}
/// <summary>
/// Reset all special variables to have default values
/// </summary>
/// <inheritdoc/>
protected override void ResetValues()
{
BaseCommand = Command.NONE;
@@ -244,24 +276,8 @@ namespace DICUI.DD
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)
/// <inheritdoc/>
protected override void SetDefaultParameters(char driveLetter, string filename, int? driveSpeed, Options options)
{
BaseCommand = Command.NONE;
@@ -273,7 +289,7 @@ namespace DICUI.DD
// TODO: Add more common block sizes
this[Flag.BlockSize] = true;
switch (type)
switch (this.Type)
{
case MediaType.FloppyDisk:
BlockSizeValue = 1440 * 1024;
@@ -288,11 +304,7 @@ namespace DICUI.DD
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>
/// <inheritdoc/>
protected override bool ValidateAndSetParameters(string parameters)
{
// The string has to be valid by itself first
@@ -393,78 +405,9 @@ namespace DICUI.DD
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;
}
#endregion
/// <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;
}
}
#region Private Extra Methods
/// <summary>
/// Get the list of commands that use a given flag
@@ -526,6 +469,10 @@ namespace DICUI.DD
return commands;
}
#endregion
#region Process Parameter Helpers
/// <summary>
/// Process a boolean parameter
/// </summary>
@@ -664,5 +611,7 @@ namespace DICUI.DD
return string.Empty;
}
#endregion
}
}

View File

@@ -2,15 +2,63 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using DICUI.Utilities;
using DICUI.Web;
using BurnOutSharp.ProtectionType;
using Compress.ThreadReaders;
using MPF.Hashing;
namespace DICUI.Data
namespace MPF.Data
{
public abstract class BaseParameters
{
#region Event Handlers
/// <summary>
/// Geneeic way of reporting a message
/// </summary>
/// <param name="message">String value to report</param>
public EventHandler<string> ReportStatus;
/// <summary>
/// Event handler for data returned from a process
/// </summary>
private void OutputToLog(object proc, DataReceivedEventArgs args)
{
ReportStatus.Invoke(this, args.Data);
}
#endregion
#region Generic Dumping Information
/// <summary>
/// Input path for operations
/// </summary>
public virtual string InputPath => null;
/// <summary>
/// Output path for operations
/// </summary>
/// <returns>String representing the path, null on error</returns>
public virtual string OutputPath => null;
/// <summary>
/// Get the processing speed from the implementation
/// </summary>
public virtual int? Speed { get; set; } = null;
/// <summary>
/// Process to track external program
/// </summary>
private Process process;
#endregion
#region Metadata
/// <summary>
/// Path to the executable
/// </summary>
@@ -19,12 +67,19 @@ namespace DICUI.Data
/// <summary>
/// Program that this set of parameters represents
/// </summary>
public InternalProgram InternalProgram { get; set; }
public virtual InternalProgram InternalProgram { get; }
/// <summary>
/// Process to track external program
/// Currently represented system
/// </summary>
private Process process;
public KnownSystem? System { get; set; }
/// <summary>
/// Currently represented media type
/// </summary>
public MediaType? Type { get; set; }
#endregion
/// <summary>
/// Populate a Parameters object from a param string
@@ -34,9 +89,7 @@ namespace DICUI.Data
{
// If any parameters are not valid, wipe out everything
if (!ValidateAndSetParameters(parameters))
{
ResetValues();
}
}
/// <summary>
@@ -47,169 +100,138 @@ namespace DICUI.Data
/// <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)
/// <param name="options">Options object containing all settings that may be used for setting parameters</param>
public BaseParameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
{
SetDefaultParameters(system, type, driveLetter, filename, driveSpeed, paranoid, retryCount);
this.System = system;
this.Type = type;
SetDefaultParameters(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 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);
#region Abstract Methods
/// <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);
/// <returns>Tuple of true if all required files exist, false otherwise and a list representing missing files</returns>
public abstract (bool, List<string>) CheckAllOutputFilesExist(string basePath);
/// <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);
/// <param name="includeArtifacts">True to include output files as encoded artifacts, false otherwise</param>
public abstract void GenerateSubmissionInfo(SubmissionInfo submissionInfo, string basePath, Drive drive, bool includeArtifacts);
#endregion
#region Virtual Methods
/// <summary>
/// Blindly generate a parameter string based on the inputs
/// </summary>
/// <returns>Parameter string for invocation, null on error</returns>
public virtual string GenerateParameters() => null;
/// <summary>
/// Get the default extension for a given media type
/// </summary>
/// <param name="mediaType">MediaType value to check</param>
/// <returns>String representing the media type, null on error</returns>
public virtual string GetDefaultExtension(MediaType? mediaType) => null;
/// <summary>
/// Generate a list of all log files generated
/// </summary>
/// <param name="basePath">Base filename and path to use for checking</param>
/// <returns>List of all log file paths, empty otherwise</returns>
public virtual List<string> GetLogFilePaths(string basePath) => new List<string>();
/// <summary>
/// Get the MediaType from the current set of parameters
/// </summary>
/// <returns>MediaType value if successful, null on error</returns>
public virtual 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 virtual bool IsDumpingCommand() => true;
/// <summary>
/// Returns if the current Parameter object is valid
/// </summary>
/// <returns></returns>
public bool IsValid() => GenerateParameters() != null;
/// <summary>
/// Reset all special variables to have default values
/// </summary>
protected virtual void ResetValues() { }
/// <summary>
/// Set default parameters for a given system and media type
/// </summary>
/// <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="options">Options object containing all settings that may be used for setting parameters</param>
protected virtual void SetDefaultParameters(char driveLetter, string filename, int? driveSpeed, Options options) { }
/// <summary>
/// Scan a possible parameter string and populate whatever possible
/// </summary>
/// <param name="parameters">String possibly representing parameters</param>
/// <returns>True if the parameters were set correctly, false otherwise</returns>
protected virtual bool ValidateAndSetParameters(string parameters) => true;
#endregion
#region Execution
/// <summary>
/// Run internal program
/// </summary>
public void ExecuteInternalProgram()
/// <param name="separateWindow">True to show in separate window, false otherwise</param>
public void ExecuteInternalProgram(bool separateWindow)
{
process = new Process()
// Create the start info
var startInfo = new ProcessStartInfo()
{
StartInfo = new ProcessStartInfo()
{
FileName = ExecutablePath,
Arguments = GenerateParameters() ?? "",
},
FileName = ExecutablePath,
Arguments = GenerateParameters() ?? "",
CreateNoWindow = !separateWindow,
UseShellExecute = separateWindow,
RedirectStandardOutput = !separateWindow,
RedirectStandardError = !separateWindow,
};
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(() =>
// Create the new process
process = new Process() { StartInfo = startInfo };
// Add event handlers, if necessary
if (!separateWindow)
{
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);
process.OutputDataReceived += OutputToLog;
process.ErrorDataReceived += OutputToLog;
}
// 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");
// Start the process
process.Start();
string stdout = childProcess.StandardOutput.ReadToEnd();
childProcess.Dispose();
return stdout;
});
// Begin reading the outputs, if necessary
if (!separateWindow)
{
process.BeginOutputReadLine();
process.BeginErrorReadLine();
}
return output;
process.WaitForExit();
process.Close();
}
/// <summary>
@@ -219,13 +241,17 @@ namespace DICUI.Data
{
try
{
if (process != null && !process.HasExited)
while (process != null && !process.HasExited)
{
process.Kill();
}
}
catch
{ }
}
#endregion
#region Parameter Parsing
/// <summary>
@@ -242,6 +268,20 @@ namespace DICUI.Data
return true;
}
/// <summary>
/// Get the Base64 representation of a string
/// </summary>
/// <param name="content">String content to encode</param>
/// <returns>Base64-encoded contents, if possible</returns>
protected static string GetBase64(string content)
{
if (string.IsNullOrEmpty(content))
return null;
byte[] temp = Encoding.UTF8.GetBytes(content);
return Convert.ToBase64String(temp);
}
/// <summary>
/// Get the full lines from the input file, if possible
/// </summary>
@@ -257,15 +297,8 @@ namespace DICUI.Data
// 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;
byte[] bytes = File.ReadAllBytes(filename);
return BitConverter.ToString(bytes).Replace("-", string.Empty);
}
return string.Join("\n", File.ReadAllLines(filename));
@@ -387,6 +420,113 @@ namespace DICUI.Data
#region Common Information Extraction
/// <summary>
/// Get hashes from an input file path
/// </summary>
/// <param name="filename">Path to the input file</param>
/// <returns>True if hashing was successful, false otherwise</returns>
protected static bool GetFileHashes(string filename, out long size, out string crc32, out string md5, out string sha1)
{
// Set all initial values
size = -1; crc32 = null; md5 = null; sha1 = null;
// If the file doesn't exist, we can't do anything
if (!File.Exists(filename))
return false;
// Set the file size
size = new FileInfo(filename).Length;
// Open the input file
var input = File.OpenRead(filename);
try
{
// Get a list of hashers to run over the buffer
List<Hasher> hashers = new List<Hasher>
{
new Hasher(Hash.CRC),
new Hasher(Hash.MD5),
new Hasher(Hash.SHA1),
new Hasher(Hash.SHA256),
new Hasher(Hash.SHA384),
new Hasher(Hash.SHA512),
};
// Initialize the hashing helpers
var loadBuffer = new ThreadLoadBuffer(input);
int buffersize = 3 * 1024 * 1024;
byte[] buffer0 = new byte[buffersize];
byte[] buffer1 = new byte[buffersize];
/*
Please note that some of the following code is adapted from
RomVault. This is a modified version of how RomVault does
threaded hashing. As such, some of the terminology and code
is the same, though variable names and comments may have
been tweaked to better fit this code base.
*/
// Pre load the first buffer
long refsize = size;
int next = refsize > buffersize ? buffersize : (int)refsize;
input.Read(buffer0, 0, next);
int current = next;
refsize -= next;
bool bufferSelect = true;
while (current > 0)
{
// Trigger the buffer load on the second buffer
next = refsize > buffersize ? buffersize : (int)refsize;
if (next > 0)
loadBuffer.Trigger(bufferSelect ? buffer1 : buffer0, next);
byte[] buffer = bufferSelect ? buffer0 : buffer1;
// Run hashes in parallel
Parallel.ForEach(hashers, h => h.Process(buffer, current));
// Wait for the load buffer worker, if needed
if (next > 0)
loadBuffer.Wait();
// Setup for the next hashing step
current = next;
refsize -= next;
bufferSelect = !bufferSelect;
}
// Finalize all hashing helpers
loadBuffer.Finish();
Parallel.ForEach(hashers, h => h.Terminate());
// Get the results
crc32 = hashers.First(h => h.HashType == Hash.CRC).GetHashString();
md5 = hashers.First(h => h.HashType == Hash.MD5).GetHashString();
sha1 = hashers.First(h => h.HashType == Hash.SHA1).GetHashString();
//sha256 = hashers.First(h => h.HashType == Hash.SHA256).GetHashString();
//sha384 = hashers.First(h => h.HashType == Hash.SHA384).GetHashString();
//sha512 = hashers.First(h => h.HashType == Hash.SHA512).GetHashString();
// Dispose of the hashers
loadBuffer.Dispose();
hashers.ForEach(h => h.Dispose());
return true;
}
catch (IOException ex)
{
return false;
}
finally
{
input.Dispose();
}
return false;
}
/// <summary>
/// Get the split values for ISO-based media
/// </summary>
@@ -431,17 +571,15 @@ namespace DICUI.Data
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
var antiModchip = new PSXAntiModchip();
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))
byte[] fileContent = File.ReadAllBytes(path);
string protection = antiModchip.CheckContents(path, fileContent, includePosition: false);
if (!string.IsNullOrWhiteSpace(protection))
return true;
}
catch
@@ -461,7 +599,7 @@ namespace DICUI.Data
/// <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)
protected static bool GetPlayStationExecutableInfo(char? driveLetter, out string serial, out RedumpRegion? region, out string date)
{
serial = null; region = null; date = null;
@@ -595,6 +733,43 @@ namespace DICUI.Data
}
}
/// <summary>
/// Get the version from a PlayStation 5 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 GetPlayStation5Version(char? driveLetter)
{
// If there's no drive letter, we can't do this part
if (driveLetter == null)
return null;
// If the folder no longer exists, we can't do this part
string drivePath = driveLetter + ":\\";
if (!Directory.Exists(drivePath))
return null;
// If we can't find param.json, we don't have a PlayStation 5 disc
string paramJsonPath = Path.Combine(drivePath, "bd", "param.json");
if (!File.Exists(paramJsonPath))
return null;
// Let's try reading param.json to find the version in the unencrypted JSON
try
{
using (BinaryReader br = new BinaryReader(File.OpenRead(paramJsonPath)))
{
br.BaseStream.Seek(0x89E, SeekOrigin.Begin);
return new string(br.ReadChars(5));
}
}
catch
{
// We don't care what the error was
return null;
}
}
#endregion
#region Category Extraction
@@ -604,16 +779,16 @@ namespace DICUI.Data
/// </summary>
/// <param name="region">String representing the category</param>
/// <returns>Category, if possible</returns>
protected static DiscCategory? GetUMDCategory(string category)
protected static RedumpDiscCategory? GetUMDCategory(string category)
{
switch (category)
{
case "GAME":
return DiscCategory.Games;
return RedumpDiscCategory.Games;
case "VIDEO":
return DiscCategory.Video;
return RedumpDiscCategory.Video;
case "AUDIO":
return DiscCategory.Audio;
return RedumpDiscCategory.Audio;
default:
return null;
}
@@ -628,7 +803,7 @@ namespace DICUI.Data
/// </summary>
/// <param name="serial">PlayStation serial code</param>
/// <returns>Region mapped from name, if possible</returns>
protected static Region? GetPlayStationRegion(string serial)
protected static RedumpRegion? GetPlayStationRegion(string serial)
{
// Standardized "S" serials
if (serial.StartsWith("S"))
@@ -638,25 +813,25 @@ namespace DICUI.Data
switch (serial[2])
{
case 'A':
return Region.Asia;
return RedumpRegion.Asia;
case 'C':
return Region.China;
return RedumpRegion.China;
case 'E':
return Region.Europe;
return RedumpRegion.Europe;
case 'J':
return Region.JapanKorea;
return RedumpRegion.JapanKorea;
case 'K':
return Region.Korea;
return RedumpRegion.Korea;
case 'P':
return Region.Japan;
return RedumpRegion.Japan;
case 'U':
return Region.USA;
return RedumpRegion.USA;
}
}
// Japan-only special serial
else if (serial.StartsWith("PAPX"))
return Region.Japan;
return RedumpRegion.Japan;
// Region appears entirely random
else if (serial.StartsWith("PABX"))
@@ -664,15 +839,15 @@ namespace DICUI.Data
// Japan-only special serial
else if (serial.StartsWith("PCBX"))
return Region.Japan;
return RedumpRegion.Japan;
// Single disc known, Japan
else if (serial.StartsWith("PDBX"))
return Region.Japan;
return RedumpRegion.Japan;
// Single disc known, Europe
else if (serial.StartsWith("PEBX"))
return Region.Europe;
return RedumpRegion.Europe;
return null;
}
@@ -682,24 +857,24 @@ namespace DICUI.Data
/// </summary>
/// <param name="region">Character denoting the region</param>
/// <returns>Region, if possible</returns>
protected static Region? GetXgdRegion(char region)
protected static RedumpRegion? GetXgdRegion(char region)
{
switch (region)
{
case 'W':
return Region.World;
return RedumpRegion.World;
case 'A':
return Region.USA;
return RedumpRegion.USA;
case 'J':
return Region.JapanAsia;
return RedumpRegion.JapanAsia;
case 'E':
return Region.Europe;
return RedumpRegion.Europe;
case 'K':
return Region.USAJapan;
return RedumpRegion.USAJapan;
case 'L':
return Region.USAEurope;
return RedumpRegion.USAEurope;
case 'H':
return Region.JapanEurope;
return RedumpRegion.JapanEurope;
default:
return null;
}

View File

@@ -1,7 +1,7 @@
using System.Collections.Generic;
using System.Linq;
namespace DICUI.Data
namespace MPF.Data
{
/// <summary>
/// Constant values for UI
@@ -12,6 +12,9 @@ namespace DICUI.Data
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();

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>
{

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

@@ -0,0 +1,511 @@
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>
/// 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>
/// 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 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
}
}

View File

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

View File

@@ -1,4 +1,4 @@
namespace DICUI.Utilities
namespace MPF.Data
{
/// <summary>
/// Generic success/failure result object, with optional message
@@ -32,13 +32,6 @@
/// <param name="message">String to add as a message</param>
public static Result Success(string message) => new Result(true, message);
/// <summary>
/// Create a success result with a custom message with format parameters
/// </summary>
/// <param name="message">String to add as a message</param>
/// <param name="args">Formatting parameters for the string</param>
public static Result Success(string message, params object[] args) => new Result(true, string.Format(message, args));
/// <summary>
/// Create a default failure result with no message
/// </summary>
@@ -51,13 +44,6 @@
/// <param name="message">String to add as a message</param>
public static Result Failure(string message) => new Result(false, message);
/// <summary>
/// Create a failure result with a custom message with format parameters
/// </summary>
/// <param name="message">String to add as a message</param>
/// <param name="args">Formatting parameters for the string</param>
public static Result Failure(string message, params object[] args) => new Result(false, string.Format(message, args));
/// <summary>
/// Results can be compared to boolean values based on the success value
/// </summary>

View File

@@ -1,14 +1,20 @@
using System;
using System.Collections.Generic;
using DICUI.Data;
using DICUI.Utilities;
using MPF.Data;
using MPF.Utilities;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace DICUI.Web
namespace MPF.Data
{
public class SubmissionInfo
{
/// <summary>
/// Version of the current schema
/// </summary>
[JsonProperty(PropertyName = "schema_version", DefaultValueHandling = DefaultValueHandling.Ignore)]
public int SchemaVersion { get; set; } = 1;
/// <summary>
/// List of matched Redump IDs
/// </summary>
@@ -53,6 +59,9 @@ namespace DICUI.Web
[JsonProperty(PropertyName = "size_and_checksums", DefaultValueHandling = DefaultValueHandling.Ignore)]
public SizeAndChecksumsSection SizeAndChecksums { get; set; } = new SizeAndChecksumsSection();
[JsonProperty(PropertyName = "artifacts", DefaultValueHandling = DefaultValueHandling.Ignore)]
public Dictionary<string, string> Artifacts { get; set; } = new Dictionary<string, string>();
}
/// <summary>
@@ -66,7 +75,6 @@ namespace DICUI.Web
public KnownSystem? System { get; set; }
// Name not defined by Redump
// TODO: Have this convert to a new `RedumpMedia?` if possible, for submission
[JsonProperty(PropertyName = "d_media", Required = Required.AllowNull)]
[JsonConverter(typeof(MediaTypeConverter))]
public MediaType? Media { get; set; }
@@ -84,19 +92,19 @@ namespace DICUI.Web
public string DiscTitle { get; set; }
[JsonProperty(PropertyName = "d_category", Required = Required.AllowNull)]
public DiscCategory? Category { get; set; }
public RedumpDiscCategory? Category { get; set; }
[JsonProperty(PropertyName = "d_region", Required = Required.AllowNull)]
[JsonConverter(typeof(RegionConverter))]
public Region? Region { get; set; }
[JsonConverter(typeof(RedumpRegionConverter))]
public RedumpRegion? Region { get; set; }
[JsonProperty(PropertyName = "d_languages", Required = Required.AllowNull)]
[JsonConverter(typeof(LanguagesConverter))]
public Language?[] Languages { get; set; }
[JsonConverter(typeof(RedumpLanguageConverter))]
public RedumpLanguage?[] Languages { get; set; }
[JsonProperty(PropertyName = "d_languages_selection", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore)]
[JsonConverter(typeof(LanguageSelectionConverter))]
public LanguageSelection?[] LanguageSelection { get; set; }
[JsonConverter(typeof(RedumpLanguageSelectionConverter))]
public RedumpLanguageSelection?[] LanguageSelection { get; set; }
[JsonProperty(PropertyName = "d_serial", NullValueHandling = NullValueHandling.Ignore)]
public string Serial { get; set; }
@@ -108,34 +116,52 @@ namespace DICUI.Web
public string RingId { get; }
[JsonProperty(PropertyName = "d_ring_0_ma1", Required = Required.AllowNull)]
public string MasteringRingFirstLayerDataSide { get; set; }
public string Layer0MasteringRing { get; set; }
[JsonProperty(PropertyName = "d_ring_0_ma1_sid", NullValueHandling = NullValueHandling.Ignore)]
public string MasteringSIDCodeFirstLayerDataSide { get; set; }
public string Layer0MasteringSID { get; set; }
[JsonProperty(PropertyName = "d_ring_0_ts1", NullValueHandling = NullValueHandling.Ignore)]
public string ToolstampMasteringCodeFirstLayerDataSide { get; set; }
public string Layer0ToolstampMasteringCode { get; set; }
[JsonProperty(PropertyName = "d_ring_0_mo1_sid", NullValueHandling = NullValueHandling.Ignore)]
public string MouldSIDCodeFirstLayerDataSide { get; set; }
public string Layer0MouldSID { get; set; }
[JsonProperty(PropertyName = "dr_ring_0_mo1", NullValueHandling = NullValueHandling.Ignore)]
public string AdditionalMouldFirstLayerDataSide { get; set; }
public string Layer0AdditionalMould { get; set; }
[JsonProperty(PropertyName = "d_ring_0_ma2", NullValueHandling = NullValueHandling.Ignore)]
public string MasteringRingSecondLayerLabelSide { get; set; }
[JsonProperty(PropertyName = "d_ring_0_ma2", Required = Required.AllowNull)]
public string Layer1MasteringRing { get; set; }
[JsonProperty(PropertyName = "d_ring_0_ma2_sid", NullValueHandling = NullValueHandling.Ignore)]
public string MasteringSIDCodeSecondLayerLabelSide { get; set; }
public string Layer1MasteringSID { get; set; }
[JsonProperty(PropertyName = "d_ring_0_ts2", NullValueHandling = NullValueHandling.Ignore)]
public string ToolstampMasteringCodeSecondLayerLabelSide { get; set; }
public string Layer1ToolstampMasteringCode { get; set; }
[JsonProperty(PropertyName = "d_ring_0_mo2_sid", NullValueHandling = NullValueHandling.Ignore)]
public string MouldSIDCodeSecondLayerLabelSide { get; set; }
public string Layer1MouldSID { get; set; }
[JsonProperty(PropertyName = "dr_ring_0_mo2", NullValueHandling = NullValueHandling.Ignore)]
public string AdditionalMouldSecondLayerLabelSide { get; set; }
public string Layer1AdditionalMould { get; set; }
[JsonProperty(PropertyName = "d_ring_0_ma3", Required = Required.AllowNull)]
public string Layer2MasteringRing { get; set; }
[JsonProperty(PropertyName = "d_ring_0_ma3_sid", NullValueHandling = NullValueHandling.Ignore)]
public string Layer2MasteringSID { get; set; }
[JsonProperty(PropertyName = "d_ring_0_ts3", NullValueHandling = NullValueHandling.Ignore)]
public string Layer2ToolstampMasteringCode { get; set; }
[JsonProperty(PropertyName = "d_ring_0_ma4", Required = Required.AllowNull)]
public string Layer3MasteringRing { get; set; }
[JsonProperty(PropertyName = "d_ring_0_ma4_sid", NullValueHandling = NullValueHandling.Ignore)]
public string Layer3MasteringSID { get; set; }
[JsonProperty(PropertyName = "d_ring_0_ts4", NullValueHandling = NullValueHandling.Ignore)]
public string Layer3ToolstampMasteringCode { get; set; }
[JsonProperty(PropertyName = "d_ring_0_offsets", NullValueHandling = NullValueHandling.Ignore)]
public string RingOffsetsHidden { get { return "1"; } }
@@ -261,7 +287,7 @@ namespace DICUI.Web
public class DumpersAndStatusSection
{
[JsonProperty(PropertyName = "d_status", NullValueHandling = NullValueHandling.Ignore)]
public DumpStatus Status { get; set; }
public RedumpDumpStatus Status { get; set; }
[JsonProperty(PropertyName = "d_dumpers", NullValueHandling = NullValueHandling.Ignore)]
public string[] Dumpers { get; set; }
@@ -289,13 +315,19 @@ namespace DICUI.Web
}
/// <summary>
/// Size & checksums section of New Disc form (DVD/BD/UMD-based)
/// Size &amp; checksums section of New Disc form (DVD/BD/UMD-based)
/// </summary>
public class SizeAndChecksumsSection
{
[JsonProperty(PropertyName = "d_layerbreak", NullValueHandling = NullValueHandling.Ignore)]
public long Layerbreak { get; set; }
[JsonProperty(PropertyName = "d_layerbreak_2", NullValueHandling = NullValueHandling.Ignore)]
public long Layerbreak2 { get; set; }
[JsonProperty(PropertyName = "d_layerbreak_3", NullValueHandling = NullValueHandling.Ignore)]
public long Layerbreak3 { get; set; }
[JsonProperty(PropertyName = "d_size", NullValueHandling = NullValueHandling.Ignore)]
public long Size { get; set; }

View File

@@ -1,4 +1,4 @@
namespace DICUI.DiscImageCreator
namespace MPF.DiscImageCreator
{
/// <summary>
/// Top-level commands for DiscImageCreator
@@ -47,6 +47,7 @@ namespace DICUI.DiscImageCreator
public const string ExtractMicroSoftCabFile = "/mscf";
public const string Fix = "/fix";
public const string ForceUnitAccess = "/f";
public const string MultiSectorRead = "/mr";
public const string MultiSession = "/ms";
public const string NoFixSubP = "/np";
public const string NoFixSubQ = "/nq";
@@ -54,6 +55,7 @@ namespace DICUI.DiscImageCreator
public const string NoFixSubRtoW = "/nr";
public const string NoFixSubQSecuROM = "/ns";
public const string NoSkipSS = "/nss";
public const string PadSector = "/ps";
public const string Raw = "/raw";
public const string Resume = "/re";
public const string Reverse = "/r";

View File

@@ -1,6 +1,6 @@
using DICUI.Data;
using MPF.Data;
namespace DICUI.DiscImageCreator
namespace MPF.DiscImageCreator
{
public static class Converters
{
@@ -218,6 +218,8 @@ namespace DICUI.DiscImageCreator
return FlagStrings.Fix;
case Flag.ForceUnitAccess:
return FlagStrings.ForceUnitAccess;
case Flag.MultiSectorRead:
return FlagStrings.MultiSectorRead;
case Flag.MultiSession:
return FlagStrings.MultiSession;
case Flag.NoFixSubP:
@@ -232,6 +234,8 @@ namespace DICUI.DiscImageCreator
return FlagStrings.NoFixSubQSecuROM;
case Flag.NoSkipSS:
return FlagStrings.NoSkipSS;
case Flag.PadSector:
return FlagStrings.PadSector;
case Flag.Raw:
return FlagStrings.Raw;
case Flag.Resume:

View File

@@ -1,4 +1,4 @@
namespace DICUI.DiscImageCreator
namespace MPF.DiscImageCreator
{
/// <summary>
/// Supported DiscImageCreator commands
@@ -49,6 +49,7 @@ namespace DICUI.DiscImageCreator
ExtractMicroSoftCabFile,
Fix,
ForceUnitAccess,
MultiSectorRead,
MultiSession,
NoFixSubP,
NoFixSubQ,
@@ -56,6 +57,7 @@ namespace DICUI.DiscImageCreator
NoFixSubRtoW,
NoFixSubQSecuROM,
NoSkipSS,
PadSector,
Raw,
Resume,
Reverse,

View File

@@ -0,0 +1,160 @@
using System;
using System.Linq;
using System.Security.Cryptography;
using MPF.Data;
using OptimizedCRC;
namespace MPF.Hashing
{
/// <summary>
/// Async hashing class wraper
/// </summary>
public class Hasher
{
public Hash HashType { get; private set; }
private IDisposable _hasher;
public Hasher(Hash hashType)
{
this.HashType = hashType;
GetHasher();
}
/// <summary>
/// Generate the correct hashing class based on the hash type
/// </summary>
private void GetHasher()
{
switch (HashType)
{
case Hash.CRC:
_hasher = new OptimizedCRC.OptimizedCRC();
break;
case Hash.MD5:
_hasher = MD5.Create();
break;
case Hash.SHA1:
_hasher = SHA1.Create();
break;
case Hash.SHA256:
_hasher = SHA256.Create();
break;
case Hash.SHA384:
_hasher = SHA384.Create();
break;
case Hash.SHA512:
_hasher = SHA512.Create();
break;
}
}
public void Dispose()
{
_hasher.Dispose();
}
/// <summary>
/// Process a buffer of some length with the internal hash algorithm
/// </summary>
public void Process(byte[] buffer, int size)
{
switch (HashType)
{
case Hash.CRC:
(_hasher as OptimizedCRC.OptimizedCRC).Update(buffer, 0, size);
break;
case Hash.MD5:
case Hash.SHA1:
case Hash.SHA256:
case Hash.SHA384:
case Hash.SHA512:
(_hasher as HashAlgorithm).TransformBlock(buffer, 0, size, null, 0);
break;
}
}
/// <summary>
/// Finalize the internal hash algorigthm
/// </summary>
public void Terminate()
{
byte[] emptyBuffer = new byte[0];
switch (HashType)
{
case Hash.CRC:
(_hasher as OptimizedCRC.OptimizedCRC).Update(emptyBuffer, 0, 0);
break;
case Hash.MD5:
case Hash.SHA1:
case Hash.SHA256:
case Hash.SHA384:
case Hash.SHA512:
(_hasher as HashAlgorithm).TransformFinalBlock(emptyBuffer, 0, 0);
break;
}
}
/// <summary>
/// Get internal hash as a byte array
/// </summary>
public byte[] GetHash()
{
switch (HashType)
{
case Hash.CRC:
return BitConverter.GetBytes((_hasher as OptimizedCRC.OptimizedCRC).Value).Reverse().ToArray();
case Hash.MD5:
case Hash.SHA1:
case Hash.SHA256:
case Hash.SHA384:
case Hash.SHA512:
return (_hasher as HashAlgorithm).Hash;
}
return null;
}
/// <summary>
/// Get internal hash as a string
/// </summary>
public string GetHashString()
{
byte[] hash = GetHash();
if (hash == null)
return null;
return ByteArrayToString(hash);
}
/// <summary>
/// Convert a byte array to a hex string
/// </summary>
/// <param name="bytes">Byte array to convert</param>
/// <returns>Hex string representing the byte array</returns>
/// <link>http://stackoverflow.com/questions/311165/how-do-you-convert-byte-array-to-hexadecimal-string-and-vice-versa</link>
private static string ByteArrayToString(byte[] bytes)
{
// If we get null in, we send null out
if (bytes == null)
return null;
try
{
string hex = BitConverter.ToString(bytes);
return hex.Replace("-", string.Empty).ToLowerInvariant();
}
catch
{
return null;
}
}
}
}

View File

@@ -0,0 +1,153 @@
/*
Copyright (c) 2012-2015 Eugene Larchenko (spct@mail.ru)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
using System;
namespace OptimizedCRC
{
internal class OptimizedCRC : IDisposable
{
private const uint kCrcPoly = 0xEDB88320;
private const uint kInitial = 0xFFFFFFFF;
private const int CRC_NUM_TABLES = 8;
private static readonly uint[] Table;
static OptimizedCRC()
{
unchecked
{
Table = new uint[256 * CRC_NUM_TABLES];
int i;
for (i = 0; i < 256; i++)
{
uint r = (uint)i;
for (int j = 0; j < 8; j++)
{
r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
}
Table[i] = r;
}
for (; i < 256 * CRC_NUM_TABLES; i++)
{
uint r = Table[i - 256];
Table[i] = Table[r & 0xFF] ^ (r >> 8);
}
}
}
public uint UnsignedValue;
public OptimizedCRC()
{
Init();
}
/// <summary>
/// Reset CRC
/// </summary>
public void Init()
{
UnsignedValue = kInitial;
}
public int Value
{
get { return (int)~UnsignedValue; }
}
public void Update(byte[] data, int offset, int count)
{
new ArraySegment<byte>(data, offset, count); // check arguments
if (count == 0)
{
return;
}
var table = OptimizedCRC.Table;
uint crc = UnsignedValue;
for (; (offset & 7) != 0 && count != 0; count--)
{
crc = (crc >> 8) ^ table[(byte)crc ^ data[offset++]];
}
if (count >= 8)
{
/*
* Idea from 7-zip project sources (http://7-zip.org/sdk.html)
*/
int end = (count - 8) & ~7;
count -= end;
end += offset;
while (offset != end)
{
crc ^= (uint)(data[offset] + (data[offset + 1] << 8) + (data[offset + 2] << 16) + (data[offset + 3] << 24));
uint high = (uint)(data[offset + 4] + (data[offset + 5] << 8) + (data[offset + 6] << 16) + (data[offset + 7] << 24));
offset += 8;
crc = table[(byte)crc + 0x700]
^ table[(byte)(crc >>= 8) + 0x600]
^ table[(byte)(crc >>= 8) + 0x500]
^ table[/*(byte)*/(crc >> 8) + 0x400]
^ table[(byte)(high) + 0x300]
^ table[(byte)(high >>= 8) + 0x200]
^ table[(byte)(high >>= 8) + 0x100]
^ table[/*(byte)*/(high >> 8) + 0x000];
}
}
while (count-- != 0)
{
crc = (crc >> 8) ^ table[(byte)crc ^ data[offset++]];
}
UnsignedValue = crc;
}
static public int Compute(byte[] data, int offset, int count)
{
var crc = new OptimizedCRC();
crc.Update(data, offset, count);
return crc.Value;
}
static public int Compute(byte[] data)
{
return Compute(data, 0, data.Length);
}
static public int Compute(ArraySegment<byte> block)
{
return Compute(block.Array, block.Offset, block.Count);
}
public void Dispose()
{
UnsignedValue = 0;
}
}
}

View File

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

View File

@@ -0,0 +1,93 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;netcoreapp3.1</TargetFrameworks>
<Title>MPF Library</Title>
<AssemblyName>MPF.Library</AssemblyName>
<Description>Library code for MPF and MPF.Check</Description>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2021</Copyright>
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
<Version>2.0</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<FileVersion>$(Version)</FileVersion>
<IncludeSource>true</IncludeSource>
<IncludeSymbols>true</IncludeSymbols>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup>
<NrtRevisionFormat>$(Version)-{chash:8}</NrtRevisionFormat>
<NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes>
<NrtShowRevision>false</NrtShowRevision>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)'!='netcoreapp3.1'">
<DefineConstants>NET_FRAMEWORK</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'!='netcoreapp3.1'">
<COMReference Include="IMAPI2">
<Guid>{2735412F-7F64-5B0F-8F00-5D77AFBE261E}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
<COMReference Include="IMAPI2FS">
<Guid>{2C941FD0-975B-59BE-A960-9A2A262853A5}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup>
<Compile Remove="Aaru\CICMMetadata\CICMMetadataEditor\**" />
<Compile Remove="Aaru\CICMMetadata\java\**" />
<Compile Remove="Aaru\CICMMetadata\samples\**" />
<EmbeddedResource Remove="Aaru\CICMMetadata\CICMMetadataEditor\**" />
<EmbeddedResource Remove="Aaru\CICMMetadata\java\**" />
<EmbeddedResource Remove="Aaru\CICMMetadata\samples\**" />
<None Remove="Aaru\CICMMetadata\CICMMetadataEditor\**" />
<None Remove="Aaru\CICMMetadata\java\**" />
<None Remove="Aaru\CICMMetadata\samples\**" />
</ItemGroup>
<ItemGroup>
<None Remove="Aaru\CICMMetadata\.editorconfig" />
<None Remove="Aaru\CICMMetadata\.git" />
<None Remove="Aaru\CICMMetadata\.gitignore" />
<None Remove="Aaru\CICMMetadata\.project" />
<None Remove="Aaru\CICMMetadata\build.sh" />
<None Remove="Aaru\CICMMetadata\cicm.xml" />
<None Remove="Aaru\CICMMetadata\cicm.xsd" />
<None Remove="Aaru\CICMMetadata\CICMMetadata.iml" />
<None Remove="Aaru\CICMMetadata\dotnet\cicm.vb" />
<None Remove="Aaru\CICMMetadata\README.md" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="1.6.1" GeneratePathProperty="true">
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
<PackageReference Include="System.Management" Version="6.0.0-preview.3.21201.4" />
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.0" />
</ItemGroup>
<ItemGroup>
<Content Include="$(PkgBurnOutSharp)\content\**" PackagePath="contentFiles\any\any;content" CopyToOutputDirectory="Always" PackageCopyToOutput="true" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Management" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,229 @@
using MPF.Data;
namespace MPF.Redump
{
/// <summary>
/// Information pertaining to Redump systems
/// </summary>
public static class Extras
{
#region Special lists
/// <summary>
/// List of systems that are not publically accessible
/// </summary>
public static readonly RedumpSystem?[] BannedSystems = new RedumpSystem?[]
{
RedumpSystem.AudioCD,
RedumpSystem.BDVideo,
RedumpSystem.DVDVideo,
RedumpSystem.HasbroVideoNow,
RedumpSystem.HasbroVideoNowColor,
RedumpSystem.HasbroVideoNowJr,
RedumpSystem.HasbroVideoNowXP,
RedumpSystem.KonamiM2,
RedumpSystem.MicrosoftXbox360,
RedumpSystem.MicrosoftXboxOne,
//RedumpSystem.MicrosoftXboxSeriesXS,
RedumpSystem.NavisoftNaviken21,
RedumpSystem.NintendoWii,
RedumpSystem.NintendoWiiU,
RedumpSystem.PanasonicM2,
RedumpSystem.SegaPrologue21,
RedumpSystem.SegaRingEdge,
RedumpSystem.SegaRingEdge2,
RedumpSystem.SonyPlayStation3,
RedumpSystem.SonyPlayStation4,
//RedumpSystem.SonyPlayStation5,
RedumpSystem.VideoCD,
};
/// <summary>
/// List of systems that have a Cues pack
/// </summary>
public static readonly RedumpSystem?[] HasCues = new RedumpSystem?[]
{
RedumpSystem.AppleMacintosh,
RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem,
RedumpSystem.AudioCD,
RedumpSystem.BandaiPippin,
RedumpSystem.BandaiPlaydiaQuickInteractiveSystem,
RedumpSystem.CommodoreAmigaCD,
RedumpSystem.CommodoreAmigaCD32,
RedumpSystem.CommodoreAmigaCDTV,
RedumpSystem.FujitsuFMTownsseries,
RedumpSystem.funworldPhotoPlay,
RedumpSystem.HasbroVideoNow,
RedumpSystem.HasbroVideoNowColor,
RedumpSystem.HasbroVideoNowJr,
RedumpSystem.HasbroVideoNowXP,
RedumpSystem.IBMPCcompatible,
RedumpSystem.IncredibleTechnologiesEagle,
RedumpSystem.KonamieAmusement,
RedumpSystem.KonamiFireBeat,
RedumpSystem.KonamiM2,
RedumpSystem.KonamiSystemGV,
RedumpSystem.MattelFisherPriceiXL,
RedumpSystem.MattelHyperScan,
RedumpSystem.MemorexVisualInformationSystem,
RedumpSystem.MicrosoftXbox,
RedumpSystem.MicrosoftXbox360,
RedumpSystem.NamcoSegaNintendoTriforce,
RedumpSystem.NamcoSystem246,
RedumpSystem.NavisoftNaviken21,
RedumpSystem.NECPCEngineCDTurboGrafxCD,
RedumpSystem.NECPC88series,
RedumpSystem.NECPC98series,
RedumpSystem.NECPCFXPCFXGA,
RedumpSystem.PalmOS,
RedumpSystem.Panasonic3DOInteractiveMultiplayer,
RedumpSystem.PanasonicM2,
RedumpSystem.PhilipsCDi,
RedumpSystem.PhotoCD,
RedumpSystem.PlayStationGameSharkUpdates,
RedumpSystem.SegaChihiro,
RedumpSystem.SegaDreamcast,
RedumpSystem.SegaMegaCDSegaCD,
RedumpSystem.SegaNaomi,
RedumpSystem.SegaNaomi2,
RedumpSystem.SegaPrologue21,
RedumpSystem.SegaSaturn,
RedumpSystem.SNKNeoGeoCD,
RedumpSystem.SonyPlayStation,
RedumpSystem.SonyPlayStation2,
RedumpSystem.SonyPlayStation3,
RedumpSystem.TABAustriaQuizard,
RedumpSystem.TomyKissSite,
RedumpSystem.VideoCD,
RedumpSystem.VTechVFlashVSmilePro,
};
/// <summary>
/// List of systems that has a Dat pack
/// </summary>
public static readonly RedumpSystem?[] HasDat = new RedumpSystem?[]
{
RedumpSystem.MicrosoftXboxBIOS,
RedumpSystem.NintendoGameCubeBIOS,
RedumpSystem.SonyPlayStationBIOS,
RedumpSystem.SonyPlayStation2BIOS,
RedumpSystem.AppleMacintosh,
RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem,
RedumpSystem.AudioCD,
RedumpSystem.BandaiPippin,
RedumpSystem.BandaiPlaydiaQuickInteractiveSystem,
RedumpSystem.BDVideo,
RedumpSystem.CommodoreAmigaCD,
RedumpSystem.CommodoreAmigaCD32,
RedumpSystem.CommodoreAmigaCDTV,
RedumpSystem.DVDVideo,
RedumpSystem.FujitsuFMTownsseries,
RedumpSystem.funworldPhotoPlay,
RedumpSystem.HasbroVideoNow,
RedumpSystem.HasbroVideoNowColor,
RedumpSystem.HasbroVideoNowJr,
RedumpSystem.HasbroVideoNowXP,
RedumpSystem.IBMPCcompatible,
RedumpSystem.IncredibleTechnologiesEagle,
RedumpSystem.KonamieAmusement,
RedumpSystem.KonamiFireBeat,
RedumpSystem.KonamiM2,
RedumpSystem.KonamiSystemGV,
RedumpSystem.MattelFisherPriceiXL,
RedumpSystem.MattelHyperScan,
RedumpSystem.MemorexVisualInformationSystem,
RedumpSystem.MicrosoftXbox,
RedumpSystem.MicrosoftXbox360,
RedumpSystem.MicrosoftXboxOne,
//RedumpSystem.MicrosoftXboxSeriesXS,
RedumpSystem.NamcoSegaNintendoTriforce,
RedumpSystem.NamcoSystem246,
RedumpSystem.NavisoftNaviken21,
RedumpSystem.NECPCEngineCDTurboGrafxCD,
RedumpSystem.NECPC88series,
RedumpSystem.NECPC98series,
RedumpSystem.NECPCFXPCFXGA,
RedumpSystem.NintendoGameCube,
RedumpSystem.NintendoWii,
RedumpSystem.NintendoWiiU,
RedumpSystem.PalmOS,
RedumpSystem.Panasonic3DOInteractiveMultiplayer,
RedumpSystem.PanasonicM2,
RedumpSystem.PhilipsCDi,
RedumpSystem.PhotoCD,
RedumpSystem.PlayStationGameSharkUpdates,
RedumpSystem.SegaChihiro,
RedumpSystem.SegaDreamcast,
RedumpSystem.SegaLindbergh,
RedumpSystem.SegaMegaCDSegaCD,
RedumpSystem.SegaNaomi,
RedumpSystem.SegaNaomi2,
RedumpSystem.SegaRingEdge,
RedumpSystem.SegaRingEdge2,
RedumpSystem.SegaSaturn,
RedumpSystem.SNKNeoGeoCD,
RedumpSystem.SonyPlayStation,
RedumpSystem.SonyPlayStation2,
RedumpSystem.SonyPlayStation3,
RedumpSystem.SonyPlayStation4,
//RedumpSystem.SonyPlayStation5,
RedumpSystem.SonyPlayStationPortable,
RedumpSystem.TABAustriaQuizard,
RedumpSystem.TomyKissSite,
RedumpSystem.VideoCD,
RedumpSystem.VMLabsNUON,
RedumpSystem.VTechVFlashVSmilePro,
RedumpSystem.ZAPiTGamesGameWaveFamilyEntertainmentSystem,
};
/// <summary>
/// List of systems that has a Decrypted Keys pack
/// </summary>
public static readonly RedumpSystem?[] HasDkeys = new RedumpSystem?[]
{
RedumpSystem.SonyPlayStation3,
};
/// <summary>
/// List of systems that has a GDI pack
/// </summary>
public static readonly RedumpSystem?[] HasGdi = new RedumpSystem?[]
{
RedumpSystem.NamcoSegaNintendoTriforce,
RedumpSystem.SegaChihiro,
RedumpSystem.SegaDreamcast,
RedumpSystem.SegaNaomi,
RedumpSystem.SegaNaomi2,
};
/// <summary>
/// List of systems that has a Keys pack
/// </summary>
public static readonly RedumpSystem?[] HasKeys = new RedumpSystem?[]
{
RedumpSystem.NintendoWiiU,
RedumpSystem.SonyPlayStation3,
};
/// <summary>
/// List of systems that has an LSD pack
/// </summary>
public static readonly RedumpSystem?[] HasLsd = new RedumpSystem?[]
{
RedumpSystem.IBMPCcompatible,
RedumpSystem.SonyPlayStation,
};
/// <summary>
/// List of systems that has an SBI pack
/// </summary>
public static readonly RedumpSystem?[] HasSbi = new RedumpSystem?[]
{
RedumpSystem.IBMPCcompatible,
RedumpSystem.SonyPlayStation,
};
#endregion
}
}

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