mirror of
https://github.com/SabreTools/MPF.git
synced 2026-02-05 05:37:36 +00:00
Compare commits
223 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a2061a36e | ||
|
|
191c7b080e | ||
|
|
aab0813688 | ||
|
|
9ad564772c | ||
|
|
20bb34c3c7 | ||
|
|
b15ddf390b | ||
|
|
18d1562ad3 | ||
|
|
d6f2ecbd25 | ||
|
|
3620686afa | ||
|
|
1524224bc3 | ||
|
|
35200d53d6 | ||
|
|
4b7d4e05e7 | ||
|
|
7e73f69433 | ||
|
|
9e1a972df5 | ||
|
|
1edac34c1a | ||
|
|
9adc588c9c | ||
|
|
71bfdcba8f | ||
|
|
9854c9970a | ||
|
|
0c68164d6d | ||
|
|
a413357b57 | ||
|
|
5e283c9e80 | ||
|
|
500eb66e30 | ||
|
|
411e5245a5 | ||
|
|
d270501c2d | ||
|
|
f7f924593f | ||
|
|
5126a66eb9 | ||
|
|
7fddef238d | ||
|
|
ace673f90d | ||
|
|
e063df63df | ||
|
|
22b15710d0 | ||
|
|
87199c1b0d | ||
|
|
7e5952bbb8 | ||
|
|
1a52a3a205 | ||
|
|
742db4c854 | ||
|
|
4fd51dbe45 | ||
|
|
096a8a6a06 | ||
|
|
ad5cd5b8f9 | ||
|
|
3230d59f6a | ||
|
|
96fa8d8cef | ||
|
|
01bf3c9efb | ||
|
|
da0bf64e94 | ||
|
|
d39cf5d13f | ||
|
|
7c7e78fd4e | ||
|
|
d2c504898a | ||
|
|
58028b4f18 | ||
|
|
54e835687b | ||
|
|
10f2318541 | ||
|
|
eb4e95e5db | ||
|
|
203418eebc | ||
|
|
136c6c8fbf | ||
|
|
2c216d6a58 | ||
|
|
f7ec19cc5d | ||
|
|
e8c4a97158 | ||
|
|
5e5fc4c812 | ||
|
|
5e0d99ff5d | ||
|
|
e88e67c927 | ||
|
|
d963dbbd5f | ||
|
|
11ce78fca2 | ||
|
|
fd4022ba84 | ||
|
|
f91aecad8e | ||
|
|
709b7d357f | ||
|
|
59980fa160 | ||
|
|
180caf83cc | ||
|
|
7047ee832a | ||
|
|
4b5532e1b0 | ||
|
|
137155d3dc | ||
|
|
793dd8289a | ||
|
|
bcf298e40b | ||
|
|
589aef1e21 | ||
|
|
9ab0b7ab3b | ||
|
|
4c5ea13aac | ||
|
|
0cf48bbdaa | ||
|
|
8fc9cc18a3 | ||
|
|
b1e156eed6 | ||
|
|
a8b3a837ef | ||
|
|
3f3a1c9a44 | ||
|
|
cf4d2f5055 | ||
|
|
2d19d51bc7 | ||
|
|
4842bdd38b | ||
|
|
7cc4f6d6a7 | ||
|
|
b284ffd99d | ||
|
|
81d0cc2cc2 | ||
|
|
70f368d6e9 | ||
|
|
bfbae5cf5c | ||
|
|
7cc231f5fd | ||
|
|
eda34b3477 | ||
|
|
bfb67ec0c9 | ||
|
|
275fd0da48 | ||
|
|
1ad5c25ed0 | ||
|
|
512f7ae016 | ||
|
|
3a00efc7fd | ||
|
|
3068c74ad7 | ||
|
|
9bdead5616 | ||
|
|
0ed5feb96b | ||
|
|
ec80ef2ede | ||
|
|
617591cc26 | ||
|
|
c855aa5cef | ||
|
|
e2a27479f5 | ||
|
|
c8cfe76aa3 | ||
|
|
ecb0234258 | ||
|
|
24ce4bcc51 | ||
|
|
162af3de31 | ||
|
|
7c0af96dc9 | ||
|
|
026f999b46 | ||
|
|
bbbc3e98a0 | ||
|
|
f78ad4e7b6 | ||
|
|
d756ae2163 | ||
|
|
701738ce25 | ||
|
|
620bdc9132 | ||
|
|
71f474c26c | ||
|
|
c48137a5c1 | ||
|
|
e248368484 | ||
|
|
7225b8c32d | ||
|
|
20e475e130 | ||
|
|
88dc005592 | ||
|
|
40792ff0eb | ||
|
|
6ae59e91de | ||
|
|
5c7aa5f7f5 | ||
|
|
aaa1ed674f | ||
|
|
42def3bbe5 | ||
|
|
9cdab52556 | ||
|
|
5c104ebf3d | ||
|
|
7ab72e542c | ||
|
|
3a8420cd2f | ||
|
|
916aa9fd70 | ||
|
|
8809df10b6 | ||
|
|
34d65a9d70 | ||
|
|
2830d7c8a2 | ||
|
|
c702c8b0ac | ||
|
|
e1df9a9754 | ||
|
|
03fe5ce8a5 | ||
|
|
432a9dda16 | ||
|
|
1dfc0f731e | ||
|
|
af515e0adf | ||
|
|
2222b57143 | ||
|
|
d8cfa2e6a4 | ||
|
|
a622cdd4e0 | ||
|
|
2a4ec83d0d | ||
|
|
b1d144d091 | ||
|
|
23a8b66c16 | ||
|
|
381ebd5961 | ||
|
|
b4d1f7d6c3 | ||
|
|
b3eff64275 | ||
|
|
f15c00acca | ||
|
|
a66d0d4722 | ||
|
|
66cdade01b | ||
|
|
9e9f001768 | ||
|
|
3514bdcbc4 | ||
|
|
312df37365 | ||
|
|
6214d91940 | ||
|
|
23d500434b | ||
|
|
7ee5e3ab43 | ||
|
|
6be4bb7c85 | ||
|
|
d620c13e22 | ||
|
|
73b585cdd2 | ||
|
|
2f33581e4a | ||
|
|
f3dba9a026 | ||
|
|
d7d0af369c | ||
|
|
2ab9a45a71 | ||
|
|
dc0bf642a9 | ||
|
|
9e32435972 | ||
|
|
c2b724e949 | ||
|
|
195d3c6ff7 | ||
|
|
04a8079cee | ||
|
|
0b2daf7d30 | ||
|
|
1353ee603b | ||
|
|
e9d272d139 | ||
|
|
0308c7a81e | ||
|
|
4caad10c9b | ||
|
|
85c1623d33 | ||
|
|
5be1825bb5 | ||
|
|
ec5e533bd8 | ||
|
|
c3e4c7fa78 | ||
|
|
bf66a3fcbd | ||
|
|
101193cb78 | ||
|
|
b610c29be6 | ||
|
|
999c4dceb5 | ||
|
|
2957370fac | ||
|
|
5dd36d7b06 | ||
|
|
47b5bbe7e7 | ||
|
|
5a2e4ca77e | ||
|
|
c479ddb80b | ||
|
|
da1f59e0c1 | ||
|
|
9574832e86 | ||
|
|
3df7842d23 | ||
|
|
62a0f6e49a | ||
|
|
60c180e4dd | ||
|
|
343d937362 | ||
|
|
f20b321433 | ||
|
|
ba19b0825f | ||
|
|
5abb44957c | ||
|
|
b9d9cf812f | ||
|
|
d1529f428a | ||
|
|
5061a79c4c | ||
|
|
eab3e25cf2 | ||
|
|
33e73a8992 | ||
|
|
a63972b549 | ||
|
|
bc57df7fc1 | ||
|
|
e16f616286 | ||
|
|
c5497d787b | ||
|
|
64f60004c4 | ||
|
|
020c063177 | ||
|
|
a3e6f8157f | ||
|
|
f27040cd1c | ||
|
|
3a490cfc8d | ||
|
|
1f8c5998c1 | ||
|
|
f96d4ee37e | ||
|
|
d0d15f03af | ||
|
|
eff6407206 | ||
|
|
c1e559568a | ||
|
|
ef030b290c | ||
|
|
71630591a1 | ||
|
|
31505745be | ||
|
|
e40444b60c | ||
|
|
44edf387a6 | ||
|
|
d3d225644d | ||
|
|
3afd9200a9 | ||
|
|
c5c340ff12 | ||
|
|
b28b85f7c6 | ||
|
|
c60684b83c | ||
|
|
a183a1ec91 | ||
|
|
abd8488185 | ||
|
|
e6dea158e5 |
7
.github/ISSUE_TEMPLATE/feature-request.md
vendored
7
.github/ISSUE_TEMPLATE/feature-request.md
vendored
@@ -8,9 +8,10 @@ assignees: mnadareski
|
||||
---
|
||||
|
||||
**Before You Submit**
|
||||
- Remember to try the [latest WIP build](https://ci.appveyor.com/project/mnadareski/dicui/build/artifacts) to see if the feature already exists.
|
||||
- .NET Core 3.1 has known limitations, so make sure that what you're asking for isn't already in another build.
|
||||
- Check [previous issues](https://github.com/SabreTools/DICUI/issues) to see if any of those are related to what you're about to ask for.
|
||||
- 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...
|
||||
|
||||
|
||||
22
.github/ISSUE_TEMPLATE/informational.md
vendored
Normal file
22
.github/ISSUE_TEMPLATE/informational.md
vendored
Normal 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.
|
||||
5
.github/ISSUE_TEMPLATE/issue-report.md
vendored
5
.github/ISSUE_TEMPLATE/issue-report.md
vendored
@@ -8,8 +8,9 @@ assignees: mnadareski
|
||||
---
|
||||
|
||||
**Before You Submit**
|
||||
- Remember to try the [latest WIP build](https://ci.appveyor.com/project/mnadareski/dicui/build/artifacts) to see if the issue has already been addressed.
|
||||
- .NET Core 3.1 has known issues, please try using another build to reproduce the error
|
||||
- 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.
|
||||
|
||||
|
||||
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
||||
[submodule "DICUI.Library/Aaru/CICMMetadata"]
|
||||
path = DICUI.Library/Aaru/CICMMetadata
|
||||
[submodule "MPF.Library/Aaru/CICMMetadata"]
|
||||
path = MPF.Library/Aaru/CICMMetadata
|
||||
url = https://github.com/claunia/CICMMetadata
|
||||
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@@ -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
6
.vscode/tasks.json
vendored
@@ -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"
|
||||
],
|
||||
|
||||
@@ -1,3 +1,57 @@
|
||||
### 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)
|
||||
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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?; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
|
||||
namespace DICUI.Avalonia
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single item in the Internal Program combo box
|
||||
/// </summary>
|
||||
public class InternalProgramComboBoxItem
|
||||
{
|
||||
private object data;
|
||||
|
||||
public InternalProgramComboBoxItem(InternalProgram? internalProgram) => data = internalProgram;
|
||||
|
||||
public static implicit operator InternalProgram? (InternalProgramComboBoxItem item) => item.data as InternalProgram?;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return (data as InternalProgram?).LongName();
|
||||
}
|
||||
}
|
||||
|
||||
public InternalProgram? Value
|
||||
{
|
||||
get { return data as InternalProgram?; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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?; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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?; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -1,57 +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.18</Version>
|
||||
<AssemblyVersion>1.18</AssemblyVersion>
|
||||
<FileVersion>1.18</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" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="1.5.0" GeneratePathProperty="true">
|
||||
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.7.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="$(PkgBurnOutSharp)\content\**" PackagePath="contentFiles\any\any;content" CopyToOutputDirectory="Always" PackageCopyToOutput="true" />
|
||||
</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>
|
||||
@@ -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>
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -1,837 +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 possible
|
||||
if (UIOptions.Options.SkipMediaTypeDetection)
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLog("Media type detection disabled, defaulting to CD-ROM");
|
||||
CurrentMediaType = MediaType.CDROM;
|
||||
}
|
||||
else
|
||||
{
|
||||
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, defaulting to CD-ROM." : ($"detected {CurrentMediaType.LongName()}."));
|
||||
if (CurrentMediaType == null)
|
||||
CurrentMediaType = MediaType.CDROM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <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()
|
||||
{
|
||||
// Determine current environment, just in case
|
||||
if (Env == null)
|
||||
Env = DetermineEnvironment();
|
||||
|
||||
// Pull the drive letter from the UI directly, just in case
|
||||
var drive = this.Find<ComboBox>("DriveLetterComboBox").SelectedItem as Drive;
|
||||
if (drive.Letter != default(char))
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Scanning for copy protection in {0}", 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(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}", 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;
|
||||
optionsWindow.Refresh();
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,165 +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="2" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="dd Path" />
|
||||
<TextBox Name="DDPathTextBox" Grid.Row="2" 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="2" Grid.Column="2" Height="25" Width="25" Content="..." Click="BrowseForPathClick" />
|
||||
-->
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="5" Text="Region" />
|
||||
<ComboBox Name="InternalProgramComboBox" Grid.Row="2" 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="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>
|
||||
@@ -1,183 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
using DICUI.Web;
|
||||
|
||||
namespace DICUI.Avalonia
|
||||
{
|
||||
public class OptionsWindow : Window
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Current UI options
|
||||
/// </summary>
|
||||
public UIOptions UIOptions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of available internal programs
|
||||
/// </summary>
|
||||
public List<InternalProgramComboBoxItem> InternalPrograms { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
public OptionsWindow()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
#if DEBUG
|
||||
this.AttachDevTools();
|
||||
#endif
|
||||
|
||||
PopulateInternalPrograms();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Get a complete list of internal programs and fill the combo box
|
||||
/// </summary>
|
||||
private void PopulateInternalPrograms()
|
||||
{
|
||||
// We only support certain programs for dumping
|
||||
var internalPrograms = new List<InternalProgram> { InternalProgram.DiscImageCreator, InternalProgram.Aaru, InternalProgram.DD };
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Populating internal programs, {0} internal programs found.", internalPrograms.Count);
|
||||
|
||||
InternalPrograms = new List<InternalProgramComboBoxItem>();
|
||||
foreach (var internalProgram in internalPrograms)
|
||||
{
|
||||
InternalPrograms.Add(new InternalProgramComboBoxItem(internalProgram));
|
||||
}
|
||||
|
||||
this.Find<ComboBox>("InternalProgramComboBox").Items = InternalPrograms;
|
||||
this.Find<ComboBox>("InternalProgramComboBox").SelectedIndex = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refresh any options-related elements
|
||||
/// </summary>
|
||||
public void Refresh()
|
||||
{
|
||||
// Handle non-bindable fields
|
||||
this.Find<ComboBox>("InternalProgramComboBox").SelectedIndex = InternalPrograms.FindIndex(r => r == Converters.ToInternalProgram(UIOptions.Options.InternalProgram));
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
// Handle non-bindable fields
|
||||
UIOptions.Options.InternalProgram = (this.Find<ComboBox>("InternalProgramComboBox").SelectedItem as InternalProgramComboBoxItem)?.Name ?? InternalProgram.DiscImageCreator.ToString();
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,227 +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; }
|
||||
}
|
||||
|
||||
#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();
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -1,284 +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; }
|
||||
}
|
||||
|
||||
#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", true); }
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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?; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
|
||||
namespace DICUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single item in the Internal Program combo box
|
||||
/// </summary>
|
||||
public class InternalProgramComboBoxItem
|
||||
{
|
||||
private object data;
|
||||
|
||||
public InternalProgramComboBoxItem(InternalProgram? internalProgram) => data = internalProgram;
|
||||
|
||||
public static implicit operator InternalProgram? (InternalProgramComboBoxItem item) => item.data as InternalProgram?;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return (data as InternalProgram?).LongName();
|
||||
}
|
||||
}
|
||||
|
||||
public InternalProgram? Value
|
||||
{
|
||||
get { return data as InternalProgram?; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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?; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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?; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
DICUI/Icon.ico
BIN
DICUI/Icon.ico
Binary file not shown.
|
Before Width: | Height: | Size: 71 KiB |
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,225 +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; }
|
||||
}
|
||||
|
||||
#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();
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -1,401 +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 FlowDocument _document;
|
||||
private 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();
|
||||
_paragraph = new Paragraph();
|
||||
_document.Blocks.Add(_paragraph);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -1,224 +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="2" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="DD Path" />
|
||||
<TextBox x:Name="DDPathTextBox" Grid.Row="2" 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="2" Grid.Column="2" Height="22" Width="22" Content="..." Click="BrowseForPathClick" />
|
||||
-->
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Dumping Program" />
|
||||
<ComboBox x:Name="InternalProgramComboBox" Grid.Row="2" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" >
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Path=Name}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<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>
|
||||
2
LICENSE
2
LICENSE
@@ -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.
|
||||
|
||||
@@ -1,30 +1,37 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net48;netcoreapp3.1</TargetFrameworks>
|
||||
<TargetFrameworks>net48;netcoreapp3.1</TargetFrameworks>
|
||||
<OutputType>Exe</OutputType>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<Title>DICUI Check</Title>
|
||||
<AssemblyName>DICUI.Check</AssemblyName>
|
||||
<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-2020</Copyright>
|
||||
<RepositoryUrl>https://github.com/SabreTools/DICUI</RepositoryUrl>
|
||||
<Version>1.18</Version>
|
||||
<AssemblyVersion>1.18</AssemblyVersion>
|
||||
<FileVersion>1.18</FileVersion>
|
||||
<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.5.0" GeneratePathProperty="true">
|
||||
<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>
|
||||
@@ -32,9 +39,9 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DICUI.Library\DICUI.Library.csproj">
|
||||
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj">
|
||||
<Project>{51ab0928-13f9-44bf-a407-b6957a43a056}</Project>
|
||||
<Name>DICUI.Library</Name>
|
||||
<Name>MPF.Library</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
@@ -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}");
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"profiles": {
|
||||
"DICUI.Check": {
|
||||
"MPF.Check": {
|
||||
"commandName": "Project"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace DICUI.Aaru
|
||||
namespace MPF.Aaru
|
||||
{
|
||||
/// <summary>
|
||||
/// Top-level commands for Aaru
|
||||
@@ -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
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace DICUI.Aaru
|
||||
namespace MPF.Aaru
|
||||
{
|
||||
/// <summary>
|
||||
/// Supported Aaru commands
|
||||
@@ -7,24 +7,47 @@ using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
using System.Xml.Serialization;
|
||||
using DICUI.CueSheets;
|
||||
using DICUI.Data;
|
||||
using DICUI.Utilities;
|
||||
using DICUI.Web;
|
||||
using MPF.CueSheets;
|
||||
using MPF.Data;
|
||||
using MPF.Utilities;
|
||||
using Schemas;
|
||||
|
||||
namespace DICUI.Aaru
|
||||
namespace MPF.Aaru
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic set of Aaru parameters
|
||||
/// </summary>
|
||||
public class Parameters : BaseParameters
|
||||
{
|
||||
#region Generic Dumping Information
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string InputPath => InputValue;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string OutputPath => OutputValue;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int? Speed
|
||||
{
|
||||
get { return SpeedValue; }
|
||||
set { SpeedValue = (sbyte?)value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Metadata
|
||||
|
||||
/// <summary>
|
||||
/// Base command to run
|
||||
/// </summary>
|
||||
public Command BaseCommand { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override InternalProgram InternalProgram => InternalProgram.Aaru;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Set of flags to pass to the executable
|
||||
/// </summary>
|
||||
@@ -125,175 +148,242 @@ namespace DICUI.Aaru
|
||||
|
||||
#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.Aaru;
|
||||
}
|
||||
/// <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>
|
||||
/// Reset all special variables to have default values
|
||||
/// </summary>
|
||||
protected override void ResetValues()
|
||||
#region BaseParameters Implementations
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override (bool, List<string>) CheckAllOutputFilesExist(string basePath)
|
||||
{
|
||||
BaseCommand = Command.NONE;
|
||||
|
||||
_flags = new Dictionary<Flag, bool?>();
|
||||
|
||||
BlockSizeValue = null;
|
||||
CommentsValue = null;
|
||||
CreatorValue = null;
|
||||
CountValue = null;
|
||||
DriveManufacturerValue = null;
|
||||
DriveModelValue = null;
|
||||
DriveRevisionValue = null;
|
||||
DriveSerialValue = null;
|
||||
EncodingValue = null;
|
||||
FormatConvertValue = null;
|
||||
FormatDumpValue = null;
|
||||
ImgBurnLogValue = null;
|
||||
InputValue = null;
|
||||
Input1Value = null;
|
||||
Input2Value = null;
|
||||
LengthValue = null;
|
||||
MediaBarcodeValue = null;
|
||||
MediaLastSequenceValue = null;
|
||||
MediaManufacturerValue = null;
|
||||
MediaModelValue = null;
|
||||
MediaPartNumberValue = null;
|
||||
MediaSequenceValue = null;
|
||||
MediaSerialValue = null;
|
||||
MediaTitleValue = null;
|
||||
MHDDLogValue = null;
|
||||
NamespaceValue = null;
|
||||
OptionsValue = null;
|
||||
OutputValue = null;
|
||||
OutputPrefixValue = null;
|
||||
RemoteHostValue = null;
|
||||
ResumeFileValue = null;
|
||||
RetryPassesValue = null;
|
||||
SkipValue = null;
|
||||
SpeedValue = null;
|
||||
StartValue = null;
|
||||
SubchannelValue = null;
|
||||
WidthValue = null;
|
||||
XMLSidecarValue = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set default parameters for a given system and media type
|
||||
/// </summary>
|
||||
/// <param name="system">KnownSystem value to use</param>
|
||||
/// <param name="type">MediaType value to use</param>
|
||||
/// <param name="driveLetter">Drive letter to use</param>
|
||||
/// <param name="filename">Filename to use</param>
|
||||
/// <param name="driveSpeed">Drive speed to use</param>
|
||||
/// <param name="paranoid">Enable paranoid mode (safer dumping)</param>
|
||||
/// <param name="retryCount">User-defined reread count</param>
|
||||
protected override void SetDefaultParameters(
|
||||
KnownSystem? system,
|
||||
MediaType? type,
|
||||
char driveLetter,
|
||||
string filename,
|
||||
int? driveSpeed,
|
||||
bool paranoid,
|
||||
int retryCount)
|
||||
{
|
||||
BaseCommand = Command.MediaDump;
|
||||
|
||||
InputValue = $"\\\\?\\{driveLetter}:";
|
||||
OutputValue = filename;
|
||||
|
||||
this[Flag.Force] = true;
|
||||
|
||||
if (driveSpeed != null)
|
||||
{
|
||||
this[Flag.Speed] = true;
|
||||
SpeedValue = (sbyte?)driveSpeed;
|
||||
}
|
||||
|
||||
// First check to see if the combination of system and MediaType is valid
|
||||
var validTypes = Validators.GetValidMediaTypes(system);
|
||||
if (!validTypes.Contains(type))
|
||||
return;
|
||||
|
||||
// Set retry count
|
||||
if (retryCount > 0)
|
||||
{
|
||||
this[Flag.RetryPasses] = true;
|
||||
RetryPassesValue = (short)retryCount;
|
||||
}
|
||||
|
||||
// Paranoia in Aaru means more output
|
||||
if (paranoid)
|
||||
{
|
||||
this[Flag.Debug] = true;
|
||||
this[Flag.Verbose] = true;
|
||||
this[Flag.Private] = true; // This removes identifiable information
|
||||
}
|
||||
|
||||
// TODO: Look at dump-media formats and the like and see what options there are there to fill in defaults
|
||||
// Now sort based on disc type
|
||||
switch (type)
|
||||
List<string> missingFiles = new List<string>();
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
this[Flag.FirstPregap] = true;
|
||||
this[Flag.FixOffset] = true;
|
||||
this[Flag.Subchannel] = true;
|
||||
SubchannelValue = "any";
|
||||
if (!File.Exists($"{basePath}.cicm.xml"))
|
||||
missingFiles.Add($"{basePath}.cicm.xml");
|
||||
if (!File.Exists($"{basePath}.ibg"))
|
||||
missingFiles.Add($"{basePath}.ibg");
|
||||
if (!File.Exists($"{basePath}.log"))
|
||||
missingFiles.Add($"{basePath}.log");
|
||||
if (!File.Exists($"{basePath}.mhddlog.bin"))
|
||||
missingFiles.Add($"{basePath}.mhddlog.bin");
|
||||
if (!File.Exists($"{basePath}.resume.xml"))
|
||||
missingFiles.Add($"{basePath}.resume.xml");
|
||||
if (!File.Exists($"{basePath}.sub.log"))
|
||||
missingFiles.Add($"{basePath}.sub.log");
|
||||
|
||||
break;
|
||||
|
||||
case MediaType.DVD:
|
||||
// Currently no defaults set
|
||||
break;
|
||||
case MediaType.GDROM:
|
||||
// Currently no defaults set
|
||||
break;
|
||||
case MediaType.HDDVD:
|
||||
// Currently no defaults set
|
||||
break;
|
||||
case MediaType.BluRay:
|
||||
// Currently no defaults set
|
||||
if (!File.Exists($"{basePath}.cicm.xml"))
|
||||
missingFiles.Add($"{basePath}.cicm.xml");
|
||||
if (!File.Exists($"{basePath}.ibg"))
|
||||
missingFiles.Add($"{basePath}.ibg");
|
||||
if (!File.Exists($"{basePath}.log"))
|
||||
missingFiles.Add($"{basePath}.log");
|
||||
if (!File.Exists($"{basePath}.mhddlog.bin"))
|
||||
missingFiles.Add($"{basePath}.mhddlog.bin");
|
||||
if (!File.Exists($"{basePath}.resume.xml"))
|
||||
missingFiles.Add($"{basePath}.resume.xml");
|
||||
|
||||
break;
|
||||
|
||||
// Special Formats
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
// Currently no defaults set
|
||||
break;
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
// Currently no defaults set
|
||||
default:
|
||||
return (false, missingFiles); // TODO: Figure out more formats
|
||||
}
|
||||
|
||||
return (!missingFiles.Any(), missingFiles);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive, bool includeArtifacts)
|
||||
{
|
||||
// TODO: Fill in submission info specifics for Aaru
|
||||
string outputDirectory = Path.GetDirectoryName(basePath);
|
||||
|
||||
// Deserialize the sidecar, if possible
|
||||
var sidecar = GenerateSidecar(basePath + ".cicm.xml");
|
||||
|
||||
// Fill in the hash data
|
||||
info.TracksAndWriteOffsets.ClrMameProData = GenerateDatfile(sidecar, basePath);
|
||||
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
// TODO: Can this do GD-ROM?
|
||||
info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD";
|
||||
|
||||
long errorCount = -1;
|
||||
if (File.Exists(basePath + ".resume.xml"))
|
||||
errorCount = GetErrorCount(basePath + ".resume.xml");
|
||||
|
||||
info.CommonDiscInfo.ErrorsCount = (errorCount == -1 ? "Error retrieving error count" : errorCount.ToString());
|
||||
|
||||
info.TracksAndWriteOffsets.Cuesheet = GenerateCuesheet(sidecar, basePath) ?? "";
|
||||
|
||||
string cdWriteOffset = GetWriteOffset(sidecar) ?? "";
|
||||
info.CommonDiscInfo.RingWriteOffset = cdWriteOffset;
|
||||
info.TracksAndWriteOffsets.OtherWriteOffsets = cdWriteOffset;
|
||||
break;
|
||||
|
||||
// Non-optical
|
||||
case MediaType.FloppyDisk:
|
||||
// Currently no defaults set
|
||||
case MediaType.DVD:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.BluRay:
|
||||
// Get the individual hash data, as per internal
|
||||
if (GetISOHashValues(info.TracksAndWriteOffsets.ClrMameProData, out long size, out string crc32, out string md5, out string sha1))
|
||||
{
|
||||
info.SizeAndChecksums.Size = size;
|
||||
info.SizeAndChecksums.CRC32 = crc32;
|
||||
info.SizeAndChecksums.MD5 = md5;
|
||||
info.SizeAndChecksums.SHA1 = sha1;
|
||||
}
|
||||
|
||||
// Deal with the layerbreak
|
||||
string layerbreak = null;
|
||||
if (this.Type == MediaType.DVD)
|
||||
layerbreak = GetLayerbreak(sidecar) ?? "";
|
||||
else if (this.Type == MediaType.BluRay)
|
||||
layerbreak = info.SizeAndChecksums.Size > 25_025_314_816 ? "25025314816" : null;
|
||||
|
||||
// If we have a single-layer disc
|
||||
if (string.IsNullOrWhiteSpace(layerbreak))
|
||||
{
|
||||
info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD";
|
||||
}
|
||||
// If we have a dual-layer disc
|
||||
else
|
||||
{
|
||||
info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD";
|
||||
info.SizeAndChecksums.Layerbreak = Int64.Parse(layerbreak);
|
||||
}
|
||||
|
||||
// TODO: Investigate XGD disc outputs
|
||||
// TODO: Investigate BD specifics like PIC
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
switch (this.System)
|
||||
{
|
||||
// TODO: Can we get SecuROM data?
|
||||
// TODO: Can we get SS version/ranges?
|
||||
// TODO: Can we get DMI info?
|
||||
// TODO: Can we get Sega Header info?
|
||||
// TODO: Can we get PS1 EDC status?
|
||||
// TODO: Can we get PS1 LibCrypt status?
|
||||
|
||||
case KnownSystem.DVDAudio:
|
||||
case KnownSystem.DVDVideo:
|
||||
info.CopyProtection.Protection = GetDVDProtection(sidecar) ?? "";
|
||||
break;
|
||||
|
||||
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.MicrosoftXBOX:
|
||||
if (GetXgdAuxInfo(sidecar, out string dmihash, out string pfihash, out string sshash, out string ss, out string ssver))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"{Template.XBOXDMIHash}: {dmihash ?? ""}\n" +
|
||||
$"{Template.XBOXPFIHash}: {pfihash ?? ""}\n" +
|
||||
$"{Template.XBOXSSHash}: {sshash ?? ""}\n" +
|
||||
$"{Template.XBOXSSVersion}: {ssver ?? ""}\n";
|
||||
info.Extras.SecuritySectorRanges = ss ?? "";
|
||||
}
|
||||
|
||||
if (GetXboxDMIInfo(sidecar, out string serial, out string version, out RedumpRegion? region))
|
||||
{
|
||||
info.CommonDiscInfo.Serial = serial ?? "";
|
||||
info.VersionAndEditions.Version = version ?? "";
|
||||
info.CommonDiscInfo.Region = region;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case KnownSystem.MicrosoftXBOX360:
|
||||
if (GetXgdAuxInfo(sidecar, out string dmi360hash, out string pfi360hash, out string ss360hash, out string ss360, out string ssver360))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"{Template.XBOXDMIHash}: {dmi360hash ?? ""}\n" +
|
||||
$"{Template.XBOXPFIHash}: {pfi360hash ?? ""}\n" +
|
||||
$"{Template.XBOXSSHash}: {ss360hash ?? ""}\n" +
|
||||
$"{Template.XBOXSSVersion}: {ssver360 ?? ""}\n";
|
||||
info.Extras.SecuritySectorRanges = ss360 ?? "";
|
||||
}
|
||||
|
||||
if (GetXbox360DMIInfo(sidecar, out string serial360, out string version360, out RedumpRegion? region360))
|
||||
{
|
||||
info.CommonDiscInfo.Serial = serial360 ?? "";
|
||||
info.VersionAndEditions.Version = version360 ?? "";
|
||||
info.CommonDiscInfo.Region = region360;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// Fill in any artifacts that exist, Base64-encoded, if we need to
|
||||
if (includeArtifacts)
|
||||
{
|
||||
if (File.Exists(basePath + ".cicm.xml"))
|
||||
info.Artifacts["cicm"] = GetBase64(GetFullFile(basePath + ".cicm.xml"));
|
||||
if (File.Exists(basePath + ".ibg"))
|
||||
info.Artifacts["ibg"] = Convert.ToBase64String(File.ReadAllBytes(basePath + ".ibg"));
|
||||
if (File.Exists(basePath + ".log"))
|
||||
info.Artifacts["log"] = GetBase64(GetFullFile(basePath + ".log"));
|
||||
if (File.Exists(basePath + ".mhddlog.bin"))
|
||||
info.Artifacts["mhddlog_bin"] = Convert.ToBase64String(File.ReadAllBytes(basePath + ".mhddlog.bin"));
|
||||
if (File.Exists(basePath + ".resume.xml"))
|
||||
info.Artifacts["resume"] = GetBase64(GetFullFile(basePath + ".resume.xml"));
|
||||
if (File.Exists(basePath + ".sub.log"))
|
||||
info.Artifacts["sub_log"] = GetBase64(GetFullFile(basePath + ".sub.log"));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Blindly generate a parameter string based on the inputs
|
||||
/// </summary>
|
||||
/// <returns>Correctly formatted parameter string, null on error</returns>
|
||||
/// <inheritdoc/>
|
||||
public override string GenerateParameters()
|
||||
{
|
||||
List<string> parameters = new List<string>();
|
||||
@@ -940,40 +1030,52 @@ namespace DICUI.Aaru
|
||||
return string.Join(" ", parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the input path from the implementation
|
||||
/// </summary>
|
||||
/// <returns>String representing the path, null on error</returns>
|
||||
public override string InputPath() => InputValue;
|
||||
/// <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() => OutputValue;
|
||||
/// <inheritdoc/>
|
||||
public override List<string> GetLogFilePaths(string basePath)
|
||||
{
|
||||
List<string> logFiles = new List<string>();
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
if (File.Exists($"{basePath}.cicm.xml"))
|
||||
logFiles.Add($"{basePath}.cicm.xml");
|
||||
if (File.Exists($"{basePath}.ibg"))
|
||||
logFiles.Add($"{basePath}.ibg");
|
||||
if (File.Exists($"{basePath}.log"))
|
||||
logFiles.Add($"{basePath}.log");
|
||||
if (File.Exists($"{basePath}.mhddlog.bin"))
|
||||
logFiles.Add($"{basePath}.mhddlog.bin");
|
||||
if (File.Exists($"{basePath}.resume.xml"))
|
||||
logFiles.Add($"{basePath}.resume.xml");
|
||||
if (File.Exists($"{basePath}.sub.log"))
|
||||
logFiles.Add($"{basePath}.sub.log");
|
||||
|
||||
/// <summary>
|
||||
/// Get the processing speed from the implementation
|
||||
/// </summary>
|
||||
/// <returns>int? representing the speed, null on error</returns>
|
||||
public override int? GetSpeed() => SpeedValue;
|
||||
break;
|
||||
|
||||
/// <summary>
|
||||
/// Set the processing speed int the implementation
|
||||
/// </summary>
|
||||
/// <param name="speed">int? representing the speed</param>
|
||||
public override void SetSpeed(int? speed) => SpeedValue = (sbyte?)speed;
|
||||
case MediaType.DVD:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.BluRay:
|
||||
if (File.Exists($"{basePath}.cicm.xml"))
|
||||
logFiles.Add($"{basePath}.cicm.xml");
|
||||
if (File.Exists($"{basePath}.ibg"))
|
||||
logFiles.Add($"{basePath}.ibg");
|
||||
if (File.Exists($"{basePath}.log"))
|
||||
logFiles.Add($"{basePath}.log");
|
||||
if (File.Exists($"{basePath}.mhddlog.bin"))
|
||||
logFiles.Add($"{basePath}.mhddlog.bin");
|
||||
if (File.Exists($"{basePath}.resume.xml"))
|
||||
logFiles.Add($"{basePath}.resume.xml");
|
||||
|
||||
/// <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;
|
||||
break;
|
||||
}
|
||||
|
||||
/// <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>
|
||||
return logFiles;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool IsDumpingCommand()
|
||||
{
|
||||
switch (BaseCommand)
|
||||
@@ -986,11 +1088,124 @@ namespace DICUI.Aaru
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scan a possible parameter string and populate whatever possible
|
||||
/// </summary>
|
||||
/// <param name="parameters">String possibly representing parameters</param>
|
||||
/// <returns></returns>
|
||||
/// <inheritdoc/>
|
||||
protected override void ResetValues()
|
||||
{
|
||||
BaseCommand = Command.NONE;
|
||||
|
||||
_flags = new Dictionary<Flag, bool?>();
|
||||
|
||||
BlockSizeValue = null;
|
||||
CommentsValue = null;
|
||||
CreatorValue = null;
|
||||
CountValue = null;
|
||||
DriveManufacturerValue = null;
|
||||
DriveModelValue = null;
|
||||
DriveRevisionValue = null;
|
||||
DriveSerialValue = null;
|
||||
EncodingValue = null;
|
||||
FormatConvertValue = null;
|
||||
FormatDumpValue = null;
|
||||
ImgBurnLogValue = null;
|
||||
InputValue = null;
|
||||
Input1Value = null;
|
||||
Input2Value = null;
|
||||
LengthValue = null;
|
||||
MediaBarcodeValue = null;
|
||||
MediaLastSequenceValue = null;
|
||||
MediaManufacturerValue = null;
|
||||
MediaModelValue = null;
|
||||
MediaPartNumberValue = null;
|
||||
MediaSequenceValue = null;
|
||||
MediaSerialValue = null;
|
||||
MediaTitleValue = null;
|
||||
MHDDLogValue = null;
|
||||
NamespaceValue = null;
|
||||
OptionsValue = null;
|
||||
OutputValue = null;
|
||||
OutputPrefixValue = null;
|
||||
RemoteHostValue = null;
|
||||
ResumeFileValue = null;
|
||||
RetryPassesValue = null;
|
||||
SkipValue = null;
|
||||
SpeedValue = null;
|
||||
StartValue = null;
|
||||
SubchannelValue = null;
|
||||
WidthValue = null;
|
||||
XMLSidecarValue = null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void SetDefaultParameters(char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
{
|
||||
BaseCommand = Command.MediaDump;
|
||||
|
||||
InputValue = $"\\\\?\\{driveLetter}:";
|
||||
OutputValue = filename;
|
||||
|
||||
if (driveSpeed != null)
|
||||
{
|
||||
this[Flag.Speed] = true;
|
||||
SpeedValue = (sbyte?)driveSpeed;
|
||||
}
|
||||
|
||||
// First check to see if the combination of system and MediaType is valid
|
||||
var validTypes = Validators.GetValidMediaTypes(this.System);
|
||||
if (!validTypes.Contains(this.Type))
|
||||
return;
|
||||
|
||||
// Set retry count
|
||||
if (options.AaruRereadCount > 0)
|
||||
{
|
||||
this[Flag.RetryPasses] = true;
|
||||
RetryPassesValue = (short)options.AaruRereadCount;
|
||||
}
|
||||
|
||||
// Set user-defined options
|
||||
this[Flag.Debug] = options.AaruEnableDebug;
|
||||
this[Flag.Verbose] = options.AaruEnableVerbose;
|
||||
this[Flag.Force] = options.AaruForceDumping;
|
||||
this[Flag.Private] = options.AaruStripPersonalData;
|
||||
|
||||
// TODO: Look at dump-media formats and the like and see what options there are there to fill in defaults
|
||||
// Now sort based on disc type
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
this[Flag.FirstPregap] = true;
|
||||
this[Flag.FixOffset] = true;
|
||||
this[Flag.Subchannel] = true;
|
||||
SubchannelValue = "any";
|
||||
break;
|
||||
case MediaType.DVD:
|
||||
// Currently no defaults set
|
||||
break;
|
||||
case MediaType.GDROM:
|
||||
// Currently no defaults set
|
||||
break;
|
||||
case MediaType.HDDVD:
|
||||
// Currently no defaults set
|
||||
break;
|
||||
case MediaType.BluRay:
|
||||
// Currently no defaults set
|
||||
break;
|
||||
|
||||
// Special Formats
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
// Currently no defaults set
|
||||
break;
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
// Currently no defaults set
|
||||
break;
|
||||
|
||||
// Non-optical
|
||||
case MediaType.FloppyDisk:
|
||||
// Currently no defaults set
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override bool ValidateAndSetParameters(string parameters)
|
||||
{
|
||||
// The string has to be valid by itself first
|
||||
@@ -1473,232 +1688,9 @@ namespace DICUI.Aaru
|
||||
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>
|
||||
/// <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.CDROM:
|
||||
if (!File.Exists($"{basePath}.cicm.xml"))
|
||||
missingFiles += $";{basePath}.cicm.xml";
|
||||
if (!File.Exists($"{basePath}.ibg"))
|
||||
missingFiles += $";{basePath}.ibg";
|
||||
if (!File.Exists($"{basePath}.log"))
|
||||
missingFiles += $";{basePath}.log";
|
||||
if (!File.Exists($"{basePath}.mhddlog.bin"))
|
||||
missingFiles += $";{basePath}.mhddlog.bin";
|
||||
if (!File.Exists($"{basePath}.resume.xml"))
|
||||
missingFiles += $";{basePath}.resume.xml";
|
||||
if (!File.Exists($"{basePath}.sub.log"))
|
||||
missingFiles += $";{basePath}.sub.log";
|
||||
#endregion
|
||||
|
||||
break;
|
||||
|
||||
case MediaType.DVD:
|
||||
if (!File.Exists($"{basePath}.cicm.xml"))
|
||||
missingFiles += $";{basePath}.cicm.xml";
|
||||
if (!File.Exists($"{basePath}.ibg"))
|
||||
missingFiles += $";{basePath}.ibg";
|
||||
if (!File.Exists($"{basePath}.log"))
|
||||
missingFiles += $";{basePath}.log";
|
||||
if (!File.Exists($"{basePath}.mhddlog.bin"))
|
||||
missingFiles += $";{basePath}.mhddlog.bin";
|
||||
if (!File.Exists($"{basePath}.resume.xml"))
|
||||
missingFiles += $";{basePath}.resume.xml";
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return false; // TODO: Figure out more formats
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
// TODO: Fill in submission info specifics for Aaru
|
||||
string outputDirectory = Path.GetDirectoryName(basePath);
|
||||
|
||||
// Deserialize the sidecar, if possible
|
||||
var sidecar = GenerateSidecar(basePath + ".cicm.xml");
|
||||
|
||||
// Fill in the hash data
|
||||
info.TracksAndWriteOffsets.ClrMameProData = GenerateDatfile(sidecar, basePath);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
// TODO: Can this do GD-ROM?
|
||||
info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD";
|
||||
|
||||
long errorCount = -1;
|
||||
if (File.Exists(basePath + ".resume.xml"))
|
||||
errorCount = GetErrorCount(basePath + ".resume.xml");
|
||||
|
||||
info.CommonDiscInfo.ErrorsCount = (errorCount == -1 ? "Error retrieving error count" : errorCount.ToString());
|
||||
|
||||
info.TracksAndWriteOffsets.Cuesheet = GenerateCuesheet(sidecar, basePath) ?? "";
|
||||
|
||||
string cdWriteOffset = GetWriteOffset(sidecar) ?? "";
|
||||
info.CommonDiscInfo.RingWriteOffset = cdWriteOffset;
|
||||
info.TracksAndWriteOffsets.OtherWriteOffsets = cdWriteOffset;
|
||||
break;
|
||||
|
||||
case MediaType.DVD:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.BluRay:
|
||||
bool xgd = (system == KnownSystem.MicrosoftXBOX || system == KnownSystem.MicrosoftXBOX360);
|
||||
|
||||
// Get the individual hash data, as per internal
|
||||
if (GetISOHashValues(info.TracksAndWriteOffsets.ClrMameProData, out long size, out string crc32, out string md5, out string sha1))
|
||||
{
|
||||
info.SizeAndChecksums.Size = size;
|
||||
info.SizeAndChecksums.CRC32 = crc32;
|
||||
info.SizeAndChecksums.MD5 = md5;
|
||||
info.SizeAndChecksums.SHA1 = sha1;
|
||||
}
|
||||
|
||||
// Deal with the layerbreak
|
||||
string layerbreak = null;
|
||||
if (type == MediaType.DVD)
|
||||
layerbreak = GetLayerbreak(sidecar) ?? "";
|
||||
else if (type == MediaType.BluRay)
|
||||
layerbreak = info.SizeAndChecksums.Size > 25_025_314_816 ? "25025314816" : null;
|
||||
|
||||
// If we have a single-layer disc
|
||||
if (string.IsNullOrWhiteSpace(layerbreak))
|
||||
{
|
||||
info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD";
|
||||
}
|
||||
// If we have a dual-layer disc
|
||||
else
|
||||
{
|
||||
info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD";
|
||||
info.SizeAndChecksums.Layerbreak = Int64.Parse(layerbreak);
|
||||
}
|
||||
|
||||
// TODO: Investigate XGD disc outputs
|
||||
// TODO: Investigate BD specifics like PIC
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
switch (system)
|
||||
{
|
||||
// TODO: Can we get SecuROM data?
|
||||
// TODO: Can we get SS version/ranges?
|
||||
// TODO: Can we get DMI info?
|
||||
// TODO: Can we get Sega Header info?
|
||||
// TODO: Can we get PS1 EDC status?
|
||||
// TODO: Can we get PS1 LibCrypt status?
|
||||
|
||||
case KnownSystem.DVDAudio:
|
||||
case KnownSystem.DVDVideo:
|
||||
info.CopyProtection.Protection = GetDVDProtection(sidecar) ?? "";
|
||||
break;
|
||||
|
||||
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.MicrosoftXBOX:
|
||||
if (GetXgdAuxInfo(sidecar, out string dmihash, out string pfihash, out string sshash, out string ss, out string ssver))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"{Template.XBOXDMIHash}: {dmihash ?? ""}\n" +
|
||||
$"{Template.XBOXPFIHash}: {pfihash ?? ""}\n" +
|
||||
$"{Template.XBOXSSHash}: {sshash ?? ""}\n" +
|
||||
$"{Template.XBOXSSVersion}: {ssver ?? ""}\n";
|
||||
info.Extras.SecuritySectorRanges = ss ?? "";
|
||||
}
|
||||
|
||||
if (GetXboxDMIInfo(sidecar, out string serial, out string version, out Region? region))
|
||||
{
|
||||
info.CommonDiscInfo.Serial = serial ?? "";
|
||||
info.VersionAndEditions.Version = version ?? "";
|
||||
info.CommonDiscInfo.Region = region;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case KnownSystem.MicrosoftXBOX360:
|
||||
if (GetXgdAuxInfo(sidecar, out string dmi360hash, out string pfi360hash, out string ss360hash, out string ss360, out string ssver360))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"{Template.XBOXDMIHash}: {dmi360hash ?? ""}\n" +
|
||||
$"{Template.XBOXPFIHash}: {pfi360hash ?? ""}\n" +
|
||||
$"{Template.XBOXSSHash}: {ss360hash ?? ""}\n" +
|
||||
$"{Template.XBOXSSVersion}: {ssver360 ?? ""}\n";
|
||||
info.Extras.SecuritySectorRanges = ss360 ?? "";
|
||||
}
|
||||
|
||||
if (GetXbox360DMIInfo(sidecar, out string serial360, out string version360, out Region? region360))
|
||||
{
|
||||
info.CommonDiscInfo.Serial = serial360 ?? "";
|
||||
info.VersionAndEditions.Version = version360 ?? "";
|
||||
info.CommonDiscInfo.Region = region360;
|
||||
}
|
||||
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
|
||||
@@ -1976,6 +1968,8 @@ namespace DICUI.Aaru
|
||||
return commands;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Process Parameter Helpers
|
||||
|
||||
/// <summary>
|
||||
@@ -2262,9 +2256,11 @@ namespace DICUI.Aaru
|
||||
|
||||
// Required variables
|
||||
uint totalTracks = 0;
|
||||
CueSheet cueSheet = new CueSheet();
|
||||
cueSheet.Performer = string.Join(", ", cicmSidecar.Performer ?? new string[0]);
|
||||
cueSheet.Files = new List<CueFile>();
|
||||
CueSheet cueSheet = new CueSheet
|
||||
{
|
||||
Performer = string.Join(", ", cicmSidecar.Performer ?? new string[0]),
|
||||
Files = new List<CueFile>(),
|
||||
};
|
||||
|
||||
// Only care about OpticalDisc types
|
||||
if (cicmSidecar.OpticalDisc == null || cicmSidecar.OpticalDisc.Length == 0)
|
||||
@@ -2288,17 +2284,21 @@ namespace DICUI.Aaru
|
||||
foreach (TrackType track in opticalDisc.Track)
|
||||
{
|
||||
// Create cue track entry
|
||||
CueTrack cueTrack = new CueTrack();
|
||||
cueTrack.Number = (int)(track.Sequence?.TrackNumber ?? 0);
|
||||
cueTrack.DataType = ConvertToDataType(track.TrackType1, track.BytesPerSector);
|
||||
cueTrack.Flags = ConvertToTrackFlag(track.Flags);
|
||||
cueTrack.ISRC = track.ISRC;
|
||||
CueTrack cueTrack = new CueTrack
|
||||
{
|
||||
Number = (int)(track.Sequence?.TrackNumber ?? 0),
|
||||
DataType = ConvertToDataType(track.TrackType1, track.BytesPerSector),
|
||||
Flags = ConvertToTrackFlag(track.Flags),
|
||||
ISRC = track.ISRC,
|
||||
};
|
||||
|
||||
// Create cue file entry
|
||||
CueFile cueFile = new CueFile();
|
||||
cueFile.FileName = GenerateTrackName(basePath, (int)totalTracks, cueTrack.Number, opticalDisc.DiscType);
|
||||
cueFile.FileType = CueFileType.BINARY;
|
||||
cueFile.Tracks = new List<CueTrack>();
|
||||
CueFile cueFile = new CueFile
|
||||
{
|
||||
FileName = GenerateTrackName(basePath, (int)totalTracks, cueTrack.Number, opticalDisc.DiscType),
|
||||
FileType = CueFileType.BINARY,
|
||||
Tracks = new List<CueTrack>(),
|
||||
};
|
||||
|
||||
// Add index data
|
||||
if (track.Indexes != null && track.Indexes.Length > 0)
|
||||
@@ -2971,9 +2971,9 @@ namespace DICUI.Aaru
|
||||
/// </summary>
|
||||
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
|
||||
/// <returns>True on successful extraction of info, false otherwise</returns>
|
||||
private static bool GetXboxDMIInfo(CICMMetadataType cicmSidecar, out string serial, out string version, out Region? region)
|
||||
private static bool GetXboxDMIInfo(CICMMetadataType cicmSidecar, out string serial, out string version, out RedumpRegion? region)
|
||||
{
|
||||
serial = null; version = null; region = Region.World;
|
||||
serial = null; version = null; region = RedumpRegion.World;
|
||||
|
||||
// If the object is null, we can't get information from it
|
||||
if (cicmSidecar == null)
|
||||
@@ -3019,9 +3019,9 @@ namespace DICUI.Aaru
|
||||
/// </summary>
|
||||
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
|
||||
/// <returns>True on successful extraction of info, false otherwise</returns>
|
||||
private static bool GetXbox360DMIInfo(CICMMetadataType cicmSidecar, out string serial, out string version, out Region? region)
|
||||
private static bool GetXbox360DMIInfo(CICMMetadataType cicmSidecar, out string serial, out string version, out RedumpRegion? region)
|
||||
{
|
||||
serial = null; version = null; region = Region.World;
|
||||
serial = null; version = null; region = RedumpRegion.World;
|
||||
|
||||
// If the object is null, we can't get information from it
|
||||
if (cicmSidecar == null)
|
||||
@@ -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")]
|
||||
@@ -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
|
||||
@@ -4,7 +4,7 @@ using System.IO;
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace DICUI.CueSheets
|
||||
namespace MPF.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// The audio or data file’s filetype
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace DICUI.CueSheets
|
||||
namespace MPF.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single INDEX in a TRACK
|
||||
@@ -8,7 +8,7 @@ using System.Text.RegularExpressions;
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace DICUI.CueSheets
|
||||
namespace MPF.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single cuesheet
|
||||
@@ -5,7 +5,7 @@ using System.IO;
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace DICUI.CueSheets
|
||||
namespace MPF.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Track datatype
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace DICUI.CueSheets
|
||||
namespace MPF.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents POSTGAP information of a track
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace DICUI.CueSheets
|
||||
namespace MPF.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents PREGAP information of a track
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace DICUI.DD
|
||||
namespace MPF.DD
|
||||
{
|
||||
/// <summary>
|
||||
/// Top-level commands for DD
|
||||
@@ -1,6 +1,6 @@
|
||||
using DICUI.Data;
|
||||
using MPF.Data;
|
||||
|
||||
namespace DICUI.DD
|
||||
namespace MPF.DD
|
||||
{
|
||||
public static class Converters
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace DICUI.DD
|
||||
namespace MPF.DD
|
||||
{
|
||||
/// <summary>
|
||||
/// Supported DD commands
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace DICUI.Data
|
||||
namespace MPF.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Constant values for UI
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.IO;
|
||||
using DICUI.Data;
|
||||
|
||||
namespace DICUI.Utilities
|
||||
namespace MPF.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents information for a single drive
|
||||
@@ -14,14 +13,19 @@ namespace DICUI.Utilities
|
||||
public InternalDriveType? InternalDriveType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// DriveInfo object representing the drive, if possible
|
||||
/// Drive partition format
|
||||
/// </summary>
|
||||
public DriveInfo DriveInfo { get; private set; }
|
||||
public string DriveFormat { get { return driveInfo.DriveFormat; } }
|
||||
|
||||
/// <summary>
|
||||
/// Windows drive letter
|
||||
/// </summary>
|
||||
public char Letter { get { return DriveInfo?.Name[0] ?? '\0'; } }
|
||||
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
|
||||
@@ -31,12 +35,12 @@ namespace DICUI.Utilities
|
||||
get
|
||||
{
|
||||
string volumeLabel = Template.DiscNotDetected;
|
||||
if (DriveInfo.IsReady)
|
||||
if (driveInfo.IsReady)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(DriveInfo.VolumeLabel))
|
||||
if (string.IsNullOrWhiteSpace(driveInfo.VolumeLabel))
|
||||
volumeLabel = "track";
|
||||
else
|
||||
volumeLabel = DriveInfo.VolumeLabel;
|
||||
volumeLabel = driveInfo.VolumeLabel;
|
||||
}
|
||||
|
||||
foreach (char c in Path.GetInvalidFileNameChars())
|
||||
@@ -47,19 +51,14 @@ namespace DICUI.Utilities
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drive partition format
|
||||
/// DriveInfo object representing the drive, if possible
|
||||
/// </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; } }
|
||||
private readonly DriveInfo driveInfo;
|
||||
|
||||
public Drive(InternalDriveType? driveType, DriveInfo driveInfo)
|
||||
{
|
||||
this.InternalDriveType = driveType;
|
||||
this.DriveInfo = driveInfo;
|
||||
this.driveInfo = driveInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -71,7 +70,7 @@ namespace DICUI.Utilities
|
||||
public byte[] ReadSector(long num, int size = 2048)
|
||||
{
|
||||
// Missing drive leter is not supported
|
||||
if (string.IsNullOrEmpty(this.DriveInfo?.Name))
|
||||
if (string.IsNullOrEmpty(this.driveInfo?.Name))
|
||||
return null;
|
||||
|
||||
// We don't support negative sectors
|
||||
@@ -79,10 +78,11 @@ namespace DICUI.Utilities
|
||||
return null;
|
||||
|
||||
// Wrap the following in case of device access errors
|
||||
Stream fs = null;
|
||||
try
|
||||
{
|
||||
// Open the drive as a device
|
||||
var fs = File.OpenRead($"\\\\?\\{this.Letter}:");
|
||||
fs = File.OpenRead($"\\\\?\\{this.Letter}:");
|
||||
|
||||
// Seek to the start of the sector, if possible
|
||||
long start = num * size;
|
||||
@@ -97,6 +97,10 @@ namespace DICUI.Utilities
|
||||
{
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
fs?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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,
|
||||
@@ -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
511
MPF.Library/Data/Options.cs
Normal 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
|
||||
}
|
||||
}
|
||||
77
MPF.Library/Data/ProcessingQueue.cs
Normal file
77
MPF.Library/Data/ProcessingQueue.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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 & 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; }
|
||||
|
||||
@@ -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";
|
||||
@@ -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:
|
||||
@@ -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,
|
||||
File diff suppressed because it is too large
Load Diff
160
MPF.Library/Hashing/Hasher.cs
Normal file
160
MPF.Library/Hashing/Hasher.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
153
MPF.Library/Hashing/OptimizedCRC.cs
Normal file
153
MPF.Library/Hashing/OptimizedCRC.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
79
MPF.Library/Hashing/ThreadLoadBuffer.cs
Normal file
79
MPF.Library/Hashing/ThreadLoadBuffer.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,27 @@
|
||||
<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>
|
||||
<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-2020</Copyright>
|
||||
<RepositoryUrl>https://github.com/SabreTools/DICUI</RepositoryUrl>
|
||||
<Version>1.18</Version>
|
||||
<AssemblyVersion>1.18</AssemblyVersion>
|
||||
<FileVersion>1.18</FileVersion>
|
||||
<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>
|
||||
@@ -67,11 +73,13 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="1.5.0" GeneratePathProperty="true">
|
||||
<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="12.0.3" />
|
||||
<PackageReference Include="System.Management" Version="4.7.0" />
|
||||
<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>
|
||||
229
MPF.Library/Redump/Extras.cs
Normal file
229
MPF.Library/Redump/Extras.cs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,11 @@ using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using DICUI.Utilities;
|
||||
using MPF.Data;
|
||||
using MPF.Utilities;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace DICUI.Web
|
||||
namespace MPF.Redump
|
||||
{
|
||||
// https://stackoverflow.com/questions/1777221/using-cookiecontainer-with-webclient-class
|
||||
public class RedumpWebClient : WebClient
|
||||
@@ -34,7 +35,7 @@ namespace DICUI.Web
|
||||
+ "<tr><td>(?<row1number>.*?)</td><td>(?<row1contents>.*?)</td><td>(?<row1ascii>.*?)</td></tr>"
|
||||
+ "<tr><td>(?<row2number>.*?)</td><td>(?<row2contents>.*?)</td><td>(?<row2ascii>.*?)</td></tr>"
|
||||
+ "<tr><td>(?<row3number>.*?)</td><td>(?<row3contents>.*?)</td><td>(?<row3ascii>.*?)</td></tr>"
|
||||
+ "<tr><td>(?<row4number>.*?)</td><td>(?<row4contents>.*?)</td><td>(?<row4ascii>.*?)</td></tr>");
|
||||
+ "<tr><td>(?<row4number>.*?)</td><td>(?<row4contents>.*?)</td><td>(?<row4ascii>.*?)</td></tr>", RegexOptions.Singleline);
|
||||
|
||||
/// <summary>
|
||||
/// Regex matching the category field on a disc page
|
||||
@@ -44,12 +45,12 @@ namespace DICUI.Web
|
||||
/// <summary>
|
||||
/// Regex matching the comments field on a disc page
|
||||
/// </summary>
|
||||
private readonly Regex commentsRegex = new Regex(@"<tr><th>Comments</th></tr><tr><td>(.*?)</td></tr>");
|
||||
private readonly Regex commentsRegex = new Regex(@"<tr><th>Comments</th></tr><tr><td>(.*?)</td></tr>", RegexOptions.Singleline);
|
||||
|
||||
/// <summary>
|
||||
/// Regex matching the contents field on a disc page
|
||||
/// </summary>
|
||||
private readonly Regex contentsRegex = new Regex(@"<tr><th>Contents</th></tr><tr .*?><td>(.*?)</td></tr>");
|
||||
private readonly Regex contentsRegex = new Regex(@"<tr><th>Contents</th></tr><tr .*?><td>(.*?)</td></tr>", RegexOptions.Singleline);
|
||||
|
||||
/// <summary>
|
||||
/// Regex matching individual disc links on a results page
|
||||
@@ -64,7 +65,7 @@ namespace DICUI.Web
|
||||
/// <summary>
|
||||
/// Regex matching the dumpers on a disc page
|
||||
/// </summary>
|
||||
private readonly Regex dumpersRegex = new Regex(@"<a href=""/discs/dumper/(.*?)/"">");
|
||||
private readonly Regex dumpersRegex = new Regex(@"<a href=""/discs/dumper/(.*?)/"">", RegexOptions.Singleline);
|
||||
|
||||
/// <summary>
|
||||
/// Regex matching the edition field on a disc page
|
||||
@@ -119,7 +120,7 @@ namespace DICUI.Web
|
||||
+ @"<tr><td>Creation</td><td>(?<creationbytes>.*?)</td><td>(?<creationdate>.*?)</td><td>(?<creationtime>.*?)</td><td>(?<creationtimezone>.*?)</td></tr>"
|
||||
+ @"<tr><td>Modification</td><td>(?<modificationbytes>.*?)</td><td>(?<modificationdate>.*?)</td><td>(?<modificationtime>.*?)</td><td>(?<modificationtimezone>.*?)</td></tr>"
|
||||
+ @"<tr><td>Expiration</td><td>(?<expirationbytes>.*?)</td><td>(?<expirationdate>.*?)</td><td>(?<expirationtime>.*?)</td><td>(?<expirationtimezone>.*?)</td></tr>"
|
||||
+ @"<tr><td>Effective</td><td>(?<effectivebytes>.*?)</td><td>(?<effectivedate>.*?)</td><td>(?<effectivetime>.*?)</td><td>(?<effectivetimezone>.*?)</td></tr>");
|
||||
+ @"<tr><td>Effective</td><td>(?<effectivebytes>.*?)</td><td>(?<effectivedate>.*?)</td><td>(?<effectivetime>.*?)</td><td>(?<effectivetimezone>.*?)</td></tr>", RegexOptions.Singleline);
|
||||
|
||||
/// <summary>
|
||||
/// Regex matching the region field on a disc page
|
||||
@@ -129,12 +130,12 @@ namespace DICUI.Web
|
||||
/// <summary>
|
||||
/// Regex matching a double-layer disc ringcode information
|
||||
/// </summary>
|
||||
private readonly Regex ringCodeDoubleRegex = new Regex(@""); // Varies based on available fields, like Addtional Mould
|
||||
private readonly Regex ringCodeDoubleRegex = new Regex(@"", RegexOptions.Singleline); // Varies based on available fields, like Addtional Mould
|
||||
|
||||
/// <summary>
|
||||
/// Regex matching a single-layer disc ringcode information
|
||||
/// </summary>
|
||||
private readonly Regex ringCodeSingleRegex = new Regex(@""); // Varies based on available fields, like Addtional Mould
|
||||
private readonly Regex ringCodeSingleRegex = new Regex(@"", RegexOptions.Singleline); // Varies based on available fields, like Addtional Mould
|
||||
|
||||
/// <summary>
|
||||
/// Regex matching the serial field on a disc page
|
||||
@@ -159,7 +160,7 @@ namespace DICUI.Web
|
||||
/// <summary>
|
||||
/// Regex matching a single track on a disc page
|
||||
/// </summary>
|
||||
private readonly Regex trackRegex = new Regex(@"<tr><td>(?<number>.*?)</td><td>(?<type>.*?)</td><td>(?<pregap>.*?)</td><td>(?<length>.*?)</td><td>(?<sectors>.*?)</td><td>(?<size>.*?)</td><td>(?<crc32>.*?)</td><td>(?<md5>.*?)</td><td>(?<sha1>.*?)</td></tr>");
|
||||
private readonly Regex trackRegex = new Regex(@"<tr><td>(?<number>.*?)</td><td>(?<type>.*?)</td><td>(?<pregap>.*?)</td><td>(?<length>.*?)</td><td>(?<sectors>.*?)</td><td>(?<size>.*?)</td><td>(?<crc32>.*?)</td><td>(?<md5>.*?)</td><td>(?<sha1>.*?)</td></tr>", RegexOptions.Singleline);
|
||||
|
||||
/// <summary>
|
||||
/// Regex matching the track count on a disc page
|
||||
@@ -310,8 +311,8 @@ namespace DICUI.Web
|
||||
/// </summary>
|
||||
/// <param name="username">Redump username</param>
|
||||
/// <param name="password">Redump password</param>
|
||||
/// <returns>True if the user could be logged in, false otherwise, false otherwise</returns>
|
||||
public bool Login(string username, string password)
|
||||
/// <returns>True if the user could be logged in, false otherwise, null on error</returns>
|
||||
public bool? Login(string username, string password)
|
||||
{
|
||||
// Credentials verification
|
||||
if (!string.IsNullOrWhiteSpace(username) && !string.IsNullOrWhiteSpace(password))
|
||||
@@ -359,19 +360,19 @@ namespace DICUI.Web
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"An exception occurred while trying to log in: {ex}");
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the latest version of DICUI from GitHub and the release URL
|
||||
/// Get the latest version of MPF from GitHub and the release URL
|
||||
/// </summary>
|
||||
public (string tag, string url) GetRemoteVersionAndUrl()
|
||||
{
|
||||
Headers["User-Agent"] = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0";
|
||||
|
||||
// TODO: Figure out a better way than having this hardcoded...
|
||||
string url = "https://api.github.com/repos/SabreTools/DICUI/releases/latest";
|
||||
string url = "https://api.github.com/repos/SabreTools/MPF/releases/latest";
|
||||
string latestReleaseJsonString = DownloadString(url);
|
||||
var latestReleaseJson = JObject.Parse(latestReleaseJsonString);
|
||||
string latestTag = latestReleaseJson["tag_name"].ToString();
|
||||
@@ -422,9 +423,9 @@ namespace DICUI.Web
|
||||
// Category
|
||||
match = categoryRegex.Match(discData);
|
||||
if (match.Success)
|
||||
info.CommonDiscInfo.Category = Extensions.ToCategory(match.Groups[1].Value);
|
||||
info.CommonDiscInfo.Category = Converters.ToDiscCategory(match.Groups[1].Value);
|
||||
else
|
||||
info.CommonDiscInfo.Category = DiscCategory.Games;
|
||||
info.CommonDiscInfo.Category = RedumpDiscCategory.Games;
|
||||
|
||||
// Comments
|
||||
match = commentsRegex.Match(discData);
|
||||
@@ -479,10 +480,10 @@ namespace DICUI.Web
|
||||
matches = languagesRegex.Matches(discData);
|
||||
if (matches.Count > 0)
|
||||
{
|
||||
List<Language?> tempLanguages = new List<Language?>();
|
||||
List<RedumpLanguage?> tempLanguages = new List<RedumpLanguage?>();
|
||||
foreach (Match submatch in matches)
|
||||
{
|
||||
tempLanguages.Add(Extensions.ToLanguage(submatch.Groups[1].Value));
|
||||
tempLanguages.Add(Converters.ToRedumpLanguage(submatch.Groups[1].Value));
|
||||
}
|
||||
|
||||
info.CommonDiscInfo.Languages = tempLanguages.Where(l => l != null).ToArray();
|
||||
@@ -516,7 +517,7 @@ namespace DICUI.Web
|
||||
// Region
|
||||
match = regionRegex.Match(discData);
|
||||
if (match.Success)
|
||||
info.CommonDiscInfo.Region = Extensions.ToRegion(match.Groups[1].Value);
|
||||
info.CommonDiscInfo.Region = Converters.ToRedumpRegion(match.Groups[1].Value);
|
||||
|
||||
// Serial
|
||||
match = serialRegex.Match(discData);
|
||||
@@ -622,13 +623,13 @@ namespace DICUI.Web
|
||||
/// <param name="useSubfolders">True to use named subfolders to store downloads, false to store directly in the output directory</param>
|
||||
public void DownloadPacks(string outDir, bool useSubfolders)
|
||||
{
|
||||
this.DownloadPacks(packCuesUrl, Extensions.HasCues, "CUEs", outDir, useSubfolders ? "cue" : null);
|
||||
this.DownloadPacks(packDatfileUrl, Extensions.HasDat, "DATs", outDir, useSubfolders ? "dat" : null);
|
||||
this.DownloadPacks(packDkeysUrl, Extensions.HasDkeys, "Decrypted KEYS", outDir, useSubfolders ? "dkey" : null);
|
||||
this.DownloadPacks(packGdiUrl, Extensions.HasGdi, "GDIs", outDir, useSubfolders ? "gdi" : null);
|
||||
this.DownloadPacks(packKeysUrl, Extensions.HasKeys, "KEYS", outDir, useSubfolders ? "keys" : null);
|
||||
this.DownloadPacks(packLsdUrl, Extensions.HasKeys, "LSD", outDir, useSubfolders ? "lsd" : null);
|
||||
this.DownloadPacks(packSbiUrl, Extensions.HasSbi, "SBIs", outDir, useSubfolders ? "sbi" : null);
|
||||
this.DownloadPacks(packCuesUrl, Extras.HasCues, "CUEs", outDir, useSubfolders ? "cue" : null);
|
||||
this.DownloadPacks(packDatfileUrl, Extras.HasDat, "DATs", outDir, useSubfolders ? "dat" : null);
|
||||
this.DownloadPacks(packDkeysUrl, Extras.HasDkeys, "Decrypted KEYS", outDir, useSubfolders ? "dkey" : null);
|
||||
this.DownloadPacks(packGdiUrl, Extras.HasGdi, "GDIs", outDir, useSubfolders ? "gdi" : null);
|
||||
this.DownloadPacks(packKeysUrl, Extras.HasKeys, "KEYS", outDir, useSubfolders ? "keys" : null);
|
||||
this.DownloadPacks(packLsdUrl, Extras.HasKeys, "LSD", outDir, useSubfolders ? "lsd" : null);
|
||||
this.DownloadPacks(packSbiUrl, Extras.HasSbi, "SBIs", outDir, useSubfolders ? "sbi" : null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -641,26 +642,26 @@ namespace DICUI.Web
|
||||
{
|
||||
RedumpSystem?[] systemAsArray = new RedumpSystem?[] { system };
|
||||
|
||||
if (Extensions.HasCues.Contains(system))
|
||||
if (Extras.HasCues.Contains(system))
|
||||
this.DownloadPacks(packCuesUrl, systemAsArray, "CUEs", outDir, useSubfolders ? "cue" : null);
|
||||
|
||||
if (Extensions.HasDat.Contains(system))
|
||||
this.DownloadPacks(packCuesUrl, Extensions.HasDat, "DATs", outDir, useSubfolders ? "dat" : null);
|
||||
if (Extras.HasDat.Contains(system))
|
||||
this.DownloadPacks(packCuesUrl, Extras.HasDat, "DATs", outDir, useSubfolders ? "dat" : null);
|
||||
|
||||
if (Extensions.HasDkeys.Contains(system))
|
||||
this.DownloadPacks(packCuesUrl, Extensions.HasDkeys, "Decrypted KEYS", outDir, useSubfolders ? "dkey" : null);
|
||||
if (Extras.HasDkeys.Contains(system))
|
||||
this.DownloadPacks(packCuesUrl, Extras.HasDkeys, "Decrypted KEYS", outDir, useSubfolders ? "dkey" : null);
|
||||
|
||||
if (Extensions.HasGdi.Contains(system))
|
||||
this.DownloadPacks(packCuesUrl, Extensions.HasGdi, "GDIs", outDir, useSubfolders ? "gdi" : null);
|
||||
if (Extras.HasGdi.Contains(system))
|
||||
this.DownloadPacks(packCuesUrl, Extras.HasGdi, "GDIs", outDir, useSubfolders ? "gdi" : null);
|
||||
|
||||
if (Extensions.HasKeys.Contains(system))
|
||||
this.DownloadPacks(packCuesUrl, Extensions.HasKeys, "KEYS", outDir, useSubfolders ? "keys" : null);
|
||||
if (Extras.HasKeys.Contains(system))
|
||||
this.DownloadPacks(packCuesUrl, Extras.HasKeys, "KEYS", outDir, useSubfolders ? "keys" : null);
|
||||
|
||||
if (Extensions.HasLsd.Contains(system))
|
||||
this.DownloadPacks(packCuesUrl, Extensions.HasKeys, "LSD", outDir, useSubfolders ? "lsd" : null);
|
||||
if (Extras.HasLsd.Contains(system))
|
||||
this.DownloadPacks(packCuesUrl, Extras.HasKeys, "LSD", outDir, useSubfolders ? "lsd" : null);
|
||||
|
||||
if (Extensions.HasSbi.Contains(system))
|
||||
this.DownloadPacks(packCuesUrl, Extensions.HasSbi, "SBIs", outDir, useSubfolders ? "sbi" : null);
|
||||
if (Extras.HasSbi.Contains(system))
|
||||
this.DownloadPacks(packCuesUrl, Extras.HasSbi, "SBIs", outDir, useSubfolders ? "sbi" : null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -844,22 +845,22 @@ namespace DICUI.Web
|
||||
// Category
|
||||
match = categoryRegex.Match(discData);
|
||||
if (match.Success)
|
||||
info.CommonDiscInfo.Category = Extensions.ToCategory(match.Groups[1].Value);
|
||||
info.CommonDiscInfo.Category = Converters.ToDiscCategory(match.Groups[1].Value);
|
||||
else
|
||||
info.CommonDiscInfo.Category = DiscCategory.Games;
|
||||
info.CommonDiscInfo.Category = RedumpDiscCategory.Games;
|
||||
|
||||
// Region
|
||||
match = regionRegex.Match(discData);
|
||||
if (match.Success)
|
||||
info.CommonDiscInfo.Region = Extensions.ToRegion(match.Groups[1].Value);
|
||||
info.CommonDiscInfo.Region = Converters.ToRedumpRegion(match.Groups[1].Value);
|
||||
|
||||
// Languages
|
||||
var matches = languagesRegex.Matches(discData);
|
||||
if (matches.Count > 0)
|
||||
{
|
||||
List<Language?> tempLanguages = new List<Language?>();
|
||||
List<RedumpLanguage?> tempLanguages = new List<RedumpLanguage?>();
|
||||
foreach (Match submatch in matches)
|
||||
tempLanguages.Add(Extensions.ToLanguage(submatch.Groups[1].Value));
|
||||
tempLanguages.Add(Converters.ToRedumpLanguage(submatch.Groups[1].Value));
|
||||
|
||||
info.CommonDiscInfo.Languages = tempLanguages.Where(l => l != null).ToArray();
|
||||
}
|
||||
@@ -941,7 +942,7 @@ namespace DICUI.Web
|
||||
/// List the disc IDs associated with a given quicksearch query
|
||||
/// </summary>
|
||||
/// <param name="query">Query string to attempt to search for</param>
|
||||
/// <returns>All disc IDs for the given query, empty on error</returns>
|
||||
/// <returns>All disc IDs for the given query, null on error</returns>
|
||||
public List<int> ListSearchResults(string query)
|
||||
{
|
||||
List<int> ids = new List<int>();
|
||||
@@ -958,13 +959,21 @@ namespace DICUI.Web
|
||||
query = query.ToLowerInvariant();
|
||||
|
||||
// Keep getting quicksearch pages until there are none left
|
||||
int pageNumber = 1;
|
||||
while (true)
|
||||
try
|
||||
{
|
||||
List<int> pageIds = CheckSingleSitePage(string.Format(quickSearchUrl, query, pageNumber++));
|
||||
ids.AddRange(pageIds);
|
||||
if (pageIds.Count <= 1)
|
||||
break;
|
||||
int pageNumber = 1;
|
||||
while (true)
|
||||
{
|
||||
List<int> pageIds = CheckSingleSitePage(string.Format(quickSearchUrl, query, pageNumber++));
|
||||
ids.AddRange(pageIds);
|
||||
if (pageIds.Count <= 1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"An exception occurred while trying to log in: {ex}");
|
||||
return null;
|
||||
}
|
||||
|
||||
return ids;
|
||||
@@ -974,7 +983,7 @@ namespace DICUI.Web
|
||||
/// List the disc IDs associated with the given user
|
||||
/// </summary>
|
||||
/// <param name="username">Username to check discs for</param>
|
||||
/// <returns>All disc IDs for the given user, empty on error</returns>
|
||||
/// <returns>All disc IDs for the given user, null on error</returns>
|
||||
public List<int> ListUser(string username)
|
||||
{
|
||||
List<int> ids = new List<int>();
|
||||
@@ -986,13 +995,21 @@ namespace DICUI.Web
|
||||
}
|
||||
|
||||
// Keep getting user pages until there are none left
|
||||
int pageNumber = 1;
|
||||
while (true)
|
||||
try
|
||||
{
|
||||
List<int> pageIds = CheckSingleSitePage(string.Format(userDumpsUrl, username, pageNumber++));
|
||||
ids.AddRange(pageIds);
|
||||
if (pageIds.Count <= 1)
|
||||
break;
|
||||
int pageNumber = 1;
|
||||
while (true)
|
||||
{
|
||||
List<int> pageIds = CheckSingleSitePage(string.Format(userDumpsUrl, username, pageNumber++));
|
||||
ids.AddRange(pageIds);
|
||||
if (pageIds.Count <= 1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"An exception occurred while trying to log in: {ex}");
|
||||
return null;
|
||||
}
|
||||
|
||||
return ids;
|
||||
@@ -1485,7 +1502,7 @@ namespace DICUI.Web
|
||||
|
||||
// If we didn't have credentials
|
||||
if (!LoggedIn)
|
||||
systems = systems.Where(s => !Extensions.BannedSystems.Contains(s)).ToArray();
|
||||
systems = systems.Where(s => !Extras.BannedSystems.Contains(s)).ToArray();
|
||||
|
||||
Console.WriteLine($"Downloading {title}");
|
||||
foreach (var system in systems)
|
||||
@@ -1514,7 +1531,7 @@ namespace DICUI.Web
|
||||
{
|
||||
// If we didn't have credentials
|
||||
if (!LoggedIn)
|
||||
systems = systems.Where(s => !Extensions.BannedSystems.Contains(s)).ToArray();
|
||||
systems = systems.Where(s => !Extras.BannedSystems.Contains(s)).ToArray();
|
||||
|
||||
Console.WriteLine($"Downloading {title}");
|
||||
foreach (var system in systems)
|
||||
216
MPF.Library/UmdImageCreator/Parameters.cs
Normal file
216
MPF.Library/UmdImageCreator/Parameters.cs
Normal file
@@ -0,0 +1,216 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MPF.Data;
|
||||
using MPF.Utilities;
|
||||
|
||||
namespace MPF.UmdImageCreator
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic set of UmdImageCreator parameters
|
||||
/// </summary>
|
||||
public class Parameters : BaseParameters
|
||||
{
|
||||
#region Metadata
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override InternalProgram InternalProgram => InternalProgram.UmdImageCreator;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(string parameters) : base(parameters) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
: base(system, type, driveLetter, filename, driveSpeed, options)
|
||||
{
|
||||
}
|
||||
|
||||
#region BaseParameters Implementations
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override (bool, List<string>) CheckAllOutputFilesExist(string basePath)
|
||||
{
|
||||
List<string> missingFiles = new List<string>();
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.UMD:
|
||||
if (!File.Exists($"{basePath}_disc.txt"))
|
||||
missingFiles.Add($"{basePath}_disc.txt");
|
||||
if (!File.Exists($"{basePath}_mainError.txt"))
|
||||
missingFiles.Add($"{basePath}_mainError.txt");
|
||||
if (!File.Exists($"{basePath}_mainInfo.txt"))
|
||||
missingFiles.Add($"{basePath}_mainInfo.txt");
|
||||
if (!File.Exists($"{basePath}_volDesc.txt"))
|
||||
missingFiles.Add($"{basePath}_volDesc.txt");
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return (false, missingFiles);
|
||||
}
|
||||
|
||||
return (!missingFiles.Any(), missingFiles);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive, bool includeArtifacts)
|
||||
{
|
||||
// Extract info based generically on MediaType
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.UMD:
|
||||
info.Extras.PVD = GetPVD(basePath + "_mainInfo.txt") ?? "";
|
||||
|
||||
if (GetFileHashes(basePath + ".iso", out long filesize, out string crc32, out string md5, out string sha1))
|
||||
{
|
||||
info.SizeAndChecksums.Size = filesize;
|
||||
info.SizeAndChecksums.CRC32 = crc32;
|
||||
info.SizeAndChecksums.MD5 = md5;
|
||||
info.SizeAndChecksums.SHA1 = sha1;
|
||||
}
|
||||
|
||||
if (GetUMDAuxInfo(basePath + "_disc.txt", out string title, out RedumpDiscCategory? umdcat, out string umdversion, out string umdlayer, out long umdsize))
|
||||
{
|
||||
info.CommonDiscInfo.Title = title ?? "";
|
||||
info.CommonDiscInfo.Category = umdcat ?? RedumpDiscCategory.Games;
|
||||
info.VersionAndEditions.Version = umdversion ?? "";
|
||||
info.SizeAndChecksums.Size = umdsize;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(umdlayer))
|
||||
info.SizeAndChecksums.Layerbreak = Int64.Parse(umdlayer ?? "-1");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill in any artifacts that exist, Base64-encoded, if we need to
|
||||
if (includeArtifacts)
|
||||
{
|
||||
if (File.Exists(basePath + "_disc.txt"))
|
||||
info.Artifacts["disc"] = GetBase64(GetFullFile(basePath + "_disc.txt"));
|
||||
if (File.Exists(basePath + "_mainError.txt"))
|
||||
info.Artifacts["mainError"] = GetBase64(GetFullFile(basePath + "_mainError.txt"));
|
||||
if (File.Exists(basePath + "_mainInfo.txt"))
|
||||
info.Artifacts["mainInfo"] = GetBase64(GetFullFile(basePath + "_mainInfo.txt"));
|
||||
if (File.Exists(basePath + "_volDesc.txt"))
|
||||
info.Artifacts["volDesc"] = GetBase64(GetFullFile(basePath + "_volDesc.txt"));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<string> GetLogFilePaths(string basePath)
|
||||
{
|
||||
List<string> logFiles = new List<string>();
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.UMD:
|
||||
if (File.Exists($"{basePath}_disc.txt"))
|
||||
logFiles.Add($"{basePath}_disc.txt");
|
||||
if (File.Exists($"{basePath}_mainError.txt"))
|
||||
logFiles.Add($"{basePath}_mainError.txt");
|
||||
if (File.Exists($"{basePath}_mainInfo.txt"))
|
||||
logFiles.Add($"{basePath}_mainInfo.txt");
|
||||
if (File.Exists($"{basePath}_volDesc.txt"))
|
||||
logFiles.Add($"{basePath}_volDesc.txt");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return logFiles;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Information Extraction Methods
|
||||
|
||||
/// <summary>
|
||||
/// Get the PVD from the input file, if possible
|
||||
/// </summary>
|
||||
/// <param name="mainInfo">_mainInfo.txt file location</param>
|
||||
/// <returns>Newline-deliminated PVD if possible, null on error</returns>
|
||||
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, 0x0000010]: 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 RedumpDiscCategory? 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
|
||||
}
|
||||
}
|
||||
174
MPF.Library/Utilities/BinaryReaderExtensions.cs
Normal file
174
MPF.Library/Utilities/BinaryReaderExtensions.cs
Normal file
@@ -0,0 +1,174 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace MPF.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Big endian reading overloads for BinaryReader
|
||||
/// </summary>
|
||||
internal static class BinaryReaderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads the specified number of bytes from the stream, starting from a specified point in the byte array.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to read data into.</param>
|
||||
/// <param name="index">The starting point in the buffer at which to begin reading into the buffer.</param>
|
||||
/// <param name="count">The number of bytes to read.</param>
|
||||
/// <returns>The number of bytes read into buffer. This might be less than the number of bytes requested if that many bytes are not available, or it might be zero if the end of the stream is reached.</returns>
|
||||
public static int ReadBigEndian(this BinaryReader reader, byte[] buffer, int index, int count)
|
||||
{
|
||||
int retval = reader.Read(buffer, index, count);
|
||||
Array.Reverse(buffer);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of characters from the stream, starting from a specified point in the character array.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to read data into.</param>
|
||||
/// <param name="index">The starting point in the buffer at which to begin reading into the buffer.</param>
|
||||
/// <param name="count">The number of characters to read.</param>
|
||||
/// <returns>The total number of characters read into the buffer. This might be less than the number of characters requested if that many characters are not currently available, or it might be zero if the end of the stream is reached.</returns>
|
||||
public static int ReadBigEndian(this BinaryReader reader, char[] buffer, int index, int count)
|
||||
{
|
||||
int retval = reader.Read(buffer, index, count);
|
||||
Array.Reverse(buffer);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of bytes from the current stream into a byte array and advances the current position by that number of bytes.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of bytes to read. This value must be 0 or a non-negative number or an exception will occur.</param>
|
||||
/// <returns>A byte array containing data read from the underlying stream. This might be less than the number of bytes requested if the end of the stream is reached.</returns>
|
||||
public static byte[] ReadBytesBigEndian(this BinaryReader reader, int count)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(count);
|
||||
Array.Reverse(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of characters from the current stream, returns the data in a character array, and advances the current position in accordance with the Encoding used and the specific character being read from the stream.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of characters to read. This value must be 0 or a non-negative number or an exception will occur.</param>
|
||||
/// <returns>A character array containing data read from the underlying stream. This might be less than the number of bytes requested if the end of the stream is reached.</returns>
|
||||
public static char[] ReadCharsBigEndian(this BinaryReader reader, int count)
|
||||
{
|
||||
char[] retval = reader.ReadChars(count);
|
||||
Array.Reverse(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a decimal value from the current stream and advances the current position of the stream by sixteen bytes.
|
||||
/// </summary>
|
||||
/// <returns>A decimal value read from the current stream.</returns>
|
||||
public static decimal ReadDecimalBigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(16);
|
||||
Array.Reverse(retval);
|
||||
|
||||
int i1 = BitConverter.ToInt32(retval, 0);
|
||||
int i2 = BitConverter.ToInt32(retval, 4);
|
||||
int i3 = BitConverter.ToInt32(retval, 8);
|
||||
int i4 = BitConverter.ToInt32(retval, 12);
|
||||
|
||||
return new decimal(new int[] { i1, i2, i3, i4 });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// eads an 8-byte floating point value from the current stream and advances the current position of the stream by eight bytes.
|
||||
/// </summary>
|
||||
/// <returns>An 8-byte floating point value read from the current stream.</returns>
|
||||
public static double ReadDoubleBigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(8);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToDouble(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 2-byte signed integer from the current stream and advances the current position of the stream by two bytes.
|
||||
/// </summary>
|
||||
/// <returns>A 2-byte signed integer read from the current stream.</returns>
|
||||
public static short ReadInt16BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(2);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToInt16(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 4-byte signed integer from the current stream and advances the current position of the stream by four bytes.
|
||||
/// </summary>
|
||||
/// <returns>A 4-byte signed integer read from the current stream.</returns>
|
||||
public static int ReadInt32BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(4);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToInt32(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an 8-byte signed integer from the current stream and advances the current position of the stream by eight bytes.
|
||||
/// </summary>
|
||||
/// <returns>An 8-byte signed integer read from the current stream.</returns>
|
||||
public static long ReadInt64BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(8);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToInt64(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 4-byte floating point value from the current stream and advances the current position of the stream by four bytes.
|
||||
/// </summary>
|
||||
/// <returns>A 4-byte floating point value read from the current stream.</returns>
|
||||
public static float ReadSingleBigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(4);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToSingle(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 2-byte unsigned integer from the current stream using little-endian encoding and advances the position of the stream by two bytes.
|
||||
///
|
||||
/// This API is not CLS-compliant.
|
||||
/// </summary>
|
||||
/// <returns>A 2-byte unsigned integer read from this stream.</returns>
|
||||
public static ushort ReadUInt16BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(2);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToUInt16(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 4-byte unsigned integer from the current stream and advances the position of the stream by four bytes.
|
||||
///
|
||||
/// This API is not CLS-compliant.
|
||||
/// </summary>
|
||||
/// <returns>A 4-byte unsigned integer read from this stream.</returns>
|
||||
public static uint ReadUInt32BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(4);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToUInt32(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an 8-byte unsigned integer from the current stream and advances the position of the stream by eight bytes.
|
||||
///
|
||||
/// This API is not CLS-compliant.
|
||||
/// </summary>
|
||||
/// <returns>An 8-byte unsigned integer read from this stream.</returns>
|
||||
public static ulong ReadUInt64BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(8);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToUInt64(retval, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
4262
MPF.Library/Utilities/Converters.cs
Normal file
4262
MPF.Library/Utilities/Converters.cs
Normal file
File diff suppressed because it is too large
Load Diff
119
MPF.Library/Utilities/EnumExtensions.cs
Normal file
119
MPF.Library/Utilities/EnumExtensions.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
using MPF.Data;
|
||||
|
||||
namespace MPF.Utilities
|
||||
{
|
||||
public static class EnumExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Determine the category based on the system
|
||||
/// </summary>
|
||||
/// <param name="system">KnownSystem value to check</param>
|
||||
/// <returns>KnownSystemCategory related to the system</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if the media supports drive speeds
|
||||
/// </summary>
|
||||
/// <param name="type">MediaType value to check</param>
|
||||
/// <returns>True if the media has variable dumping speeds, false otherwise</returns>
|
||||
public static bool DoesSupportDriveSpeed(this MediaType? type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
case MediaType.DVD:
|
||||
case MediaType.GDROM:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.BluRay:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if a system is considered audio-only
|
||||
/// </summary>
|
||||
/// <param name="system">KnownSystem value to check</param>
|
||||
/// <returns>True if the system is audio-only, false otherwise</returns>
|
||||
/// <remarks>
|
||||
/// Philips CD-i should NOT be in this list. It's being included until there's a
|
||||
/// reasonable distinction between CD-i and CD-i ready on the database side.
|
||||
/// </remarks>
|
||||
public static bool IsAudio(this KnownSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case KnownSystem.AtariJaguarCD:
|
||||
case KnownSystem.AudioCD:
|
||||
case KnownSystem.DVDAudio:
|
||||
case KnownSystem.HasbroVideoNow:
|
||||
case KnownSystem.HasbroVideoNowColor:
|
||||
case KnownSystem.HasbroVideoNowJr:
|
||||
case KnownSystem.HasbroVideoNowXP:
|
||||
case KnownSystem.PhilipsCDi:
|
||||
case KnownSystem.SuperAudioCD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if a system is a marker value
|
||||
/// </summary>
|
||||
/// <param name="system">KnownSystem value to check</param>
|
||||
/// <returns>True if the system is a marker value, false otherwise</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if a system is considered XGD
|
||||
/// </summary>
|
||||
/// <param name="system">KnownSystem value to check</param>
|
||||
/// <returns>True if the system is XGD, false otherwise</returns>
|
||||
public static bool IsXGD(this KnownSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case KnownSystem.MicrosoftXBOX:
|
||||
case KnownSystem.MicrosoftXBOX360:
|
||||
case KnownSystem.MicrosoftXBOXOne:
|
||||
case KnownSystem.MicrosoftXboxSeriesXS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user