mirror of
https://github.com/SabreTools/MPF.git
synced 2026-02-04 05:35:52 +00:00
Compare commits
107 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b2d30bc01 | ||
|
|
ec8b65a7fa | ||
|
|
ec5611f5ff | ||
|
|
3e350b666b | ||
|
|
e83f69fc3e | ||
|
|
6ecbbb6978 | ||
|
|
771483ac14 | ||
|
|
ccde878286 | ||
|
|
e0ab3e048b | ||
|
|
cf2ae163c4 | ||
|
|
5025a3e91a | ||
|
|
dab774dab3 | ||
|
|
04c6131d28 | ||
|
|
47561baee8 | ||
|
|
a8b1a8342d | ||
|
|
7b8ef00d59 | ||
|
|
65cc502a94 | ||
|
|
d38b465b08 | ||
|
|
783c323fd0 | ||
|
|
04af8807e5 | ||
|
|
1260dfdff2 | ||
|
|
e5b883fb73 | ||
|
|
1c08451487 | ||
|
|
29b483f805 | ||
|
|
2eff4a7488 | ||
|
|
5e94d02503 | ||
|
|
ccf2166b72 | ||
|
|
024394bbec | ||
|
|
301a0cb188 | ||
|
|
64231da666 | ||
|
|
5f56977021 | ||
|
|
436ccf7a34 | ||
|
|
ef7510804e | ||
|
|
8c61b87954 | ||
|
|
17ba117949 | ||
|
|
0737ba7641 | ||
|
|
e9dba0767e | ||
|
|
2d142e9e9d | ||
|
|
7a928decff | ||
|
|
eb5409bdee | ||
|
|
1578193068 | ||
|
|
131c95e6ef | ||
|
|
a7790a271f | ||
|
|
1b342d56ef | ||
|
|
a500211129 | ||
|
|
4d798fa547 | ||
|
|
597ebdc973 | ||
|
|
c6a8a9265f | ||
|
|
393c53769d | ||
|
|
fa21999d3f | ||
|
|
dafbb05b16 | ||
|
|
1c1b23a84b | ||
|
|
fd0fe4912d | ||
|
|
b5b54d13a2 | ||
|
|
da77987db3 | ||
|
|
774f44c8ce | ||
|
|
251b3754e4 | ||
|
|
963acc3336 | ||
|
|
90588a0f8b | ||
|
|
a56c212488 | ||
|
|
6484ab5fe0 | ||
|
|
1ff48258b8 | ||
|
|
81019f9d56 | ||
|
|
d47c435236 | ||
|
|
d59b114cba | ||
|
|
7f26dcba4e | ||
|
|
5e2766f982 | ||
|
|
c883f899bb | ||
|
|
8c9950d5fa | ||
|
|
3e842af273 | ||
|
|
b837623da2 | ||
|
|
6742901243 | ||
|
|
d6460a2b68 | ||
|
|
7af59dacc6 | ||
|
|
fc3ef36fef | ||
|
|
6298487346 | ||
|
|
727d9844d5 | ||
|
|
72e7619e2d | ||
|
|
24b4647037 | ||
|
|
713b3f0557 | ||
|
|
f796a9b131 | ||
|
|
2cdf92bf92 | ||
|
|
ccc1687f1a | ||
|
|
6057ec3a59 | ||
|
|
2a5e736285 | ||
|
|
010ef9016b | ||
|
|
02606318b0 | ||
|
|
d4f641b122 | ||
|
|
a1dd6e2d21 | ||
|
|
d35679d688 | ||
|
|
83f5083ce7 | ||
|
|
5b6457f4b7 | ||
|
|
c6517d526b | ||
|
|
e35f1fc2ec | ||
|
|
14f4128d4a | ||
|
|
5465252dc7 | ||
|
|
2573b47a79 | ||
|
|
fe20905524 | ||
|
|
88f19180a4 | ||
|
|
de89968a1d | ||
|
|
8fc53c91b0 | ||
|
|
1a1fbd4b40 | ||
|
|
cac6c3049b | ||
|
|
6a6871e922 | ||
|
|
4a02a3efac | ||
|
|
f6eb961af4 | ||
|
|
faeaaef02a |
50
.github/workflows/build_check.yml
vendored
Normal file
50
.github/workflows/build_check.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: MPF Check
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
project: [MPF.Check]
|
||||
runtime: [win-x86, win-x64, linux-x64, osx-x64] #[win-x86, win-x64, win-arm64, linux-x64, linux-arm64, osx-x64]
|
||||
framework: [net8.0] #[net20, net35, net40, net452, net472, net48, netcoreapp3.1, net5.0, net6.0, net7.0, net8.0]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
|
||||
- name: Build
|
||||
run: dotnet publish ${{ matrix.project }}/${{ matrix.project }}.csproj -f ${{ matrix.framework }} -r ${{ matrix.runtime }} -c Debug --self-contained true --version-suffix ${{ github.sha }} ${{ (startsWith(matrix.framework, 'net5') || startsWith(matrix.framework, 'net6') || startsWith(matrix.framework, 'net7') || startsWith(matrix.framework, 'net8')) && '-p:PublishSingleFile=true' || ''}}
|
||||
|
||||
- name: Archive build
|
||||
run: zip -r ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_debug.zip ${{ matrix.project }}/bin/Debug/${{ matrix.framework }}/${{ matrix.runtime }}/publish/
|
||||
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_debug
|
||||
path: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_debug.zip
|
||||
|
||||
- name: Upload to rolling
|
||||
uses: ncipollo/release-action@v1.14.0
|
||||
with:
|
||||
allowUpdates: True
|
||||
artifacts: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_debug.zip
|
||||
body: 'Last built commit: ${{ github.sha }}'
|
||||
name: 'Rolling Release'
|
||||
prerelease: True
|
||||
replacesArtifacts: True
|
||||
tag: "rolling"
|
||||
updateOnlyUnreleased: True
|
||||
57
.github/workflows/build_ui.yml
vendored
Normal file
57
.github/workflows/build_ui.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
name: MPF UI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
project: [MPF]
|
||||
runtime: [win-x86, win-x64]
|
||||
framework: [net8.0-windows] #[net40, net452, net472, net48, netcoreapp3.1, net5.0-windows, net6.0-windows, net7.0-windows, net8.0-windows]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
|
||||
- name: Build
|
||||
run: dotnet publish ${{ matrix.project }}/${{ matrix.project }}.csproj -f ${{ matrix.framework }} -r ${{ matrix.runtime }} -c Debug --self-contained true --version-suffix ${{ github.sha }} ${{ (startsWith(matrix.framework, 'net5') || startsWith(matrix.framework, 'net6') || startsWith(matrix.framework, 'net7') || startsWith(matrix.framework, 'net8')) && '-p:PublishSingleFile=true' || ''}}
|
||||
|
||||
- name: Bundle Redumper
|
||||
run: |
|
||||
wget https://github.com/superg/redumper/releases/download/build_311/redumper-2024.01.08_build311-win64.zip
|
||||
unzip redumper-2024.01.08_build311-win64.zip
|
||||
mkdir -p MPF/bin/Debug/${{ matrix.framework }}/${{ matrix.runtime }}/publish/Programs/Redumper
|
||||
mv redumper-2024.01.08_build311-win64/bin/redumper.exe MPF/bin/Debug/${{ matrix.framework }}/${{ matrix.runtime }}/publish/Programs/Redumper/
|
||||
|
||||
- name: Archive build
|
||||
run: zip -r ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_debug.zip ${{ matrix.project }}/bin/Debug/${{ matrix.framework }}/${{ matrix.runtime }}/publish/
|
||||
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_debug
|
||||
path: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_debug.zip
|
||||
|
||||
- name: Upload to rolling
|
||||
uses: ncipollo/release-action@v1.14.0
|
||||
with:
|
||||
allowUpdates: True
|
||||
artifacts: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_debug.zip
|
||||
body: 'Last built commit: ${{ github.sha }}'
|
||||
name: 'Rolling Release'
|
||||
prerelease: True
|
||||
replacesArtifacts: True
|
||||
tag: "rolling"
|
||||
updateOnlyUnreleased: True
|
||||
23
.github/workflows/check_pr.yml
vendored
Normal file
23
.github/workflows/check_pr.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: Build PR
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
|
||||
- name: Build
|
||||
run: dotnet build --no-restore
|
||||
|
||||
- name: Test
|
||||
run: dotnet test --no-restore --verbosity normal
|
||||
119
CHANGELIST.md
119
CHANGELIST.md
@@ -1,3 +1,119 @@
|
||||
### 3.1.6 (2024-04-27)
|
||||
|
||||
- Fix parameter parsing for `=` symbol (Deterous)
|
||||
- Define better default categories (Deterous)
|
||||
- Custom non-redump Redumper options (Deterous)
|
||||
- Update packages
|
||||
- Update packages
|
||||
|
||||
### 3.1.5 (2024-04-05)
|
||||
|
||||
- Handle `.0.physical` files from Redumpers
|
||||
- Read C2 error count from Redumper logs
|
||||
- Read last instance of hash data from Redumper
|
||||
- Add Konami Python 2 system detection
|
||||
- Fix outdated information in README
|
||||
- Fix missing information in README
|
||||
- Language selections unchecked by default
|
||||
- Update BinaryObjectScanner to 3.1.3
|
||||
- Fix information pulling for redumper (fuzz6001)
|
||||
- Update packages
|
||||
- Update BinaryObjectScanner to 3.1.4
|
||||
- Detect Xbox Series X discs (Deterous)
|
||||
- Enable Windows targeting for test project
|
||||
- Fix test project project includes
|
||||
- Fix CleanRip hash output for Check (Deterous)
|
||||
- Enable label-side mastering SID and toolstamp
|
||||
- Enable remaining fields for label-side information
|
||||
- Update BinaryObjectScanner to 3.1.5
|
||||
|
||||
### 3.1.4 (2024-03-16)
|
||||
|
||||
- Update BinaryObjectScanner to 3.1.2
|
||||
|
||||
### 3.1.3 (2024-03-15)
|
||||
|
||||
- Gate debug publishing behind use all flag
|
||||
- Hide layerbreaks if value is 0
|
||||
- Make GHA debug-only
|
||||
- Remove GHA pull request builds
|
||||
- Add PR check workflow
|
||||
- Don't link to AppVeyor artifacts page anymore
|
||||
- Add PS3 CFW support to MPF.Check (Deterous)
|
||||
- Hide size if value is 0 (Deterous)
|
||||
- Fix title normalization (Deterous)
|
||||
- Ensure no labels are empty
|
||||
- Use SabreTools.Hashing
|
||||
- Update to SabreTools.RedumpLib 1.3.5
|
||||
- Update packages to latest
|
||||
- Enable LibIRD for all .NET frameworks (Deterous)
|
||||
- Try updating PR check action
|
||||
- Fix config access persmission (Deterous)
|
||||
- Fix Check UI deadlock (Deterous)
|
||||
- Fix formatting output formatting
|
||||
- Update LibIRD to 0.9.0 (Deterous)
|
||||
- Update packages
|
||||
- Fix Redumper generic drive type (Deterous)
|
||||
- Add MPF version to Submission info (Deterous)
|
||||
- Update to RedumpLib 1.3.6
|
||||
|
||||
### 3.1.2 (2024-02-27)
|
||||
|
||||
- Remove debugging lines from build script
|
||||
- Port build script fixes from BOS
|
||||
- Fix double git hash version (feat. Deterous)
|
||||
- Readd x86 builds by default
|
||||
- Hide unavailable dumping programs (Deterous)
|
||||
- Remove DIC and Aaru bundles from CI
|
||||
- Add x86 builds to AppVeyor
|
||||
- Make AppVeyor builds framework-dependent
|
||||
- Fix misattributed artifact
|
||||
- Update README with current build instructions
|
||||
- Opt-in automatic IRD creation after PS3 dump (Deterous)
|
||||
- Add CI via Github Workflows (Deterous)
|
||||
- Reorganize solution items
|
||||
- Split CI workflow files
|
||||
- Add GHA CI status badges
|
||||
- Rename badges for GHA
|
||||
- More tweaks to CI
|
||||
- Fix net35 build issue
|
||||
- Remove now-unnecessary restore step
|
||||
- Remove net35 from MPF... again
|
||||
- Fix whitespace that got unwhitespaced
|
||||
- Fix link in README
|
||||
- Attempt to add CD to existing actions
|
||||
- Try fixing the artifact upload
|
||||
- Use recommendation from upload-artifact
|
||||
- Revert artifact ID, use name?
|
||||
- Try using download-artifact
|
||||
- Download all artifacts?
|
||||
- Use newer download version
|
||||
- Build artifact before upload
|
||||
- Change link to WIP builds in README
|
||||
- Use commit SHA as body of rolling releases
|
||||
- Don't omit body when setting body
|
||||
- Remove unnecessary empty section
|
||||
- Unified tag for rolling release
|
||||
- Generate release notes automatically
|
||||
- Remove generation, just in case
|
||||
- Change link to WIP builds in README
|
||||
- Show hashes in readonly data
|
||||
- Update to BinaryObjectScanner 3.1.0
|
||||
- Add Mattel HyperScan detection
|
||||
- Pull PS3 Disc Key from redump (Deterous)
|
||||
|
||||
### 3.1.1 (2024-02-20)
|
||||
|
||||
- Remove .NET 6 from auto-builds
|
||||
- Make Redumper the default for new users
|
||||
- Fix DIC log parsing for SS version (Deterous)
|
||||
- Write outputs with UTF-8
|
||||
- Add funworld Photo Play detection
|
||||
- Fix Aaru drive parameter generation
|
||||
- Limit DVD protection outputs
|
||||
- Add a GUI for PS3 IRD Creation (Deterous)
|
||||
- Update LibIRD, disable UI elements when creating IRD (Deterous)
|
||||
|
||||
### 3.1.0 (2024-02-06)
|
||||
|
||||
- Update RedumpLib
|
||||
@@ -17,8 +133,9 @@
|
||||
- Prevent crashing on invalid parameters (Deterous)
|
||||
- Detect CDTV discs (Deterous)
|
||||
- Differentiate CD32 from CDTV (Deterous)
|
||||
- Skip warning line in Redumper log
|
||||
- Normalise Disc Titles in Submission Info (Deterous)
|
||||
- Skip warning line in Redumper log
|
||||
- Add a GUI for MPF.Check (Deterous)
|
||||
- Fix information pulling for CleanRip and UIC
|
||||
- Add UMD handling for the disc info window
|
||||
- Detect Photo CD
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
|
||||
<OutputType>Exe</OutputType>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<VersionPrefix>3.1.0</VersionPrefix>
|
||||
<VersionPrefix>3.1.6</VersionPrefix>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Title>MPF Check</Title>
|
||||
@@ -31,10 +32,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BinaryObjectScanner" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="3.0.2" GeneratePathProperty="true">
|
||||
<PackageReference Include="BinaryObjectScanner" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="3.1.8" GeneratePathProperty="true">
|
||||
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="1.3.2" />
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="1.3.6" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -101,6 +101,7 @@ namespace MPF.Core.Converters
|
||||
|
||||
InternalProgram.CleanRip => "CleanRip",
|
||||
InternalProgram.DCDumper => "DCDumper",
|
||||
InternalProgram.PS3CFW => "PS3 CFW",
|
||||
InternalProgram.UmdImageCreator => "UmdImageCreator",
|
||||
|
||||
#endregion
|
||||
@@ -110,7 +111,44 @@ namespace MPF.Core.Converters
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// Get the string representation of the RedumperReadMethod enum values
|
||||
/// </summary>
|
||||
/// <param name="method">RedumperReadMethod value to convert</param>
|
||||
/// <returns>String representing the value, if possible</returns>
|
||||
public static string LongName(this RedumperReadMethod? method)
|
||||
{
|
||||
return (method) switch
|
||||
{
|
||||
RedumperReadMethod.D8 => "D8",
|
||||
RedumperReadMethod.BE => "BE",
|
||||
RedumperReadMethod.BE_CDDA => "BE_CDDA",
|
||||
|
||||
RedumperReadMethod.NONE => "Default",
|
||||
_ => "Unknown",
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string representation of the RedumperSectorOrder enum values
|
||||
/// </summary>
|
||||
/// <param name="order">RedumperSectorOrder value to convert</param>
|
||||
/// <returns>String representing the value, if possible</returns>
|
||||
public static string LongName(this RedumperSectorOrder? order)
|
||||
{
|
||||
return (order) switch
|
||||
{
|
||||
RedumperSectorOrder.DATA_C2_SUB => "DATA_C2_SUB",
|
||||
RedumperSectorOrder.DATA_SUB_C2 => "DATA_SUB_C2",
|
||||
RedumperSectorOrder.DATA_SUB => "DATA_SUB",
|
||||
RedumperSectorOrder.DATA_C2 => "DATA_C2",
|
||||
|
||||
RedumperSectorOrder.NONE => "Default",
|
||||
_ => "Unknown",
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Convert From String
|
||||
|
||||
@@ -141,6 +179,11 @@ namespace MPF.Core.Converters
|
||||
"dc"
|
||||
or "dcd"
|
||||
or "dcdumper" => InternalProgram.DCDumper,
|
||||
"ps3cfw"
|
||||
or "ps3"
|
||||
or "getkey"
|
||||
or "managunz"
|
||||
or "multiman" => InternalProgram.PS3CFW,
|
||||
"uic"
|
||||
or "umd"
|
||||
or "umdcreator"
|
||||
@@ -293,6 +336,56 @@ namespace MPF.Core.Converters
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the RedumperReadMethod enum value for a given string
|
||||
/// </summary>
|
||||
/// <param name="method">String value to convert</param>
|
||||
/// <returns>RedumperReadMethod represented by the string, if possible</returns>
|
||||
public static RedumperReadMethod ToRedumperReadMethod(string? method)
|
||||
{
|
||||
return (method?.ToLowerInvariant()) switch
|
||||
{
|
||||
"d8" => RedumperReadMethod.D8,
|
||||
"be" => RedumperReadMethod.BE,
|
||||
"be_cdda"
|
||||
or "be cdda"
|
||||
or "be-cdda"
|
||||
or "becdda" => RedumperReadMethod.BE_CDDA,
|
||||
|
||||
_ => RedumperReadMethod.NONE,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the RedumperSectorOrder enum value for a given string
|
||||
/// </summary>
|
||||
/// <param name="order">String value to convert</param>
|
||||
/// <returns>RedumperSectorOrder represented by the string, if possible</returns>
|
||||
public static RedumperSectorOrder ToRedumperSectorOrder(string? order)
|
||||
{
|
||||
return (order?.ToLowerInvariant()) switch
|
||||
{
|
||||
"data_c2_sub"
|
||||
or "data c2 sub"
|
||||
or "data-c2-sub"
|
||||
or "datac2sub" => RedumperSectorOrder.DATA_C2_SUB,
|
||||
"data_sub_c2"
|
||||
or "data sub c2"
|
||||
or "data-sub-c2"
|
||||
or "datasubc2" => RedumperSectorOrder.DATA_SUB_C2,
|
||||
"data_sub"
|
||||
or "data sub"
|
||||
or "data-sub"
|
||||
or "datasub" => RedumperSectorOrder.DATA_SUB,
|
||||
"data_c2"
|
||||
or "data c2"
|
||||
or "data-c2"
|
||||
or "datac2" => RedumperSectorOrder.DATA_C2,
|
||||
|
||||
_ => RedumperSectorOrder.NONE,
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace MPF.Core.Data
|
||||
InfoTool.GetPlayStationExecutableInfo(this.Name, out string? serial, out _, out _);
|
||||
volumeLabel = serial ?? "track";
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
volumeLabel = "track";
|
||||
break;
|
||||
@@ -282,6 +282,23 @@ namespace MPF.Core.Data
|
||||
return systemFromLabel;
|
||||
|
||||
// Get a list of files for quicker checking
|
||||
#region Arcade
|
||||
|
||||
// funworld Photo Play
|
||||
if (File.Exists(Path.Combine(this.Name, "PP.INF"))
|
||||
&& Directory.Exists(Path.Combine(this.Name, "PPINC")))
|
||||
{
|
||||
return RedumpSystem.funworldPhotoPlay;
|
||||
}
|
||||
|
||||
// Konami Python 2
|
||||
if (Directory.Exists(Path.Combine(this.Name, "PY2.D")))
|
||||
{
|
||||
return RedumpSystem.KonamiPython2;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Consoles
|
||||
|
||||
// Bandai Playdia Quick Interactive System
|
||||
@@ -320,6 +337,12 @@ namespace MPF.Core.Data
|
||||
return RedumpSystem.CommodoreAmigaCD32;
|
||||
}
|
||||
|
||||
// Mattel HyperScan -- TODO: May need case-insensitivity added
|
||||
if (File.Exists(Path.Combine(this.Name, "hyper.exe")))
|
||||
{
|
||||
return RedumpSystem.MattelHyperScan;
|
||||
}
|
||||
|
||||
// Mattel Fisher-Price iXL
|
||||
#if NET20 || NET35
|
||||
if (File.Exists(Path.Combine(Path.Combine(this.Name, "iXL"), "iXLUpdater.exe")))
|
||||
@@ -346,17 +369,43 @@ namespace MPF.Core.Data
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Microsoft Xbox One
|
||||
// Microsoft Xbox One and Series X
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(this.Name, "MSXC"))
|
||||
#if NET20 || NET35
|
||||
&& Directory.GetFiles(Path.Combine(this.Name, "MSXC")).Any())
|
||||
#else
|
||||
&& Directory.EnumerateFiles(Path.Combine(this.Name, "MSXC")).Any())
|
||||
#endif
|
||||
if (Directory.Exists(Path.Combine(this.Name, "MSXC")))
|
||||
{
|
||||
return RedumpSystem.MicrosoftXboxOne;
|
||||
try
|
||||
{
|
||||
#if NET20 || NET35
|
||||
string catalogjs = Path.Combine(this.Name, Path.Combine("MSXC", Path.Combine("Metadata", "catalog.js")));
|
||||
#else
|
||||
string catalogjs = Path.Combine(this.Name, "MSXC", "Metadata", "catalog.js");
|
||||
#endif
|
||||
if (!File.Exists(catalogjs))
|
||||
return RedumpSystem.MicrosoftXboxOne;
|
||||
|
||||
SabreTools.Models.Xbox.Catalog? catalog = SabreTools.Serialization.Deserializers.Catalog.DeserializeFile(catalogjs);
|
||||
if (catalog != null && catalog.Version != null && catalog.Packages != null)
|
||||
{
|
||||
if (!double.TryParse(catalog.Version, out double version))
|
||||
return RedumpSystem.MicrosoftXboxOne;
|
||||
|
||||
if (version < 4)
|
||||
return RedumpSystem.MicrosoftXboxOne;
|
||||
|
||||
foreach (var package in catalog.Packages)
|
||||
{
|
||||
if (package.Generation != "9")
|
||||
return RedumpSystem.MicrosoftXboxOne;
|
||||
}
|
||||
|
||||
return RedumpSystem.MicrosoftXboxSeriesXS;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return RedumpSystem.MicrosoftXboxOne;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
@@ -439,7 +488,7 @@ namespace MPF.Core.Data
|
||||
return RedumpSystem.VTechVFlashVSmilePro;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Computers
|
||||
|
||||
@@ -530,7 +579,7 @@ namespace MPF.Core.Data
|
||||
}
|
||||
catch { }
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
// Default return
|
||||
return defaultValue;
|
||||
@@ -596,7 +645,7 @@ namespace MPF.Core.Data
|
||||
this.PopulateFromDriveInfo(driveInfo);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
|
||||
@@ -46,9 +46,35 @@
|
||||
// Verification support only
|
||||
CleanRip,
|
||||
DCDumper,
|
||||
PS3CFW,
|
||||
UmdImageCreator,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drive read method option
|
||||
/// </summary>
|
||||
public enum RedumperReadMethod
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
BE,
|
||||
D8,
|
||||
BE_CDDA,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drive sector order option
|
||||
/// </summary>
|
||||
public enum RedumperSectorOrder
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
DATA_C2_SUB,
|
||||
DATA_SUB_C2,
|
||||
DATA_SUB,
|
||||
DATA_C2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log level for output
|
||||
/// </summary>
|
||||
|
||||
@@ -56,9 +56,9 @@ namespace MPF.Core.Data
|
||||
{
|
||||
get
|
||||
{
|
||||
var valueString = GetStringSetting(Settings, "InternalProgram", InternalProgram.DiscImageCreator.ToString());
|
||||
var valueString = GetStringSetting(Settings, "InternalProgram", InternalProgram.Redumper.ToString());
|
||||
var valueEnum = EnumConverter.ToInternalProgram(valueString);
|
||||
return valueEnum == InternalProgram.NONE ? InternalProgram.DiscImageCreator : valueEnum;
|
||||
return valueEnum == InternalProgram.NONE ? InternalProgram.Redumper : valueEnum;
|
||||
}
|
||||
set
|
||||
{
|
||||
@@ -326,12 +326,12 @@ namespace MPF.Core.Data
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable BE reading by default with Redumper
|
||||
/// Enable options incompatible with redump submissions
|
||||
/// </summary>
|
||||
public bool RedumperUseBEReading
|
||||
public bool RedumperNonRedumpMode
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "RedumperUseBEReading", false); }
|
||||
set { Settings["RedumperUseBEReading"] = value.ToString(); }
|
||||
get { return GetBooleanSetting(Settings, "RedumperNonRedumpMode", false); }
|
||||
set { Settings["RedumperNonRedumpMode"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -343,6 +343,38 @@ namespace MPF.Core.Data
|
||||
set { Settings["RedumperUseGenericDriveType"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected default redumper read method
|
||||
/// </summary>
|
||||
public RedumperReadMethod RedumperReadMethod
|
||||
{
|
||||
get
|
||||
{
|
||||
var valueString = GetStringSetting(Settings, "RedumperReadMethod", RedumperReadMethod.NONE.ToString());
|
||||
return EnumConverter.ToRedumperReadMethod(valueString);
|
||||
}
|
||||
set
|
||||
{
|
||||
Settings["RedumperReadMethod"] = value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected default redumper sector order
|
||||
/// </summary>
|
||||
public RedumperSectorOrder RedumperSectorOrder
|
||||
{
|
||||
get
|
||||
{
|
||||
var valueString = GetStringSetting(Settings, "RedumperSectorOrder", RedumperSectorOrder.NONE.ToString());
|
||||
return EnumConverter.ToRedumperSectorOrder(valueString);
|
||||
}
|
||||
set
|
||||
{
|
||||
Settings["RedumperSectorOrder"] = value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default number of rereads
|
||||
/// </summary>
|
||||
@@ -500,6 +532,15 @@ namespace MPF.Core.Data
|
||||
set { Settings["DeleteUnnecessaryFiles"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a PS3 IRD file after dumping PS3 BD-ROM discs
|
||||
/// </summary>
|
||||
public bool CreateIRDAfterDumping
|
||||
{
|
||||
get { return GetBooleanSetting(Settings, "CreateIRDAfterDumping", false); }
|
||||
set { Settings["CreateIRDAfterDumping"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Skip Options
|
||||
|
||||
@@ -148,10 +148,14 @@ namespace MPF.Core
|
||||
// Verification support only
|
||||
InternalProgram.CleanRip => new Modules.CleanRip.Parameters(parameters) { ExecutablePath = null },
|
||||
InternalProgram.DCDumper => null, // TODO: Create correct parameter type when supported
|
||||
InternalProgram.PS3CFW => new Modules.PS3CFW.Parameters(parameters) { ExecutablePath = null },
|
||||
InternalProgram.UmdImageCreator => new Modules.UmdImageCreator.Parameters(parameters) { ExecutablePath = null },
|
||||
|
||||
// If no dumping program found, set to null
|
||||
InternalProgram.NONE => null,
|
||||
|
||||
// This should never happen, but it needs a fallback
|
||||
_ => new Modules.DiscImageCreator.Parameters(parameters) { ExecutablePath = Options.DiscImageCreatorPath },
|
||||
_ => new Modules.Redumper.Parameters(parameters) { ExecutablePath = Options.RedumperPath },
|
||||
};
|
||||
|
||||
// Set system and type
|
||||
@@ -183,12 +187,15 @@ namespace MPF.Core
|
||||
InternalProgram.DiscImageCreator => new Modules.DiscImageCreator.Parameters(System, Type, Drive.Name, OutputPath, driveSpeed, Options),
|
||||
InternalProgram.Redumper => new Modules.Redumper.Parameters(System, Type, Drive.Name, OutputPath, driveSpeed, Options),
|
||||
|
||||
// If no dumping program found, set to null
|
||||
InternalProgram.NONE => null,
|
||||
|
||||
// This should never happen, but it needs a fallback
|
||||
_ => new Modules.DiscImageCreator.Parameters(System, Type, Drive.Name, OutputPath, driveSpeed, Options),
|
||||
_ => new Modules.Redumper.Parameters(System, Type, Drive.Name, OutputPath, driveSpeed, Options),
|
||||
};
|
||||
|
||||
// Generate and return the param string
|
||||
return Parameters.GenerateParameters();
|
||||
return Parameters?.GenerateParameters();
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -281,6 +288,9 @@ namespace MPF.Core
|
||||
Func<SubmissionInfo?, (bool?, SubmissionInfo?)>? processUserInfo = null,
|
||||
SubmissionInfo? seedInfo = null)
|
||||
{
|
||||
if (Parameters == null)
|
||||
return Result.Failure("Error! Current configuration is not supported!");
|
||||
|
||||
resultProgress?.Report(Result.Success("Gathering submission information... please wait!"));
|
||||
|
||||
// Get the output directory and filename separately
|
||||
@@ -353,9 +363,9 @@ namespace MPF.Core
|
||||
resultProgress?.Report(Result.Success("Formatting information..."));
|
||||
(var formattedValues, var formatResult) = Formatter.FormatOutputData(submissionInfo, Options.EnableRedumpCompatibility);
|
||||
if (formattedValues == null)
|
||||
resultProgress?.Report(Result.Success(formatResult));
|
||||
else
|
||||
resultProgress?.Report(Result.Failure(formatResult));
|
||||
else
|
||||
resultProgress?.Report(Result.Success(formatResult));
|
||||
|
||||
// Get the filename suffix for auto-generated files
|
||||
var filenameSuffix = Options.AddFilenameSuffix ? Path.GetFileNameWithoutExtension(outputFilename) : null;
|
||||
@@ -415,6 +425,17 @@ namespace MPF.Core
|
||||
resultProgress?.Report(Result.Failure(deleteResult));
|
||||
}
|
||||
|
||||
// Create PS3 IRD, if required
|
||||
if (Options.CreateIRDAfterDumping && System == RedumpSystem.SonyPlayStation3 && Type == MediaType.BluRay)
|
||||
{
|
||||
resultProgress?.Report(Result.Success("Creating IRD... please wait!"));
|
||||
(bool deleteSuccess, string deleteResult) = await InfoTool.WriteIRD(OutputPath, submissionInfo?.Extras?.DiscKey, submissionInfo?.Extras?.DiscID, submissionInfo?.Extras?.PIC, submissionInfo?.SizeAndChecksums?.Layerbreak, submissionInfo?.SizeAndChecksums?.CRC32);
|
||||
if (deleteSuccess)
|
||||
resultProgress?.Report(Result.Success(deleteResult));
|
||||
else
|
||||
resultProgress?.Report(Result.Failure(deleteResult));
|
||||
}
|
||||
|
||||
resultProgress?.Report(Result.Success("Submission information process complete!"));
|
||||
return Result.Success();
|
||||
}
|
||||
|
||||
@@ -1,350 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
#if NET6_0_OR_GREATER
|
||||
using System.IO.Hashing;
|
||||
#endif
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
using MPF.Core.Data;
|
||||
|
||||
namespace MPF.Core.Hashing
|
||||
{
|
||||
public sealed class Hasher : IDisposable
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Hash type associated with the current state
|
||||
/// </summary>
|
||||
#if NETFRAMEWORK || NETCOREAPP3_1
|
||||
public Hash HashType { get; private set; }
|
||||
#else
|
||||
public Hash HashType { get; init; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Current hash in bytes
|
||||
/// </summary>
|
||||
public byte[]? CurrentHashBytes
|
||||
{
|
||||
get
|
||||
{
|
||||
return (_hasher) switch
|
||||
{
|
||||
HashAlgorithm ha => ha.Hash,
|
||||
NonCryptographicHashAlgorithm ncha => ncha.GetCurrentHash().Reverse().ToArray(),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Current hash as a string
|
||||
/// </summary>
|
||||
public string? CurrentHashString => ByteArrayToString(CurrentHashBytes);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Internal hasher being used for processing
|
||||
/// </summary>
|
||||
/// <remarks>May be either a HashAlgorithm or NonCryptographicHashAlgorithm</remarks>
|
||||
private object? _hasher;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="hashType">Hash type to instantiate</param>
|
||||
public Hasher(Hash hashType)
|
||||
{
|
||||
this.HashType = hashType;
|
||||
GetHasher();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the correct hashing class based on the hash type
|
||||
/// </summary>
|
||||
private void GetHasher()
|
||||
{
|
||||
_hasher = HashType switch
|
||||
{
|
||||
Hash.CRC32 => new Crc32(),
|
||||
#if NET6_0_OR_GREATER
|
||||
Hash.CRC64 => new Crc64(),
|
||||
#endif
|
||||
Hash.MD5 => MD5.Create(),
|
||||
Hash.SHA1 => SHA1.Create(),
|
||||
Hash.SHA256 => SHA256.Create(),
|
||||
Hash.SHA384 => SHA384.Create(),
|
||||
Hash.SHA512 => SHA512.Create(),
|
||||
#if NET6_0_OR_GREATER
|
||||
Hash.XxHash32 => new XxHash32(),
|
||||
Hash.XxHash64 => new XxHash64(),
|
||||
#endif
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
if (_hasher is IDisposable disposable)
|
||||
disposable.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static Hashing
|
||||
|
||||
/// <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>
|
||||
public static bool GetFileHashes(string filename, out long size, out string? crc32, out string? md5, out string? sha1)
|
||||
{
|
||||
// Set all initial values
|
||||
crc32 = null; md5 = null; sha1 = null;
|
||||
|
||||
// Get all file hashes
|
||||
var fileHashes = GetFileHashes(filename, out size);
|
||||
if (fileHashes == null)
|
||||
return false;
|
||||
|
||||
// Assign the file hashes and return
|
||||
crc32 = fileHashes[Hash.CRC32];
|
||||
md5 = fileHashes[Hash.MD5];
|
||||
sha1 = fileHashes[Hash.SHA1];
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input file path
|
||||
/// </summary>
|
||||
/// <param name="filename">Path to the input file</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<Hash, string?>? GetFileHashes(string filename, out long size)
|
||||
{
|
||||
// If the file doesn't exist, we can't do anything
|
||||
if (!File.Exists(filename))
|
||||
{
|
||||
size = -1;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Set the file size
|
||||
size = new FileInfo(filename).Length;
|
||||
|
||||
// Open the input file
|
||||
var input = File.OpenRead(filename);
|
||||
|
||||
// Return the hashes from the stream
|
||||
return GetStreamHashes(input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<Hash, string?>? GetStreamHashes(Stream input)
|
||||
{
|
||||
// Create the output dictionary
|
||||
var hashDict = new Dictionary<Hash, string?>();
|
||||
|
||||
try
|
||||
{
|
||||
// Get a list of hashers to run over the buffer
|
||||
var hashers = new Dictionary<Hash, Hasher>
|
||||
{
|
||||
{ Hash.CRC32, new Hasher(Hash.CRC32) },
|
||||
#if NET6_0_OR_GREATER
|
||||
{ Hash.CRC64, new Hasher(Hash.CRC64) },
|
||||
#endif
|
||||
{ Hash.MD5, new Hasher(Hash.MD5) },
|
||||
{ Hash.SHA1, new Hasher(Hash.SHA1) },
|
||||
{ Hash.SHA256, new Hasher(Hash.SHA256) },
|
||||
{ Hash.SHA384, new Hasher(Hash.SHA384) },
|
||||
{ Hash.SHA512, new Hasher(Hash.SHA512) },
|
||||
#if NET6_0_OR_GREATER
|
||||
{ Hash.XxHash32, new Hasher(Hash.XxHash32) },
|
||||
{ Hash.XxHash64, new Hasher(Hash.XxHash64) },
|
||||
#endif
|
||||
};
|
||||
|
||||
// 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 = input.Length;
|
||||
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;
|
||||
|
||||
#if NET20 || NET35
|
||||
// Run hashers sequentially on each chunk
|
||||
foreach (var h in hashers)
|
||||
{
|
||||
h.Value.Process(buffer, current);
|
||||
}
|
||||
#else
|
||||
// Run hashers in parallel on each chunk
|
||||
Parallel.ForEach(hashers, h => h.Value.Process(buffer, current));
|
||||
#endif
|
||||
|
||||
// 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();
|
||||
#if NET20 || NET35
|
||||
foreach (var h in hashers)
|
||||
{
|
||||
h.Value.Terminate();
|
||||
}
|
||||
#else
|
||||
Parallel.ForEach(hashers, h => h.Value.Terminate());
|
||||
#endif
|
||||
|
||||
// Get the results
|
||||
hashDict[Hash.CRC32] = hashers[Hash.CRC32].CurrentHashString;
|
||||
#if NET6_0_OR_GREATER
|
||||
hashDict[Hash.CRC64] = hashers[Hash.CRC64].CurrentHashString;
|
||||
#endif
|
||||
hashDict[Hash.MD5] = hashers[Hash.MD5].CurrentHashString;
|
||||
hashDict[Hash.SHA1] = hashers[Hash.SHA1].CurrentHashString;
|
||||
hashDict[Hash.SHA256] = hashers[Hash.SHA256].CurrentHashString;
|
||||
hashDict[Hash.SHA384] = hashers[Hash.SHA384].CurrentHashString;
|
||||
hashDict[Hash.SHA512] = hashers[Hash.SHA512].CurrentHashString;
|
||||
#if NET6_0_OR_GREATER
|
||||
hashDict[Hash.XxHash32] = hashers[Hash.XxHash32].CurrentHashString;
|
||||
hashDict[Hash.XxHash64] = hashers[Hash.XxHash64].CurrentHashString;
|
||||
#endif
|
||||
|
||||
// Dispose of the hashers
|
||||
loadBuffer.Dispose();
|
||||
foreach (var hasher in hashers.Values)
|
||||
{
|
||||
hasher.Dispose();
|
||||
}
|
||||
|
||||
return hashDict;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
input.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Hashing
|
||||
|
||||
/// <summary>
|
||||
/// Process a buffer of some length with the internal hash algorithm
|
||||
/// </summary>
|
||||
public void Process(byte[] buffer, int size)
|
||||
{
|
||||
switch (_hasher)
|
||||
{
|
||||
case HashAlgorithm ha:
|
||||
ha.TransformBlock(buffer, 0, size, null, 0);
|
||||
break;
|
||||
case NonCryptographicHashAlgorithm ncha:
|
||||
#if NET20 || NET35 || NET40
|
||||
byte[] bufferSpan = new byte[size];
|
||||
Array.Copy(buffer, bufferSpan, size);
|
||||
#else
|
||||
var bufferSpan = new ReadOnlySpan<byte>(buffer, 0, size);
|
||||
#endif
|
||||
ncha.Append(bufferSpan);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalize the internal hash algorigthm
|
||||
/// </summary>
|
||||
/// <remarks>NonCryptographicHashAlgorithm implementations do not need finalization</remarks>
|
||||
public void Terminate()
|
||||
{
|
||||
byte[] emptyBuffer = [];
|
||||
switch (_hasher)
|
||||
{
|
||||
case HashAlgorithm ha:
|
||||
ha.TransformFinalBlock(emptyBuffer, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
#if NETFRAMEWORK || NETCOREAPP3_1 || NET5_0
|
||||
|
||||
/*
|
||||
|
||||
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
|
||||
namespace MPF.Core.Hashing
|
||||
{
|
||||
/// <summary>
|
||||
/// Shell class to trick older versions into using CRC-32 properly
|
||||
/// </summary>
|
||||
internal abstract class NonCryptographicHashAlgorithm
|
||||
{
|
||||
#if NET20 || NET35 || NET40
|
||||
/// <summary>
|
||||
/// When overridden in a derived class, appends the contents of source to
|
||||
/// the data already processed for the current hash computation.
|
||||
/// </summary>
|
||||
/// <param name="source">The data to process.</param>
|
||||
public abstract void Append(byte[] source);
|
||||
#else
|
||||
/// <summary>
|
||||
/// When overridden in a derived class, appends the contents of source to
|
||||
/// the data already processed for the current hash computation.
|
||||
/// </summary>
|
||||
/// <param name="source">The data to process.</param>
|
||||
public abstract void Append(ReadOnlySpan<byte> source);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current computed hash value without modifying accumulated state.
|
||||
/// </summary>
|
||||
/// <returns>The hash value for the data already provided.</returns>
|
||||
public abstract byte[] GetCurrentHash();
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// Some changes have been made to this code to make it more similar to the System.IO.Hashing implementations
|
||||
/// </remarks>
|
||||
internal class Crc32 : NonCryptographicHashAlgorithm, IDisposable
|
||||
{
|
||||
private const uint kCrcPoly = 0xEDB88320;
|
||||
private const uint kInitial = 0xFFFFFFFF;
|
||||
private const int CRC_NUM_TABLES = 8;
|
||||
private static readonly uint[] Table;
|
||||
|
||||
static Crc32()
|
||||
{
|
||||
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 Crc32()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset CRC
|
||||
/// </summary>
|
||||
public void Init()
|
||||
{
|
||||
UnsignedValue = kInitial;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] GetCurrentHash()
|
||||
{
|
||||
return BitConverter.GetBytes(~UnsignedValue);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET20 || NET35 || NET40
|
||||
public override void Append(byte[] source)
|
||||
{
|
||||
Update(source, 0, source.Length);
|
||||
}
|
||||
#else
|
||||
public override void Append(ReadOnlySpan<byte> source)
|
||||
{
|
||||
byte[] sourceBytes = source.ToArray();
|
||||
Update(sourceBytes, 0, sourceBytes.Length);
|
||||
}
|
||||
#endif
|
||||
|
||||
private void Update(byte[] data, int offset, int count)
|
||||
{
|
||||
_ = new ArraySegment<byte>(data, offset, count); // check arguments
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var table = 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;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
UnsignedValue = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,81 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
//namespace Compress.ThreadReaders
|
||||
namespace MPF.Core.Hashing
|
||||
{
|
||||
public sealed 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
|
||||
{
|
||||
if (_buffer != null)
|
||||
SizeRead = _ds.Read(_buffer, 0, _size);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorState = true;
|
||||
}
|
||||
_outEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
public void Trigger(byte[] buffer, int size)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_size = size;
|
||||
_waitEvent.Set();
|
||||
}
|
||||
|
||||
public void Wait()
|
||||
{
|
||||
_outEvent.WaitOne();
|
||||
}
|
||||
|
||||
public void Finish()
|
||||
{
|
||||
_finished = true;
|
||||
_waitEvent.Set();
|
||||
_tWorker.Join();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,7 +168,7 @@ namespace MPF.Core
|
||||
{
|
||||
try
|
||||
{
|
||||
return new SabreTools.Serialization.Files.PIC().Deserialize(pic);
|
||||
return SabreTools.Serialization.Deserializers.PIC.DeserializeFile(pic);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -1304,7 +1304,7 @@ namespace MPF.Core
|
||||
else if (!string.IsNullOrEmpty(outputDirectory) && !string.IsNullOrEmpty(filenameSuffix))
|
||||
path = Path.Combine(outputDirectory, $"!submissionInfo_{filenameSuffix}.txt");
|
||||
|
||||
using var sw = new StreamWriter(File.Open(path, FileMode.Create, FileAccess.Write));
|
||||
using var sw = new StreamWriter(File.Open(path, FileMode.Create, FileAccess.Write), Encoding.UTF8);
|
||||
foreach (string line in lines)
|
||||
{
|
||||
sw.WriteLine(line);
|
||||
@@ -1411,7 +1411,7 @@ namespace MPF.Core
|
||||
else if (!string.IsNullOrEmpty(outputDirectory) && !string.IsNullOrEmpty(filenameSuffix))
|
||||
path = Path.Combine(outputDirectory, $"!protectionInfo{filenameSuffix}.txt");
|
||||
|
||||
using var sw = new StreamWriter(File.Open(path, FileMode.Create, FileAccess.Write));
|
||||
using var sw = new StreamWriter(File.Open(path, FileMode.Create, FileAccess.Write), Encoding.UTF8);
|
||||
|
||||
List<string> sortedKeys = [.. info.CopyProtection.FullProtections.Keys.OrderBy(k => k)];
|
||||
foreach (string key in sortedKeys)
|
||||
@@ -1495,6 +1495,61 @@ namespace MPF.Core
|
||||
return files;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an IRD and write it to the specified output directory with optional filename suffix
|
||||
/// </summary>
|
||||
/// <param name="outputDirectory">Output folder to write to</param>
|
||||
/// <param name="filenameSuffix">Optional suffix to append to the filename</param>
|
||||
/// <param name="outputFilename">Output filename to use as the base path</param>
|
||||
/// <returns>True on success, false on error</returns>
|
||||
public static async Task<(bool, string)> WriteIRD(string isoPath, string? discKeyString, string? discIDString, string? picString, long? layerbreak, string? crc32)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Output IRD file path
|
||||
string irdPath = Path.ChangeExtension(isoPath, ".ird");
|
||||
|
||||
// Parse disc key from submission info (Required)
|
||||
byte[]? discKey = Tools.ParseHexKey(discKeyString);
|
||||
if (discKey == null)
|
||||
return (false, "Failed to create IRD: No key provided");
|
||||
|
||||
// Parse Disc ID from submission info (Optional)
|
||||
byte[]? discID = Tools.ParseDiscID(discIDString);
|
||||
|
||||
// Parse PIC from submission info (Optional)
|
||||
byte[]? pic = Tools.ParsePIC(picString);
|
||||
|
||||
// Parse CRC32 strings into ISO hash for Unique ID field (Optional)
|
||||
uint? uid = Tools.ParseCRC32(crc32);
|
||||
|
||||
// Ensure layerbreak value is valid (Optional)
|
||||
layerbreak = Tools.ParseLayerbreak(layerbreak);
|
||||
|
||||
// Create Redump-style reproducible IRD
|
||||
#if NET40
|
||||
LibIRD.ReIRD ird = await Task.Factory.StartNew(() =>
|
||||
#else
|
||||
LibIRD.ReIRD ird = await Task.Run(() =>
|
||||
#endif
|
||||
new LibIRD.ReIRD(isoPath, discKey, layerbreak, uid));
|
||||
if (pic != null)
|
||||
ird.PIC = pic;
|
||||
if (discID != null && ird.DiscID[15] != 0x00)
|
||||
ird.DiscID = discID;
|
||||
|
||||
// Write IRD to file
|
||||
ird.Write(irdPath);
|
||||
|
||||
return (true, "IRD created!");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// We don't care what the error is
|
||||
return (false, "Failed to create IRD");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Normalization
|
||||
@@ -1877,14 +1932,29 @@ namespace MPF.Core
|
||||
for (int i = 1; i < splitTitle.Length; i++)
|
||||
{
|
||||
string segment = splitTitle[i];
|
||||
if (segment.EndsWith(":") || segment.EndsWith("-"))
|
||||
if (!itemInserted && segment == ":")
|
||||
{
|
||||
itemInserted = true;
|
||||
newTitleBuilder.Append($"{segment}, {firstItem}");
|
||||
newTitleBuilder.Append($", {firstItem} :");
|
||||
}
|
||||
else if (!itemInserted && segment == "-")
|
||||
{
|
||||
itemInserted = true;
|
||||
newTitleBuilder.Append($", {firstItem} -");
|
||||
}
|
||||
else if (!itemInserted && segment.EndsWith(":"))
|
||||
{
|
||||
itemInserted = true;
|
||||
newTitleBuilder.Append($" {segment.Substring(0, segment.Length - 1)}, {firstItem}:");
|
||||
}
|
||||
else if (!itemInserted && segment.EndsWith("-"))
|
||||
{
|
||||
itemInserted = true;
|
||||
newTitleBuilder.Append($" {segment.Substring(0, segment.Length - 1)}, {firstItem}-");
|
||||
}
|
||||
else
|
||||
{
|
||||
newTitleBuilder.Append($"{segment} ");
|
||||
newTitleBuilder.Append($" {segment}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<VersionPrefix>3.1.0</VersionPrefix>
|
||||
<VersionPrefix>3.1.6</VersionPrefix>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
@@ -45,19 +46,18 @@
|
||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="$(TargetFramework.StartsWith(`net6`)) OR $(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`))">
|
||||
<PackageReference Include="System.IO.Hashing" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BinaryObjectScanner" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="3.0.2" GeneratePathProperty="true">
|
||||
<PackageReference Include="BinaryObjectScanner" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="3.1.8" GeneratePathProperty="true">
|
||||
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="LibIRD" Version="0.9.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="psxt001z.Library" Version="0.21.0-beta3" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.3.0" />
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="1.3.2" />
|
||||
<PackageReference Include="SabreTools.Serialization" Version="1.3.1" />
|
||||
<PackageReference Include="psxt001z.Library" Version="0.21.0-rc1" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="1.2.0" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.4.5" />
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="1.3.6" />
|
||||
<PackageReference Include="SabreTools.Serialization" Version="1.6.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1067,10 +1067,8 @@ namespace MPF.Core.Modules.Aaru
|
||||
// Handle filenames based on command, if necessary
|
||||
switch (BaseCommand)
|
||||
{
|
||||
// Input value only
|
||||
// Input value only (file path)
|
||||
case CommandStrings.ArchivePrefixLong + " " + CommandStrings.ArchiveInfo:
|
||||
case CommandStrings.DevicePrefixLong + " " + CommandStrings.DeviceInfo:
|
||||
case CommandStrings.DevicePrefixLong + " " + CommandStrings.DeviceReport:
|
||||
case CommandStrings.FilesystemPrefixLong + " " + CommandStrings.FilesystemInfo:
|
||||
case CommandStrings.FilesystemPrefixLong + " " + CommandStrings.FilesystemListLong:
|
||||
case CommandStrings.ImagePrefixLong + " " + CommandStrings.ImageChecksumLong:
|
||||
@@ -1080,12 +1078,21 @@ namespace MPF.Core.Modules.Aaru
|
||||
case CommandStrings.ImagePrefixLong + " " + CommandStrings.ImageInfo:
|
||||
case CommandStrings.ImagePrefixLong + " " + CommandStrings.ImagePrint:
|
||||
case CommandStrings.ImagePrefixLong + " " + CommandStrings.ImageVerify:
|
||||
if (string.IsNullOrEmpty(InputValue))
|
||||
return null;
|
||||
|
||||
parameters.Add($"\"{InputValue}\"");
|
||||
break;
|
||||
|
||||
// Input value only (device path)
|
||||
case CommandStrings.DevicePrefixLong + " " + CommandStrings.DeviceInfo:
|
||||
case CommandStrings.DevicePrefixLong + " " + CommandStrings.DeviceReport:
|
||||
case CommandStrings.MediaPrefixLong + " " + CommandStrings.MediaInfo:
|
||||
case CommandStrings.MediaPrefixLong + " " + CommandStrings.MediaScan:
|
||||
if (string.IsNullOrEmpty(InputValue))
|
||||
return null;
|
||||
|
||||
parameters.Add($"\"{InputValue}\"");
|
||||
parameters.Add(InputValue!.TrimEnd('\\'));
|
||||
break;
|
||||
|
||||
// Two input values
|
||||
@@ -1097,10 +1104,9 @@ namespace MPF.Core.Modules.Aaru
|
||||
parameters.Add($"\"{Input2Value}\"");
|
||||
break;
|
||||
|
||||
// Input and Output value
|
||||
// Input and Output value (file path)
|
||||
case CommandStrings.FilesystemPrefixLong + " " + CommandStrings.FilesystemExtract:
|
||||
case CommandStrings.ImagePrefixLong + " " + CommandStrings.ImageConvert:
|
||||
case CommandStrings.MediaPrefixLong + " " + CommandStrings.MediaDump:
|
||||
if (string.IsNullOrEmpty(InputValue) || string.IsNullOrEmpty(OutputValue))
|
||||
return null;
|
||||
|
||||
@@ -1108,6 +1114,15 @@ namespace MPF.Core.Modules.Aaru
|
||||
parameters.Add($"\"{OutputValue}\"");
|
||||
break;
|
||||
|
||||
// Input and Output value (device path)
|
||||
case CommandStrings.MediaPrefixLong + " " + CommandStrings.MediaDump:
|
||||
if (string.IsNullOrEmpty(InputValue) || string.IsNullOrEmpty(OutputValue))
|
||||
return null;
|
||||
|
||||
parameters.Add(InputValue!.TrimEnd('\\'));
|
||||
parameters.Add($"\"{OutputValue}\"");
|
||||
break;
|
||||
|
||||
// Remote host value only
|
||||
case CommandStrings.DevicePrefixLong + " " + CommandStrings.DeviceList:
|
||||
case CommandStrings.Remote:
|
||||
@@ -2471,7 +2486,7 @@ namespace MPF.Core.Modules.Aaru
|
||||
cueSheet.Files = [.. cueFiles];
|
||||
if (cueSheet != null && cueSheet != default)
|
||||
{
|
||||
var ms = new SabreTools.Serialization.Streams.CueSheet().Serialize(cueSheet);
|
||||
var ms = SabreTools.Serialization.Serializers.CueSheet.SerializeStream(cueSheet);
|
||||
if (ms == null)
|
||||
return null;
|
||||
|
||||
|
||||
@@ -994,11 +994,9 @@ namespace MPF.Core.Modules
|
||||
if (!IsFlagSupported(longFlagString))
|
||||
return null;
|
||||
|
||||
string[] commandParts = parts[i].Split('=');
|
||||
if (commandParts.Length != 2)
|
||||
return null;
|
||||
int loc = parts[i].IndexOf('=');
|
||||
|
||||
string valuePart = commandParts[1];
|
||||
string valuePart = parts[i].Substring(loc + 1);
|
||||
|
||||
this[longFlagString] = true;
|
||||
return valuePart.Trim('"');
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Data;
|
||||
using SabreTools.Hashing;
|
||||
using SabreTools.RedumpLib;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
@@ -72,8 +73,9 @@ namespace MPF.Core.Modules.CleanRip
|
||||
// Get the Datafile information
|
||||
var datafile = GenerateCleanripDatafile(basePath + ".iso", basePath + "-dumpinfo.txt");
|
||||
|
||||
// Fill in the hash data
|
||||
info.TracksAndWriteOffsets!.ClrMameProData = InfoTool.GenerateDatfile(datafile);
|
||||
// ClrMameProData format is only for CDs
|
||||
if (this.Type == MediaType.CDROM)
|
||||
info.TracksAndWriteOffsets!.ClrMameProData = InfoTool.GenerateDatfile(datafile);
|
||||
|
||||
// Get the individual hash data, as per internal
|
||||
if (InfoTool.GetISOHashValues(datafile, out long size, out var crc32, out var md5, out var sha1))
|
||||
@@ -182,6 +184,17 @@ namespace MPF.Core.Modules.CleanRip
|
||||
sha1 = line.Substring(7);
|
||||
}
|
||||
|
||||
// Ensure all checksums were found in log
|
||||
if (crc == string.Empty || md5 == string.Empty || sha1 == string.Empty)
|
||||
{
|
||||
if (HashTool.GetStandardHashes(iso, out long isoSize, out string? isoCRC, out string? isoMD5, out string? isoSHA1))
|
||||
{
|
||||
crc = isoCRC ?? crc;
|
||||
md5 = isoMD5 ?? md5;
|
||||
sha1 = isoSHA1 ?? sha1;
|
||||
}
|
||||
}
|
||||
|
||||
return new Datafile
|
||||
{
|
||||
Games =
|
||||
@@ -531,13 +531,13 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
}
|
||||
|
||||
// Needed for some odd copy protections
|
||||
info.CopyProtection!.Protection = GetDVDProtection($"{basePath}_CSSKey.txt", $"{basePath}_disc.txt") ?? string.Empty;
|
||||
info.CopyProtection!.Protection = GetDVDProtection($"{basePath}_CSSKey.txt", $"{basePath}_disc.txt", false) ?? string.Empty;
|
||||
|
||||
break;
|
||||
|
||||
case RedumpSystem.DVDAudio:
|
||||
case RedumpSystem.DVDVideo:
|
||||
info.CopyProtection!.Protection = GetDVDProtection($"{basePath}_CSSKey.txt", $"{basePath}_disc.txt") ?? string.Empty;
|
||||
info.CopyProtection!.Protection = GetDVDProtection($"{basePath}_CSSKey.txt", $"{basePath}_disc.txt", true) ?? string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.KonamiPython2:
|
||||
@@ -2820,8 +2820,9 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
/// </summary>
|
||||
/// <param name="cssKey">_CSSKey.txt file location</param>
|
||||
/// <param name="disc">_disc.txt file location</param>
|
||||
/// <param name="includeAlways">Indicates whether region and protection type are always included</param>
|
||||
/// <returns>Formatted string representing the DVD protection, null on error</returns>
|
||||
private static string? GetDVDProtection(string cssKey, string disc)
|
||||
private static string? GetDVDProtection(string cssKey, string disc, bool includeAlways)
|
||||
{
|
||||
// If one of the files doesn't exist, we can't get info from them
|
||||
if (!File.Exists(disc))
|
||||
@@ -2903,6 +2904,15 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
catch { }
|
||||
}
|
||||
|
||||
// Filter out if we're not always including information
|
||||
if (!includeAlways)
|
||||
{
|
||||
if (region == "1 2 3 4 5 6 7 8")
|
||||
region = null;
|
||||
if (copyrightProtectionSystemType == "No")
|
||||
copyrightProtectionSystemType = null;
|
||||
}
|
||||
|
||||
// Now we format everything we can
|
||||
string protection = string.Empty;
|
||||
if (!string.IsNullOrEmpty(region))
|
||||
@@ -3720,6 +3730,9 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
// This flag is needed because recent versions of DIC include security data twice
|
||||
bool foundSecuritySectors = false;
|
||||
|
||||
// SS version for all Kreon DIC dumps is v1
|
||||
ssver = "01";
|
||||
|
||||
try
|
||||
{
|
||||
using var sr = File.OpenText(disc);
|
||||
@@ -3729,11 +3742,13 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
if (line == null)
|
||||
break;
|
||||
|
||||
// Security Sector version
|
||||
// XGD version (1 = Xbox, 2 = Xbox360)
|
||||
/*
|
||||
if (line.StartsWith("Version of challenge table"))
|
||||
{
|
||||
ssver = line.Split(' ')[4]; // "Version of challenge table: <VER>"
|
||||
xgdver = line.Split(' ')[4]; // "Version of challenge table: <VER>"
|
||||
}
|
||||
*/
|
||||
|
||||
// Security Sector ranges
|
||||
else if (line.StartsWith("Number of security sector ranges:") && !foundSecuritySectors)
|
||||
@@ -3808,6 +3823,9 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
// This flag is needed because recent versions of DIC include security data twice
|
||||
bool foundSecuritySectors = false;
|
||||
|
||||
// SS version for all Kreon DIC dumps is v1
|
||||
ssver = "01";
|
||||
|
||||
try
|
||||
{
|
||||
using var sr = File.OpenText(disc);
|
||||
@@ -3817,11 +3835,13 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
if (line == null)
|
||||
break;
|
||||
|
||||
// Security Sector version
|
||||
// XGD version (1 = Xbox, 2 = Xbox360)
|
||||
/*
|
||||
if (line.StartsWith("Version of challenge table"))
|
||||
{
|
||||
ssver = line.Split(' ')[4]; // "Version of challenge table: <VER>"
|
||||
xgdver = line.Split(' ')[4]; // "Version of challenge table: <VER>"
|
||||
}
|
||||
*/
|
||||
|
||||
// Security Sector ranges
|
||||
else if (line.StartsWith("Number of security sector ranges:") && !foundSecuritySectors)
|
||||
|
||||
293
MPF.Core/Modules/PS3CFW/Parameters.cs
Normal file
293
MPF.Core/Modules/PS3CFW/Parameters.cs
Normal file
@@ -0,0 +1,293 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Data;
|
||||
using SabreTools.Hashing;
|
||||
using SabreTools.RedumpLib;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Modules.PS3CFW
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic set of PlayStation 3 Custom Firmware parameters
|
||||
/// </summary>
|
||||
public class Parameters : BaseParameters
|
||||
{
|
||||
#region Metadata
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override InternalProgram InternalProgram => InternalProgram.PS3CFW;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(string? parameters) : base(parameters) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(RedumpSystem? system, MediaType? type, string? drivePath, string filename, int? driveSpeed, Options options)
|
||||
: base(system, type, drivePath, filename, driveSpeed, options)
|
||||
{
|
||||
}
|
||||
|
||||
#region BaseParameters Implementations
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override (bool, List<string>) CheckAllOutputFilesExist(string basePath, bool preCheck)
|
||||
{
|
||||
var missingFiles = new List<string>();
|
||||
|
||||
if (this.Type != MediaType.BluRay || this.System != RedumpSystem.SonyPlayStation3)
|
||||
{
|
||||
missingFiles.Add("Media and system combination not supported for PS3 CFW");
|
||||
}
|
||||
else
|
||||
{
|
||||
string? getKeyBasePath = GetCFWBasePath(basePath);
|
||||
if (!File.Exists($"{getKeyBasePath}.getkey.log"))
|
||||
missingFiles.Add($"{getKeyBasePath}.getkey.log");
|
||||
if (!File.Exists($"{getKeyBasePath}.disc.pic"))
|
||||
missingFiles.Add($"{getKeyBasePath}.disc.pic");
|
||||
}
|
||||
|
||||
return (missingFiles.Count == 0, missingFiles);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive? drive, bool includeArtifacts)
|
||||
{
|
||||
// Ensure that required sections exist
|
||||
info = Builder.EnsureAllSections(info);
|
||||
|
||||
info.DumpingInfo!.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
|
||||
|
||||
// Get the Datafile information
|
||||
Datafile? datafile = GeneratePS3CFWDatafile(basePath + ".iso");
|
||||
|
||||
// Fill in the hash data
|
||||
info.TracksAndWriteOffsets!.ClrMameProData = InfoTool.GenerateDatfile(datafile);
|
||||
|
||||
// Get the individual hash data, as per internal
|
||||
if (InfoTool.GetISOHashValues(datafile, out long size, out var crc32, out var md5, out var sha1))
|
||||
{
|
||||
info.SizeAndChecksums!.Size = size;
|
||||
info.SizeAndChecksums.CRC32 = crc32;
|
||||
info.SizeAndChecksums.MD5 = md5;
|
||||
info.SizeAndChecksums.SHA1 = sha1;
|
||||
}
|
||||
|
||||
// Get the PVD from the ISO
|
||||
if (GetPVD(basePath + ".iso", out string? pvd))
|
||||
info.Extras!.PVD = pvd;
|
||||
|
||||
// Try get the serial, version, and firmware version if a drive is provided
|
||||
if (drive != null)
|
||||
{
|
||||
info.VersionAndEditions!.Version = InfoTool.GetPlayStation3Version(drive?.Name) ?? string.Empty;
|
||||
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = InfoTool.GetPlayStation3Serial(drive?.Name) ?? string.Empty;
|
||||
string? firmwareVersion = InfoTool.GetPlayStation3FirmwareVersion(drive?.Name);
|
||||
if (firmwareVersion != null)
|
||||
info.CommonDiscInfo!.ContentsSpecialFields![SiteCode.Patches] = $"PS3 Firmware {firmwareVersion}";
|
||||
}
|
||||
|
||||
// Try to determine the name of the GetKey file(s)
|
||||
string? getKeyBasePath = GetCFWBasePath(basePath);
|
||||
|
||||
// If GenerateSubmissionInfo is run, .getkey.log existence should already be checked
|
||||
if (!File.Exists(getKeyBasePath + ".getkey.log"))
|
||||
return;
|
||||
|
||||
// Get dumping date from GetKey log date
|
||||
info.DumpingInfo.DumpingDate = InfoTool.GetFileModifiedDate(getKeyBasePath + ".getkey.log")?.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
// TODO: Put info about abnormal PIC info beyond 132 bytes in comments?
|
||||
if (File.Exists(getKeyBasePath + ".disc.pic"))
|
||||
info.Extras!.PIC = GetPIC(getKeyBasePath + ".disc.pic", 264);
|
||||
|
||||
// Parse Disc Key, Disc ID, and PIC from the .getkey.log file
|
||||
if (Utilities.Tools.ParseGetKeyLog(getKeyBasePath + ".getkey.log", out string? key, out string? id, out string? pic))
|
||||
{
|
||||
if (key != null)
|
||||
info.Extras!.DiscKey = key.ToUpperInvariant();
|
||||
if (id != null)
|
||||
info.Extras!.DiscID = id.ToUpperInvariant().Substring(0, 24) + "XXXXXXXX";
|
||||
if (string.IsNullOrEmpty(info.Extras!.PIC) && !string.IsNullOrEmpty(pic))
|
||||
{
|
||||
pic = Regex.Replace(pic, ".{32}", "$0\n");
|
||||
info.Extras.PIC = pic;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in any artifacts that exist, Base64-encoded, if we need to
|
||||
if (includeArtifacts)
|
||||
{
|
||||
info.Artifacts ??= [];
|
||||
|
||||
if (File.Exists(getKeyBasePath + ".disc.pic"))
|
||||
info.Artifacts["discpic"] = GetBase64(GetFullFile(getKeyBasePath + ".disc.pic", binary: true)) ?? string.Empty;
|
||||
if (File.Exists(getKeyBasePath + ".getkey.log"))
|
||||
info.Artifacts["getkeylog"] = GetBase64(GetFullFile(getKeyBasePath + ".getkey.log")) ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<string> GetLogFilePaths(string basePath)
|
||||
{
|
||||
var logFiles = new List<string>();
|
||||
string? getKeyBasePath = GetCFWBasePath(basePath);
|
||||
|
||||
if (this.System != RedumpSystem.SonyPlayStation3)
|
||||
return logFiles;
|
||||
|
||||
switch (this.Type)
|
||||
{
|
||||
case MediaType.BluRay:
|
||||
if (File.Exists($"{getKeyBasePath}.getkey.log"))
|
||||
logFiles.Add($"{getKeyBasePath}.getkey.log");
|
||||
if (File.Exists($"{getKeyBasePath}.disc.pic"))
|
||||
logFiles.Add($"{getKeyBasePath}.disc.pic");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return logFiles;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Information Extraction Methods
|
||||
|
||||
/// <summary>
|
||||
/// Get a formatted datfile from the PS3 CFW output, if possible
|
||||
/// </summary>
|
||||
/// <param name="iso">Path to ISO file</param>
|
||||
/// <returns></returns>
|
||||
private static Datafile? GeneratePS3CFWDatafile(string iso)
|
||||
{
|
||||
// If the ISO file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(iso))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
if (HashTool.GetStandardHashes(iso, out long size, out string? crc, out string? md5, out string? sha1))
|
||||
{
|
||||
return new Datafile
|
||||
{
|
||||
Games = [new Game { Roms = [new Rom { Name = Path.GetFileName(iso), Size = size.ToString(), Crc = crc, Md5 = md5, Sha1 = sha1, }] }]
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the exception is right now
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Don't hardcode 0x8320 and move this function to BaseParameters
|
||||
/// <summary>
|
||||
/// Get a isobuster-formatted PVD from a PS3 ISO, if possible
|
||||
/// </summary>
|
||||
/// <param name="isoPath">Path to ISO file</param>
|
||||
/// <param name="pvd">Formatted PVD string, otherwise null</param>
|
||||
/// <returns>True if PVD was successfully parsed, otherwise false</returns>
|
||||
private static bool GetPVD(string isoPath, out string? pvd)
|
||||
{
|
||||
pvd = null;
|
||||
try
|
||||
{
|
||||
// Get PVD bytes from ISO file
|
||||
var buf = new byte[96];
|
||||
using (FileStream iso = File.OpenRead(isoPath))
|
||||
{
|
||||
iso.Seek(0x8320, SeekOrigin.Begin);
|
||||
|
||||
int offset = 0;
|
||||
while (offset < 96)
|
||||
{
|
||||
int read = iso.Read(buf, offset, buf.Length - offset);
|
||||
if (read == 0)
|
||||
throw new EndOfStreamException();
|
||||
offset += read;
|
||||
}
|
||||
}
|
||||
|
||||
// Format PVD to isobuster standard
|
||||
char[] pvdCharArray = new char[96];
|
||||
for (int i = 0; i < 96; i++)
|
||||
{
|
||||
if (buf[i] >= 0x20 && buf[i] <= 0x7E)
|
||||
pvdCharArray[i] = (char)buf[i];
|
||||
else
|
||||
pvdCharArray[i] = '.';
|
||||
}
|
||||
string pvdASCII = new string(pvdCharArray, 0, 96);
|
||||
pvd = string.Empty;
|
||||
for (int i = 0; i < 96; i += 16)
|
||||
{
|
||||
pvd += $"{(0x0320+i):X4} : {buf[i]:X2} {buf[i+1]:X2} {buf[i+2]:X2} {buf[i+3]:X2} {buf[i+4]:X2} {buf[i+5]:X2} {buf[i+6]:X2} {buf[i+7]:X2} " +
|
||||
$"{buf[i+8]:X2} {buf[i+9]:X2} {buf[i+10]:X2} {buf[i+11]:X2} {buf[i+12]:X2} {buf[i+13]:X2} {buf[i+14]:X2} {buf[i+15]:X2} {pvdASCII.Substring(i, 16)}\n";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error is
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a formatted datfile from the PS3 CFW output, if possible
|
||||
/// </summary>
|
||||
/// <param name="iso">Path to ISO file</param>
|
||||
/// <returns>Formatted datfile, null if not valid</returns>
|
||||
private static string? GetPS3CFWDatfile(string iso)
|
||||
{
|
||||
// If the files don't exist, we can't get info from it
|
||||
if (!File.Exists(iso))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
if (HashTool.GetStandardHashes(iso, out long size, out string? crc, out string? md5, out string? sha1))
|
||||
return $"<rom name=\"{Path.GetFileName(iso)}\" size=\"{size}\" crc=\"{crc}\" md5=\"{md5}\" sha1=\"{sha1}\" />";
|
||||
return null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the exception is right now
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper Functions
|
||||
|
||||
/// <summary>
|
||||
/// Estimate the base filename of the .getkey.log file associated with the dump
|
||||
/// </summary>
|
||||
/// <param name="iso">Path to ISO file</param>
|
||||
/// <returns>Base filename, null if not found</returns>
|
||||
private string? GetCFWBasePath(string iso)
|
||||
{
|
||||
string? dir = Path.GetDirectoryName(iso);
|
||||
dir ??= ".";
|
||||
|
||||
string[] files = Directory.GetFiles(dir, "*.getkey.log");
|
||||
|
||||
if (files.Length != 1)
|
||||
return null;
|
||||
|
||||
return files[0].Substring(0, files[0].Length - 11);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -231,7 +231,7 @@ namespace MPF.Core.Modules.Redumper
|
||||
missingFiles.Add($"{basePath}.dat");
|
||||
if (!File.Exists($"{basePath}.manufacturer") && !File.Exists($"{basePath}.1.manufacturer") && !File.Exists($"{basePath}.2.manufacturer"))
|
||||
missingFiles.Add($"{basePath}.manufacturer");
|
||||
if (!File.Exists($"{basePath}.physical") && !File.Exists($"{basePath}.1.physical") && !File.Exists($"{basePath}.2.physical"))
|
||||
if (!File.Exists($"{basePath}.physical") && !File.Exists($"{basePath}.0.physical") && !File.Exists($"{basePath}.1.physical") && !File.Exists($"{basePath}.2.physical"))
|
||||
missingFiles.Add($"{basePath}.physical");
|
||||
if (!File.Exists($"{basePath}.state"))
|
||||
missingFiles.Add($"{basePath}.state");
|
||||
@@ -256,7 +256,7 @@ namespace MPF.Core.Modules.Redumper
|
||||
missingFiles.Add($"{basePath}.log");
|
||||
else if (GetDatfile($"{basePath}.log") == null)
|
||||
missingFiles.Add($"{basePath}.dat");
|
||||
if (!File.Exists($"{basePath}.physical") && !File.Exists($"{basePath}.1.physical") && !File.Exists($"{basePath}.2.physical"))
|
||||
if (!File.Exists($"{basePath}.physical") && !File.Exists($"{basePath}.0.physical") && !File.Exists($"{basePath}.1.physical") && !File.Exists($"{basePath}.2.physical"))
|
||||
missingFiles.Add($"{basePath}.physical");
|
||||
if (!File.Exists($"{basePath}.state"))
|
||||
missingFiles.Add($"{basePath}.state");
|
||||
@@ -320,8 +320,11 @@ namespace MPF.Core.Modules.Redumper
|
||||
info.TracksAndWriteOffsets.OtherWriteOffsets = cdWriteOffset;
|
||||
|
||||
// Attempt to get the error count
|
||||
long errorCount = GetErrorCount($"{basePath}.log");
|
||||
info.CommonDiscInfo.ErrorsCount = (errorCount == -1 ? "Error retrieving error count" : errorCount.ToString());
|
||||
if (GetErrorCount($"{basePath}.log", out long redumpErrors, out long c2Errors))
|
||||
{
|
||||
info.CommonDiscInfo.ErrorsCount = (redumpErrors == -1 ? "Error retrieving error count" : redumpErrors.ToString());
|
||||
info.DumpingInfo.C2ErrorsCount = (c2Errors == -1 ? "Error retrieving error count" : c2Errors.ToString());
|
||||
}
|
||||
|
||||
// Attempt to get multisession data
|
||||
string cdMultiSessionInfo = GetMultisessionInformation($"{basePath}.log") ?? string.Empty;
|
||||
@@ -385,9 +388,14 @@ namespace MPF.Core.Modules.Redumper
|
||||
break;
|
||||
}
|
||||
|
||||
info.Extras!.PIC = GetPIC($"{basePath}.physical", trimLength) ?? string.Empty;
|
||||
info.Extras!.PIC = GetPIC($"{basePath}.physical", trimLength)
|
||||
?? GetPIC($"{basePath}.0.physical", trimLength)
|
||||
?? GetPIC($"{basePath}.1.physical", trimLength)
|
||||
?? string.Empty;
|
||||
|
||||
var di = InfoTool.GetDiscInformation($"{basePath}.physical");
|
||||
var di = InfoTool.GetDiscInformation($"{basePath}.physical")
|
||||
?? InfoTool.GetDiscInformation($"{basePath}.0.physical")
|
||||
?? InfoTool.GetDiscInformation($"{basePath}.1.physical");
|
||||
info.SizeAndChecksums!.PICIdentifier = InfoTool.GetPICIdentifier(di);
|
||||
}
|
||||
|
||||
@@ -404,12 +412,12 @@ namespace MPF.Core.Modules.Redumper
|
||||
info.CopyProtection!.SecuROMData = GetSecuROMData($"{basePath}.log") ?? string.Empty;
|
||||
|
||||
// Needed for some odd copy protections
|
||||
info.CopyProtection!.Protection = GetDVDProtection($"{basePath}.log") ?? string.Empty;
|
||||
info.CopyProtection!.Protection = GetDVDProtection($"{basePath}.log", false) ?? string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.DVDAudio:
|
||||
case RedumpSystem.DVDVideo:
|
||||
info.CopyProtection!.Protection = GetDVDProtection($"{basePath}.log") ?? string.Empty;
|
||||
info.CopyProtection!.Protection = GetDVDProtection($"{basePath}.log", true) ?? string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.KonamiPython2:
|
||||
@@ -549,6 +557,8 @@ namespace MPF.Core.Modules.Redumper
|
||||
info.Artifacts["manufacturer2"] = GetBase64(GetFullFile($"{basePath}.2.manufacturer")) ?? string.Empty;
|
||||
if (File.Exists($"{basePath}.physical"))
|
||||
info.Artifacts["physical"] = GetBase64(GetFullFile($"{basePath}.physical")) ?? string.Empty;
|
||||
if (File.Exists($"{basePath}.0.physical"))
|
||||
info.Artifacts["physical0"] = GetBase64(GetFullFile($"{basePath}.0.physical")) ?? string.Empty;
|
||||
if (File.Exists($"{basePath}.1.physical"))
|
||||
info.Artifacts["physical1"] = GetBase64(GetFullFile($"{basePath}.1.physical")) ?? string.Empty;
|
||||
if (File.Exists($"{basePath}.2.physical"))
|
||||
@@ -918,7 +928,7 @@ namespace MPF.Core.Modules.Redumper
|
||||
logFiles.Add($"{basePath}.toc");
|
||||
|
||||
// Include .hash and .skeleton for all files in cuesheet
|
||||
var cueSheet = new SabreTools.Serialization.Files.CueSheet().Deserialize($"{basePath}.cue");
|
||||
var cueSheet = SabreTools.Serialization.Deserializers.CueSheet.DeserializeFile($"{basePath}.cue");
|
||||
string? baseDir = Path.GetDirectoryName(basePath);
|
||||
if (cueSheet?.Files != null && baseDir != null)
|
||||
{
|
||||
@@ -958,6 +968,8 @@ namespace MPF.Core.Modules.Redumper
|
||||
logFiles.Add($"{basePath}.2.manufacturer");
|
||||
if (File.Exists($"{basePath}.physical"))
|
||||
logFiles.Add($"{basePath}.physical");
|
||||
if (File.Exists($"{basePath}.0.physical"))
|
||||
logFiles.Add($"{basePath}.0.physical");
|
||||
if (File.Exists($"{basePath}.1.physical"))
|
||||
logFiles.Add($"{basePath}.1.physical");
|
||||
if (File.Exists($"{basePath}.2.physical"))
|
||||
@@ -976,6 +988,8 @@ namespace MPF.Core.Modules.Redumper
|
||||
logFiles.Add($"{basePath}.log");
|
||||
if (File.Exists($"{basePath}.physical"))
|
||||
logFiles.Add($"{basePath}.physical");
|
||||
if (File.Exists($"{basePath}.0.physical"))
|
||||
logFiles.Add($"{basePath}.0.physical");
|
||||
if (File.Exists($"{basePath}.1.physical"))
|
||||
logFiles.Add($"{basePath}.1.physical");
|
||||
if (File.Exists($"{basePath}.2.physical"))
|
||||
@@ -1084,15 +1098,20 @@ namespace MPF.Core.Modules.Redumper
|
||||
this[FlagStrings.Verbose] = options.RedumperEnableVerbose;
|
||||
if (options.RedumperEnableDebug)
|
||||
this[FlagStrings.Debug] = options.RedumperEnableDebug;
|
||||
if (options.RedumperUseBEReading)
|
||||
if (options.RedumperReadMethod != RedumperReadMethod.NONE)
|
||||
{
|
||||
this[FlagStrings.DriveReadMethod] = true;
|
||||
DriveReadMethodValue = "BE_CDDA";
|
||||
DriveReadMethodValue = options.RedumperReadMethod.ToString();
|
||||
}
|
||||
if (options.RedumperSectorOrder != RedumperSectorOrder.NONE)
|
||||
{
|
||||
this[FlagStrings.DriveSectorOrder] = true;
|
||||
DriveSectorOrderValue = options.RedumperSectorOrder.ToString();
|
||||
}
|
||||
if (options.RedumperUseGenericDriveType)
|
||||
{
|
||||
this[FlagStrings.DriveType] = true;
|
||||
DriveTypeValue = "Generic";
|
||||
DriveTypeValue = "GENERIC";
|
||||
}
|
||||
|
||||
// Set the output paths
|
||||
@@ -1429,25 +1448,31 @@ namespace MPF.Core.Modules.Redumper
|
||||
|
||||
try
|
||||
{
|
||||
// Fast forward to the dat line
|
||||
using var sr = File.OpenText(log);
|
||||
while (!sr.EndOfStream && sr.ReadLine()?.TrimStart()?.StartsWith("dat:") == false) ;
|
||||
if (sr.EndOfStream)
|
||||
return null;
|
||||
string? datString = null;
|
||||
|
||||
// Now that we're at the relevant entries, read each line in and concatenate
|
||||
var datString = string.Empty;
|
||||
var line = sr.ReadLine()?.Trim();
|
||||
while (line?.StartsWith("<rom") == true)
|
||||
// Find all occurrences of the hash information
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
datString += line + "\n";
|
||||
// Fast forward to the dat line
|
||||
while (!sr.EndOfStream && sr.ReadLine()?.TrimStart()?.StartsWith("dat:") == false) ;
|
||||
if (sr.EndOfStream)
|
||||
break;
|
||||
|
||||
line = sr.ReadLine()?.Trim();
|
||||
// Now that we're at the relevant entries, read each line in and concatenate
|
||||
datString = string.Empty;
|
||||
var line = sr.ReadLine()?.Trim();
|
||||
while (line?.StartsWith("<rom") == true)
|
||||
{
|
||||
datString += line + "\n";
|
||||
if (sr.EndOfStream)
|
||||
break;
|
||||
|
||||
line = sr.ReadLine()?.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
return datString.TrimEnd('\n');
|
||||
return datString?.TrimEnd('\n');
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -1557,8 +1582,9 @@ namespace MPF.Core.Modules.Redumper
|
||||
/// Get the DVD protection information, if possible
|
||||
/// </summary>
|
||||
/// <param name="log">Log file location</param>
|
||||
/// <param name="includeAlways">Indicates whether region and protection type are always included</param>
|
||||
/// <returns>Formatted string representing the DVD protection, null on error</returns>
|
||||
private static string? GetDVDProtection(string log)
|
||||
private static string? GetDVDProtection(string log, bool includeAlways)
|
||||
{
|
||||
// If one of the files doesn't exist, we can't get info from them
|
||||
if (!File.Exists(log))
|
||||
@@ -1628,6 +1654,15 @@ namespace MPF.Core.Modules.Redumper
|
||||
catch { }
|
||||
}
|
||||
|
||||
// Filter out if we're not always including information
|
||||
if (!includeAlways)
|
||||
{
|
||||
if (region == "1 2 3 4 5 6 7 8")
|
||||
region = null;
|
||||
if (copyrightProtectionSystemType == "No")
|
||||
copyrightProtectionSystemType = null;
|
||||
}
|
||||
|
||||
// Now we format everything we can
|
||||
string protection = string.Empty;
|
||||
if (!string.IsNullOrEmpty(region))
|
||||
@@ -1645,47 +1680,54 @@ namespace MPF.Core.Modules.Redumper
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the detected error count from the input files, if possible
|
||||
/// Get the detected error counts from the input files, if possible
|
||||
/// </summary>
|
||||
/// <param name="log">Log file location</param>
|
||||
/// <returns>Error count if possible, -1 on error</returns>
|
||||
public static long GetErrorCount(string log)
|
||||
/// <returns>True if error counts could be retrieved, false otherwise</returns>
|
||||
public static bool GetErrorCount(string log, out long redumpErrors, out long c2Errors)
|
||||
{
|
||||
// Set the default values for error counts
|
||||
redumpErrors = -1; c2Errors = -1;
|
||||
|
||||
// If the file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(log))
|
||||
return -1;
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
// Fast forward to the errors lines
|
||||
using var sr = File.OpenText(log);
|
||||
while (!sr.EndOfStream && sr.ReadLine()?.Trim()?.StartsWith("CD-ROM [") == false) ;
|
||||
if (sr.EndOfStream)
|
||||
return 0;
|
||||
|
||||
// Now that we're at the relevant lines, find the error count
|
||||
// Find the error counts
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
// Skip forward to the "REDUMP.ORG" line
|
||||
var line = string.Empty;
|
||||
while (!sr.EndOfStream && (line = sr.ReadLine()?.Trim())?.StartsWith("REDUMP.ORG errors") == false) ;
|
||||
if (string.IsNullOrEmpty(line))
|
||||
var line = sr.ReadLine()?.Trim();
|
||||
if (line == null)
|
||||
break;
|
||||
|
||||
// C2: <error count>
|
||||
if (line.StartsWith("C2:"))
|
||||
{
|
||||
string[] parts = line.Split(' ');
|
||||
if (!long.TryParse(parts[1], out c2Errors))
|
||||
c2Errors = -1;
|
||||
}
|
||||
|
||||
// REDUMP.ORG errors: <error count>
|
||||
string[] parts = line!.Split(' ');
|
||||
if (long.TryParse(parts[2], out long redump))
|
||||
return redump;
|
||||
else
|
||||
return -1;
|
||||
else if (line.StartsWith("REDUMP.ORG errors:"))
|
||||
{
|
||||
string[] parts = line!.Split(' ');
|
||||
if (!long.TryParse(parts[2], out redumpErrors))
|
||||
redumpErrors = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
// If the Redump error count is -1, then an issue occurred
|
||||
return redumpErrors != -1;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the exception is right now
|
||||
return -1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1716,7 +1758,7 @@ namespace MPF.Core.Modules.Redumper
|
||||
return line.Substring("EXE date: ".Length);
|
||||
}
|
||||
|
||||
line = sr.ReadLine();
|
||||
line = sr.ReadLine();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.Hashing;
|
||||
using SabreTools.Hashing;
|
||||
using SabreTools.RedumpLib;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace MPF.Core.Modules.UmdImageCreator
|
||||
case MediaType.UMD:
|
||||
info.Extras!.PVD = GetPVD(basePath + "_mainInfo.txt") ?? string.Empty;
|
||||
|
||||
if (Hasher.GetFileHashes(basePath + ".iso", out long filesize, out var crc32, out var md5, out var sha1))
|
||||
if (HashTool.GetStandardHashes(basePath + ".iso", out long filesize, out var crc32, out var md5, out var sha1))
|
||||
{
|
||||
// Get the Datafile information
|
||||
var datafile = new Datafile
|
||||
|
||||
@@ -89,6 +89,10 @@ namespace MPF.Core
|
||||
Version = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty,
|
||||
OtherEditions = options.AddPlaceholders ? "(VERIFY THIS) Original" : string.Empty,
|
||||
},
|
||||
DumpingInfo = new DumpingInfoSection()
|
||||
{
|
||||
FrontendVersion = Utilities.Tools.GetCurrentVersion(),
|
||||
},
|
||||
};
|
||||
|
||||
// Ensure that required sections exist
|
||||
@@ -279,6 +283,12 @@ namespace MPF.Core
|
||||
info.CopyProtection.FullProtections = fullProtections as Dictionary<string, List<string>?> ?? [];
|
||||
resultProgress?.Report(Result.Success("Copy protection scan complete!"));
|
||||
|
||||
if (system == RedumpSystem.EnhancedCD)
|
||||
info.CommonDiscInfo!.Category ??= DiscCategory.Audio;
|
||||
|
||||
if (system == RedumpSystem.SonyElectronicBook)
|
||||
info.CommonDiscInfo!.Category ??= DiscCategory.Multimedia;
|
||||
|
||||
break;
|
||||
|
||||
case RedumpSystem.AudioCD:
|
||||
@@ -288,68 +298,78 @@ namespace MPF.Core
|
||||
break;
|
||||
|
||||
case RedumpSystem.BandaiPlaydiaQuickInteractiveSystem:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? Region.Japan;
|
||||
info.CommonDiscInfo!.EXEDateBuildDate ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo.Region ??= info.CommonDiscInfo.Region ?? Region.Japan;
|
||||
break;
|
||||
|
||||
case RedumpSystem.BDVideo:
|
||||
info.CommonDiscInfo!.Category ??= DiscCategory.BonusDiscs;
|
||||
info.CopyProtection!.Protection = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
case RedumpSystem.DVDVideo:
|
||||
case RedumpSystem.HDDVDVideo:
|
||||
info.CommonDiscInfo!.Category ??= DiscCategory.Video;
|
||||
info.CopyProtection!.Protection ??= options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.CommodoreAmigaCD:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo!.EXEDateBuildDate ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.CommodoreAmigaCD32:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo!.EXEDateBuildDate ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo.Region ??= Region.Europe;
|
||||
break;
|
||||
|
||||
case RedumpSystem.CommodoreAmigaCDTV:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo!.EXEDateBuildDate ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo.Region ??= Region.Europe;
|
||||
break;
|
||||
|
||||
case RedumpSystem.DVDVideo:
|
||||
info.CommonDiscInfo!.Category ??= DiscCategory.BonusDiscs;
|
||||
break;
|
||||
|
||||
case RedumpSystem.FujitsuFMTownsseries:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? Region.Japan;
|
||||
info.CommonDiscInfo!.EXEDateBuildDate ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo.Region ??= Region.Japan;
|
||||
break;
|
||||
|
||||
case RedumpSystem.FujitsuFMTownsMarty:
|
||||
info.CommonDiscInfo!.Region ??= Region.Japan;
|
||||
break;
|
||||
|
||||
case RedumpSystem.HasbroVideoNow:
|
||||
case RedumpSystem.HasbroVideoNowColor:
|
||||
case RedumpSystem.HasbroVideoNowJr:
|
||||
case RedumpSystem.VideoCD:
|
||||
info.CommonDiscInfo!.Category ??= DiscCategory.Video;
|
||||
break;
|
||||
|
||||
case RedumpSystem.HasbroVideoNowXP:
|
||||
case RedumpSystem.PhotoCD:
|
||||
info.CommonDiscInfo!.Category ??= DiscCategory.Multimedia;
|
||||
break;
|
||||
|
||||
case RedumpSystem.IncredibleTechnologiesEagle:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo!.EXEDateBuildDate ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.KonamieAmusement:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo!.EXEDateBuildDate ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.KonamiFireBeat:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo!.EXEDateBuildDate ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.KonamiSystemGV:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo!.EXEDateBuildDate ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.KonamiSystem573:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo!.EXEDateBuildDate ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.KonamiTwinkle:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo!.EXEDateBuildDate ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.MattelHyperScan:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo!.EXEDateBuildDate ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.MicrosoftXboxOne:
|
||||
@@ -358,7 +378,7 @@ namespace MPF.Core
|
||||
string xboxOneMsxcPath = Path.Combine(drive.Name, "MSXC");
|
||||
if (drive != null && Directory.Exists(xboxOneMsxcPath))
|
||||
{
|
||||
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.Filename] = string.Join("\n",
|
||||
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.Filename] ??= string.Join("\n",
|
||||
Directory.GetFiles(xboxOneMsxcPath, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName).ToArray());
|
||||
}
|
||||
}
|
||||
@@ -371,7 +391,7 @@ namespace MPF.Core
|
||||
string xboxSeriesXMsxcPath = Path.Combine(drive.Name, "MSXC");
|
||||
if (drive != null && Directory.Exists(xboxSeriesXMsxcPath))
|
||||
{
|
||||
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.Filename] = string.Join("\n",
|
||||
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.Filename] ??= string.Join("\n",
|
||||
Directory.GetFiles(xboxSeriesXMsxcPath, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName).ToArray());
|
||||
}
|
||||
}
|
||||
@@ -379,7 +399,7 @@ namespace MPF.Core
|
||||
break;
|
||||
|
||||
case RedumpSystem.NamcoSegaNintendoTriforce:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo!.EXEDateBuildDate ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.NavisoftNaviken21:
|
||||
@@ -401,23 +421,23 @@ namespace MPF.Core
|
||||
break;
|
||||
|
||||
case RedumpSystem.SegaChihiro:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo!.EXEDateBuildDate ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.SegaDreamcast:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo!.EXEDateBuildDate ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.SegaNaomi:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo!.EXEDateBuildDate ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.SegaNaomi2:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo!.EXEDateBuildDate ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.SegaTitanVideo:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo!.EXEDateBuildDate ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.SharpX68000:
|
||||
@@ -425,7 +445,7 @@ namespace MPF.Core
|
||||
break;
|
||||
|
||||
case RedumpSystem.SNKNeoGeoCD:
|
||||
info.CommonDiscInfo!.EXEDateBuildDate = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.CommonDiscInfo!.EXEDateBuildDate ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.SonyPlayStation:
|
||||
@@ -448,20 +468,21 @@ namespace MPF.Core
|
||||
break;
|
||||
|
||||
case RedumpSystem.SonyPlayStation2:
|
||||
info.CommonDiscInfo!.LanguageSelection = [LanguageSelection.BiosSettings, LanguageSelection.LanguageSelector, LanguageSelection.OptionsMenu];
|
||||
info.CommonDiscInfo!.LanguageSelection ??= [];
|
||||
break;
|
||||
|
||||
case RedumpSystem.SonyPlayStation3:
|
||||
info.Extras!.DiscKey = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.Extras.DiscID = options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.Extras!.DiscKey ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
info.Extras.DiscID ??= options.AddPlaceholders ? Template.RequiredValue : string.Empty;
|
||||
break;
|
||||
|
||||
case RedumpSystem.TomyKissSite:
|
||||
info.CommonDiscInfo!.Category ??= DiscCategory.Video;
|
||||
info.CommonDiscInfo!.Region ??= Region.Japan;
|
||||
break;
|
||||
|
||||
case RedumpSystem.ZAPiTGamesGameWaveFamilyEntertainmentSystem:
|
||||
info.CopyProtection!.Protection = options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
info.CopyProtection!.Protection ??= options.AddPlaceholders ? Template.RequiredIfExistsValue : string.Empty;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -724,6 +745,9 @@ namespace MPF.Core
|
||||
volLabels.Add($"{label.Key} ({string.Join(", ", [.. label.Value])})");
|
||||
}
|
||||
|
||||
// Ensure that no labels are empty
|
||||
volLabels = volLabels.Where(l => !string.IsNullOrEmpty(l?.Trim())).ToList();
|
||||
|
||||
// Print each label separated by a comma and a space
|
||||
if (volLabels.Count == 0)
|
||||
return null;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BinaryObjectScanner;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.UI.ComboBoxItems;
|
||||
@@ -179,6 +180,20 @@ namespace MPF.Core.UI.ViewModels
|
||||
}
|
||||
private bool _checkDumpButtonEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the status of the cancel button
|
||||
/// </summary>
|
||||
public bool CancelButtonEnabled
|
||||
{
|
||||
get => _cancelButtonEnabled;
|
||||
set
|
||||
{
|
||||
_cancelButtonEnabled = value;
|
||||
TriggerPropertyChanged(nameof(CancelButtonEnabled));
|
||||
}
|
||||
}
|
||||
private bool _cancelButtonEnabled;
|
||||
|
||||
#endregion
|
||||
|
||||
#region List Properties
|
||||
@@ -243,6 +258,7 @@ namespace MPF.Core.UI.ViewModels
|
||||
MediaTypeComboBoxEnabled = true;
|
||||
DumpingProgramComboBoxEnabled = true;
|
||||
CheckDumpButtonEnabled = false;
|
||||
CancelButtonEnabled = true;
|
||||
|
||||
MediaTypes = [];
|
||||
Systems = RedumpSystemComboBoxItem.GenerateElements().ToList();
|
||||
@@ -310,6 +326,38 @@ namespace MPF.Core.UI.ViewModels
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI Control
|
||||
|
||||
/// <summary>
|
||||
/// Enables all UI elements that should be enabled
|
||||
/// </summary>
|
||||
private void EnableUIElements()
|
||||
{
|
||||
SystemTypeComboBoxEnabled = true;
|
||||
InputPathTextBoxEnabled = true;
|
||||
InputPathBrowseButtonEnabled = true;
|
||||
DumpingProgramComboBoxEnabled = true;
|
||||
PopulateMediaType();
|
||||
CheckDumpButtonEnabled = ShouldEnableCheckDumpButton();
|
||||
CancelButtonEnabled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables all UI elements
|
||||
/// </summary>
|
||||
private void DisableUIElements()
|
||||
{
|
||||
SystemTypeComboBoxEnabled = false;
|
||||
InputPathTextBoxEnabled = false;
|
||||
InputPathBrowseButtonEnabled = false;
|
||||
MediaTypeComboBoxEnabled = false;
|
||||
DumpingProgramComboBoxEnabled = false;
|
||||
CheckDumpButtonEnabled = false;
|
||||
CancelButtonEnabled = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Population
|
||||
|
||||
/// <summary>
|
||||
@@ -354,7 +402,7 @@ namespace MPF.Core.UI.ViewModels
|
||||
InternalProgram internalProgram = this.Options.InternalProgram;
|
||||
|
||||
// Create a static list of supported Check programs, not everything
|
||||
var internalPrograms = new List<InternalProgram> { InternalProgram.DiscImageCreator, InternalProgram.Aaru, InternalProgram.CleanRip, InternalProgram.Redumper, InternalProgram.UmdImageCreator };
|
||||
var internalPrograms = new List<InternalProgram> { InternalProgram.Redumper, InternalProgram.Aaru, InternalProgram.DiscImageCreator, InternalProgram.CleanRip, InternalProgram.PS3CFW, InternalProgram.UmdImageCreator };
|
||||
InternalPrograms = internalPrograms.Select(ip => new Element<InternalProgram>(ip)).ToList();
|
||||
|
||||
// Select the current default dumping program
|
||||
@@ -398,7 +446,7 @@ namespace MPF.Core.UI.ViewModels
|
||||
/// Performs MPF.Check functionality
|
||||
/// </summary>
|
||||
/// <returns>An error message if failed, otherwise string.Empty/null</returns>
|
||||
public string? CheckDump(Func<SubmissionInfo?, (bool?, SubmissionInfo?)> processUserInfo)
|
||||
public async Task<string?> CheckDump(Func<SubmissionInfo?, (bool?, SubmissionInfo?)> processUserInfo)
|
||||
{
|
||||
if (string.IsNullOrEmpty(InputPath))
|
||||
return "Invalid Input path";
|
||||
@@ -406,6 +454,11 @@ namespace MPF.Core.UI.ViewModels
|
||||
if (!File.Exists(this.InputPath!.Trim('"')))
|
||||
return "Input Path is not a valid file";
|
||||
|
||||
// Disable UI while Check is running
|
||||
DisableUIElements();
|
||||
bool cachedCanExecuteSelectionChanged = CanExecuteSelectionChanged;
|
||||
DisableEventHandlers();
|
||||
|
||||
// Populate an environment
|
||||
var env = new DumpEnvironment(Options, Path.GetFullPath(this.InputPath.Trim('"')), null, this.CurrentSystem, this.CurrentMediaType, this.CurrentProgram, parameters: null);
|
||||
|
||||
@@ -416,13 +469,12 @@ namespace MPF.Core.UI.ViewModels
|
||||
protectionProgress.ProgressChanged += ConsoleLogger.ProgressUpdated;
|
||||
|
||||
// Finally, attempt to do the output dance
|
||||
#if NET40
|
||||
var resultTask = env.VerifyAndSaveDumpOutput(resultProgress, protectionProgress);
|
||||
resultTask.Wait();
|
||||
var result = resultTask.Result;
|
||||
#else
|
||||
var result = env.VerifyAndSaveDumpOutput(resultProgress, protectionProgress, processUserInfo).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
#endif
|
||||
var result = await env.VerifyAndSaveDumpOutput(resultProgress, protectionProgress, processUserInfo);
|
||||
|
||||
// Reenable UI and event handlers, if necessary
|
||||
EnableUIElements();
|
||||
if (cachedCanExecuteSelectionChanged)
|
||||
EnableEventHandlers();
|
||||
|
||||
return result.Message;
|
||||
}
|
||||
|
||||
1069
MPF.Core/UI/ViewModels/CreateIRDViewModel.cs
Normal file
1069
MPF.Core/UI/ViewModels/CreateIRDViewModel.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -90,6 +90,20 @@ namespace MPF.Core.UI.ViewModels
|
||||
}
|
||||
private bool _checkDumpMenuItemEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the status of the create IRD menu item
|
||||
/// </summary>
|
||||
public bool CreateIRDMenuItemEnabled
|
||||
{
|
||||
get => _createIRDMenuItemEnabled;
|
||||
set
|
||||
{
|
||||
_createIRDMenuItemEnabled = value;
|
||||
TriggerPropertyChanged(nameof(CreateIRDMenuItemEnabled));
|
||||
}
|
||||
}
|
||||
private bool _createIRDMenuItemEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the status of the options menu item
|
||||
/// </summary>
|
||||
@@ -522,6 +536,7 @@ namespace MPF.Core.UI.ViewModels
|
||||
|
||||
OptionsMenuItemEnabled = true;
|
||||
CheckDumpMenuItemEnabled = true;
|
||||
CreateIRDMenuItemEnabled = true;
|
||||
SystemTypeComboBoxEnabled = true;
|
||||
MediaTypeComboBoxEnabled = true;
|
||||
OutputPathTextBoxEnabled = true;
|
||||
@@ -686,16 +701,23 @@ namespace MPF.Core.UI.ViewModels
|
||||
bool cachedCanExecuteSelectionChanged = CanExecuteSelectionChanged;
|
||||
DisableEventHandlers();
|
||||
|
||||
// Create a static list of supported programs, not everything
|
||||
InternalPrograms = Enum.GetValues(typeof(InternalProgram)).Cast<InternalProgram>().Where(ip => InternalProgramExists(ip)).Select(ip => new Element<InternalProgram>(ip)).ToList();
|
||||
|
||||
// Get the current internal program
|
||||
InternalProgram internalProgram = this.Options.InternalProgram;
|
||||
|
||||
// Create a static list of supported programs, not everything
|
||||
var internalPrograms = new List<InternalProgram> { InternalProgram.DiscImageCreator, InternalProgram.Aaru, InternalProgram.Redumper };
|
||||
InternalPrograms = internalPrograms.Select(ip => new Element<InternalProgram>(ip)).ToList();
|
||||
|
||||
// Select the current default dumping program
|
||||
int currentIndex = InternalPrograms.FindIndex(m => m == internalProgram);
|
||||
this.CurrentProgram = (currentIndex > -1 ? InternalPrograms[currentIndex].Value : InternalPrograms[0].Value);
|
||||
if (InternalPrograms.Count == 0)
|
||||
{
|
||||
// If no programs are found, default to InternalProgram.NONE
|
||||
this.CurrentProgram = InternalProgram.NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
int currentIndex = InternalPrograms.FindIndex(m => m == internalProgram);
|
||||
this.CurrentProgram = (currentIndex > -1 ? InternalPrograms[currentIndex].Value : InternalPrograms[0].Value);
|
||||
}
|
||||
|
||||
// Reenable event handlers, if necessary
|
||||
if (cachedCanExecuteSelectionChanged) EnableEventHandlers();
|
||||
@@ -1254,6 +1276,8 @@ namespace MPF.Core.UI.ViewModels
|
||||
public void DisableAllUIElements()
|
||||
{
|
||||
OptionsMenuItemEnabled = false;
|
||||
CheckDumpMenuItemEnabled = false;
|
||||
CreateIRDMenuItemEnabled = false;
|
||||
SystemTypeComboBoxEnabled = false;
|
||||
MediaTypeComboBoxEnabled = false;
|
||||
OutputPathTextBoxEnabled = false;
|
||||
@@ -1274,6 +1298,8 @@ namespace MPF.Core.UI.ViewModels
|
||||
public void EnableAllUIElements()
|
||||
{
|
||||
OptionsMenuItemEnabled = true;
|
||||
CheckDumpMenuItemEnabled = true;
|
||||
CreateIRDMenuItemEnabled = true;
|
||||
SystemTypeComboBoxEnabled = true;
|
||||
MediaTypeComboBoxEnabled = true;
|
||||
OutputPathTextBoxEnabled = true;
|
||||
@@ -1298,7 +1324,10 @@ namespace MPF.Core.UI.ViewModels
|
||||
|
||||
// Get the status to write out
|
||||
Result result = Tools.GetSupportStatus(_environment.System, _environment.Type);
|
||||
this.Status = result.Message;
|
||||
if (this.CurrentProgram == InternalProgram.NONE || _environment.Parameters == null)
|
||||
this.Status = "No dumping program found";
|
||||
else
|
||||
this.Status = result.Message;
|
||||
|
||||
// Enable or disable the button
|
||||
this.StartStopButtonEnabled = result && ShouldEnableDumpingButton();
|
||||
@@ -1655,8 +1684,8 @@ namespace MPF.Core.UI.ViewModels
|
||||
_environment.Drive?.RefreshDrive();
|
||||
|
||||
// Output to the label and log
|
||||
this.Status = "Starting dumping process... Please wait!";
|
||||
LogLn("Starting dumping process... Please wait!");
|
||||
this.Status = "Starting dumping process... please wait!";
|
||||
LogLn("Starting dumping process... please wait!");
|
||||
if (this.Options.ToolsInSeparateWindow)
|
||||
LogLn("Look for the separate command window for more details");
|
||||
else
|
||||
@@ -1749,6 +1778,9 @@ namespace MPF.Core.UI.ViewModels
|
||||
/// <returns>True if dumping should start, false otherwise</returns>
|
||||
private bool ValidateBeforeDumping()
|
||||
{
|
||||
if (Parameters == null)
|
||||
return false;
|
||||
|
||||
// Validate that we have an output path of any sort
|
||||
if (string.IsNullOrEmpty(_environment?.OutputPath))
|
||||
{
|
||||
@@ -1788,49 +1820,51 @@ namespace MPF.Core.UI.ViewModels
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If a complete dump exists from a different program
|
||||
InternalProgram? programFound = null;
|
||||
if (programFound == null && _environment.InternalProgram != InternalProgram.Aaru)
|
||||
else
|
||||
{
|
||||
Modules.Aaru.Parameters parameters = new("")
|
||||
// If a complete dump exists from a different program
|
||||
InternalProgram? programFound = null;
|
||||
if (programFound == null && _environment.InternalProgram != InternalProgram.Aaru)
|
||||
{
|
||||
Type = _environment.Type,
|
||||
System = _environment.System
|
||||
};
|
||||
(bool foundOtherFiles, _) = parameters.FoundAllFiles(outputDirectory, outputFilename, true);
|
||||
if (foundOtherFiles)
|
||||
programFound = InternalProgram.Aaru;
|
||||
}
|
||||
if (programFound == null && _environment.InternalProgram != InternalProgram.DiscImageCreator)
|
||||
{
|
||||
Modules.DiscImageCreator.Parameters parameters = new("")
|
||||
Modules.Aaru.Parameters parameters = new("")
|
||||
{
|
||||
Type = _environment.Type,
|
||||
System = _environment.System
|
||||
};
|
||||
(bool foundOtherFiles, _) = parameters.FoundAllFiles(outputDirectory, outputFilename, true);
|
||||
if (foundOtherFiles)
|
||||
programFound = InternalProgram.Aaru;
|
||||
}
|
||||
if (programFound == null && _environment.InternalProgram != InternalProgram.DiscImageCreator)
|
||||
{
|
||||
Type = _environment.Type,
|
||||
System = _environment.System
|
||||
};
|
||||
(bool foundOtherFiles, _) = parameters.FoundAllFiles(outputDirectory, outputFilename, true);
|
||||
if (foundOtherFiles)
|
||||
programFound = InternalProgram.DiscImageCreator;
|
||||
}
|
||||
if (programFound == null && _environment.InternalProgram != InternalProgram.Redumper)
|
||||
{
|
||||
Modules.Redumper.Parameters parameters = new("")
|
||||
Modules.DiscImageCreator.Parameters parameters = new("")
|
||||
{
|
||||
Type = _environment.Type,
|
||||
System = _environment.System
|
||||
};
|
||||
(bool foundOtherFiles, _) = parameters.FoundAllFiles(outputDirectory, outputFilename, true);
|
||||
if (foundOtherFiles)
|
||||
programFound = InternalProgram.DiscImageCreator;
|
||||
}
|
||||
if (programFound == null && _environment.InternalProgram != InternalProgram.Redumper)
|
||||
{
|
||||
Type = _environment.Type,
|
||||
System = _environment.System
|
||||
};
|
||||
(bool foundOtherFiles, _) = parameters.FoundAllFiles(outputDirectory, outputFilename, true);
|
||||
if (foundOtherFiles)
|
||||
programFound = InternalProgram.Redumper;
|
||||
}
|
||||
if (programFound != null && _displayUserMessage != null)
|
||||
{
|
||||
bool? mbresult = _displayUserMessage("Overwrite?", $"A complete dump from {programFound} already exists! Dumping here may cause issues. Are you sure you want to overwrite?", 2, true);
|
||||
if (mbresult != true)
|
||||
Modules.Redumper.Parameters parameters = new("")
|
||||
{
|
||||
Type = _environment.Type,
|
||||
System = _environment.System
|
||||
};
|
||||
(bool foundOtherFiles, _) = parameters.FoundAllFiles(outputDirectory, outputFilename, true);
|
||||
if (foundOtherFiles)
|
||||
programFound = InternalProgram.Redumper;
|
||||
}
|
||||
if (programFound != null && _displayUserMessage != null)
|
||||
{
|
||||
LogLn("Dumping aborted!");
|
||||
return false;
|
||||
bool? mbresult = _displayUserMessage("Overwrite?", $"A complete dump from {programFound} already exists! Dumping here may cause issues. Are you sure you want to overwrite?", 2, true);
|
||||
if (mbresult != true)
|
||||
{
|
||||
LogLn("Dumping aborted!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1857,7 +1891,30 @@ namespace MPF.Core.UI.ViewModels
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// Checks whether a internal program is found in its path
|
||||
/// </summary>
|
||||
/// <param name="program">Program to check for</param>
|
||||
/// <returns>True if the program is found, false otherwise</returns>
|
||||
private bool InternalProgramExists(InternalProgram program)
|
||||
{
|
||||
try
|
||||
{
|
||||
return program switch
|
||||
{
|
||||
InternalProgram.Redumper => File.Exists(this.Options.RedumperPath),
|
||||
InternalProgram.Aaru => File.Exists(this.Options.AaruPath),
|
||||
InternalProgram.DiscImageCreator => File.Exists(this.Options.DiscImageCreatorPath),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Progress Reporting
|
||||
|
||||
|
||||
@@ -51,6 +51,16 @@ namespace MPF.Core.UI.ViewModels
|
||||
/// </summary>
|
||||
public static List<Element<InternalProgram>> InternalPrograms => PopulateInternalPrograms();
|
||||
|
||||
/// <summary>
|
||||
/// Current list of supported Redumper read methods
|
||||
/// </summary>
|
||||
public static List<Element<RedumperReadMethod>> RedumperReadMethods => PopulateRedumperReadMethods();
|
||||
|
||||
/// <summary>
|
||||
/// Current list of supported Redumper sector orders
|
||||
/// </summary>
|
||||
public static List<Element<RedumperSectorOrder>> RedumperSectorOrders => PopulateRedumperSectorOrders();
|
||||
|
||||
/// <summary>
|
||||
/// Current list of supported system profiles
|
||||
/// </summary>
|
||||
@@ -77,14 +87,32 @@ namespace MPF.Core.UI.ViewModels
|
||||
#region Population
|
||||
|
||||
/// <summary>
|
||||
/// Get a complete list of supported internal programs
|
||||
/// Get a complete list of supported internal programs
|
||||
/// </summary>
|
||||
private static List<Element<InternalProgram>> PopulateInternalPrograms()
|
||||
{
|
||||
var internalPrograms = new List<InternalProgram> { InternalProgram.DiscImageCreator, InternalProgram.Aaru, InternalProgram.Redumper };
|
||||
var internalPrograms = new List<InternalProgram> { InternalProgram.Redumper, InternalProgram.DiscImageCreator, InternalProgram.Aaru };
|
||||
return internalPrograms.Select(ip => new Element<InternalProgram>(ip)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a complete list of supported redumper drive read methods
|
||||
/// </summary>
|
||||
private static List<Element<RedumperReadMethod>> PopulateRedumperReadMethods()
|
||||
{
|
||||
var readMethods = new List<RedumperReadMethod> { RedumperReadMethod.NONE, RedumperReadMethod.D8, RedumperReadMethod.BE, RedumperReadMethod.BE_CDDA };
|
||||
return readMethods.Select(rm => new Element<RedumperReadMethod>(rm)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a complete list of supported redumper drive sector orders
|
||||
/// </summary>
|
||||
private static List<Element<RedumperSectorOrder>> PopulateRedumperSectorOrders()
|
||||
{
|
||||
var sectorOrders = new List<RedumperSectorOrder> { RedumperSectorOrder.NONE, RedumperSectorOrder.DATA_C2_SUB, RedumperSectorOrder.DATA_SUB_C2, RedumperSectorOrder.DATA_SUB, RedumperSectorOrder.DATA_C2 };
|
||||
return sectorOrders.Select(so => new Element<RedumperSectorOrder>(so)).ToList();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI Commands
|
||||
@@ -107,6 +135,17 @@ namespace MPF.Core.UI.ViewModels
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset Redumper non-redump options (Read Method, Sector Order, Drive Type)
|
||||
/// </summary>
|
||||
public void NonRedumpModeUnChecked()
|
||||
{
|
||||
Options.RedumperReadMethod = RedumperReadMethod.NONE;
|
||||
Options.RedumperSectorOrder = RedumperSectorOrder.NONE;
|
||||
Options.RedumperUseGenericDriveType = false;
|
||||
TriggerPropertyChanged(nameof(Options));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Property Updates
|
||||
|
||||
@@ -272,7 +272,8 @@ namespace MPF.Core.Utilities
|
||||
}
|
||||
|
||||
var serializer = JsonSerializer.Create();
|
||||
var reader = new StreamReader(ConfigurationPath);
|
||||
var stream = File.Open(ConfigurationPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
var reader = new StreamReader(stream);
|
||||
var settings = serializer.Deserialize(reader, typeof(Dictionary<string, string?>)) as Dictionary<string, string?>;
|
||||
return new Options(settings);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using MPF.Core.Data;
|
||||
@@ -71,6 +72,36 @@ namespace MPF.Core.Utilities
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a hex string into a byte array
|
||||
/// </summary>
|
||||
/// <param name="hex">Hex string</param>
|
||||
/// <returns>Converted byte array, or null if invalid hex string</returns>
|
||||
public static byte[]? HexStringToByteArray(string? hexString)
|
||||
{
|
||||
// Valid hex string must be an even number of characters
|
||||
if (string.IsNullOrEmpty(hexString) || hexString!.Length % 2 == 1)
|
||||
return null;
|
||||
|
||||
// Convert ASCII to byte via lookup table
|
||||
int[] hexLookup = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F];
|
||||
byte[] byteArray = new byte[hexString.Length / 2];
|
||||
for (int i = 0; i < hexString.Length; i += 2)
|
||||
{
|
||||
// Convert next two chars to ASCII value relative to '0'
|
||||
int a = Char.ToUpper(hexString[i]) - '0';
|
||||
int b = Char.ToUpper(hexString[i + 1]) - '0';
|
||||
|
||||
// Ensure hex string only has '0' through '9' and 'A' through 'F' (case insensitive)
|
||||
if ((a < 0 || b < 0 || a > 22 || b > 22) || (a > 10 && a < 17) || (b > 10 && b < 17))
|
||||
return null;
|
||||
byteArray[i / 2] = (byte)(hexLookup[a] << 4 | hexLookup[b]);
|
||||
}
|
||||
|
||||
return byteArray;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Support
|
||||
@@ -261,5 +292,355 @@ namespace MPF.Core.Utilities
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PlayStation 3 specific tools
|
||||
|
||||
/// <summary>
|
||||
/// Validates a getkey log to check for presence of valid PS3 key
|
||||
/// </summary>
|
||||
/// <param name="logPath">Path to getkey log file</param>
|
||||
/// <param name="key">Output key string, null if not valid</param>
|
||||
/// <param name="id">Output disc ID string, null if not valid</param>
|
||||
/// <param name="pic">Output PIC string, null if not valid</param>
|
||||
/// <returns>True if path to log file contains valid key, false otherwise</returns>
|
||||
public static bool ParseGetKeyLog(string? logPath, out string? key, out string? id, out string? pic)
|
||||
{
|
||||
key = id = pic = null;
|
||||
|
||||
if (string.IsNullOrEmpty(logPath))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
if (!File.Exists(logPath))
|
||||
return false;
|
||||
|
||||
// Protect from attempting to read from really long files
|
||||
FileInfo logFile = new(logPath);
|
||||
if (logFile.Length > 65536)
|
||||
return false;
|
||||
|
||||
// Read from .getkey.log file
|
||||
using StreamReader sr = File.OpenText(logPath);
|
||||
|
||||
// Determine whether GetKey was successful
|
||||
string? line;
|
||||
while ((line = sr.ReadLine()) != null && line.Trim().StartsWith("get_dec_key succeeded!") == false) ;
|
||||
if (line == null)
|
||||
return false;
|
||||
|
||||
// Look for Disc Key in log
|
||||
while ((line = sr.ReadLine()) != null && line.Trim().StartsWith("disc_key = ") == false) ;
|
||||
|
||||
// If end of file reached, no key found
|
||||
if (line == null)
|
||||
return false;
|
||||
|
||||
// Get Disc Key from log
|
||||
string discKeyStr = line.Substring("disc_key = ".Length);
|
||||
|
||||
// Validate Disc Key from log
|
||||
if (discKeyStr.Length != 32)
|
||||
return false;
|
||||
|
||||
// Convert Disc Key to byte array
|
||||
key = discKeyStr;
|
||||
if (key == null)
|
||||
return false;
|
||||
|
||||
// Read Disc ID
|
||||
while ((line = sr.ReadLine()) != null && line.Trim().StartsWith("disc_id = ") == false) ;
|
||||
|
||||
// If end of file reached, no ID found
|
||||
if (line == null)
|
||||
return false;
|
||||
|
||||
// Get Disc ID from log
|
||||
string discIDStr = line.Substring("disc_id = ".Length);
|
||||
|
||||
// Validate Disc ID from log
|
||||
if (discIDStr.Length != 32)
|
||||
return false;
|
||||
|
||||
// Replace X's in Disc ID with 00000001
|
||||
discIDStr = discIDStr.Substring(0, 24) + "00000001";
|
||||
|
||||
// Convert Disc ID to byte array
|
||||
id = discIDStr;
|
||||
if (id == null)
|
||||
return false;
|
||||
|
||||
// Look for PIC in log
|
||||
while ((line = sr.ReadLine()) != null && line.Trim().StartsWith("PIC:") == false) ;
|
||||
|
||||
// If end of file reached, no PIC found
|
||||
if (line == null)
|
||||
return false;
|
||||
|
||||
// Get PIC from log
|
||||
string discPICStr = "";
|
||||
for (int i = 0; i < 9; i++)
|
||||
discPICStr += sr.ReadLine();
|
||||
if (discPICStr == null)
|
||||
return false;
|
||||
|
||||
// Validate PIC from log
|
||||
if (discPICStr.Length != 264)
|
||||
return false;
|
||||
|
||||
// Convert PIC to byte array
|
||||
pic = discPICStr;
|
||||
if (pic == null)
|
||||
return false;
|
||||
|
||||
// Double check for warnings in .getkey.log
|
||||
while ((line = sr.ReadLine()) != null)
|
||||
{
|
||||
string t = line.Trim();
|
||||
if (t.StartsWith("WARNING"))
|
||||
return false;
|
||||
else if (t.StartsWith("SUCCESS"))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We are not concerned with the error
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates a getkey log to check for presence of valid PS3 key
|
||||
/// </summary>
|
||||
/// <param name="logPath">Path to getkey log file</param>
|
||||
/// <param name="key">Output 16 byte disc key, null if not valid</param>
|
||||
/// <param name="id">Output 16 byte disc ID, null if not valid</param>
|
||||
/// <param name="pic">Output 230 byte PIC, null if not valid</param>
|
||||
/// <returns>True if path to log file contains valid key, false otherwise</returns>
|
||||
public static bool ParseGetKeyLog(string? logPath, out byte[]? key, out byte[]? id, out byte[]? pic)
|
||||
{
|
||||
key = id = pic = null;
|
||||
if (ParseGetKeyLog(logPath, out string? keyString, out string? idString, out string? picString))
|
||||
{
|
||||
if (string.IsNullOrEmpty(keyString) || string.IsNullOrEmpty(idString) || string.IsNullOrEmpty(picString) || picString!.Length < 230)
|
||||
return false;
|
||||
|
||||
key = Tools.HexStringToByteArray(keyString);
|
||||
id = Tools.HexStringToByteArray(idString);
|
||||
pic = Tools.HexStringToByteArray(picString.Substring(0, 230));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates a hexadecimal disc ID
|
||||
/// </summary>
|
||||
/// <param name="discID">String representing hexadecimal disc ID</param>
|
||||
/// <returns>True if string is a valid disc ID, false otherwise</returns>
|
||||
public static byte[]? ParseDiscID(string? discID)
|
||||
{
|
||||
if (string.IsNullOrEmpty(discID))
|
||||
return null;
|
||||
|
||||
string cleandiscID = discID!.Trim().Replace("\n", string.Empty);
|
||||
|
||||
if (discID!.Length != 32)
|
||||
return null;
|
||||
|
||||
// Censor last 4 bytes by replacing with 0x00000001
|
||||
cleandiscID = cleandiscID.Substring(0, 24) + "00000001";
|
||||
|
||||
// Convert to byte array, null if invalid hex string
|
||||
byte[]? id = Tools.HexStringToByteArray(cleandiscID);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates a key file to check for presence of valid PS3 key
|
||||
/// </summary>
|
||||
/// <param name="keyPath">Path to key file</param>
|
||||
/// <returns>Output 16 byte key, null if not valid</returns>
|
||||
public static byte[]? ParseKeyFile(string? keyPath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(keyPath))
|
||||
return null;
|
||||
|
||||
// Try read from key file
|
||||
try
|
||||
{
|
||||
if (!File.Exists(keyPath))
|
||||
return null;
|
||||
|
||||
// Key file must be exactly 16 bytes long
|
||||
FileInfo keyFile = new(keyPath);
|
||||
if (keyFile.Length != 16)
|
||||
return null;
|
||||
byte[] key = new byte[16];
|
||||
|
||||
// Read 16 bytes from Key file
|
||||
using FileStream fs = new(keyPath, FileMode.Open, FileAccess.Read);
|
||||
using BinaryReader reader = new(fs);
|
||||
int numBytes = reader.Read(key, 0, 16);
|
||||
if (numBytes != 16)
|
||||
return null;
|
||||
|
||||
return key;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Not concerned with error
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates a hexadecimal key
|
||||
/// </summary>
|
||||
/// <param name="hexKey">String representing hexadecimal key</param>
|
||||
/// <returns>Output 16 byte key, null if not valid</returns>
|
||||
public static byte[]? ParseHexKey(string? hexKey)
|
||||
{
|
||||
if (string.IsNullOrEmpty(hexKey))
|
||||
return null;
|
||||
|
||||
string cleanHexKey = hexKey!.Trim().Replace("\n", string.Empty);
|
||||
|
||||
if (cleanHexKey.Length != 32)
|
||||
return null;
|
||||
|
||||
// Convert to byte array, null if invalid hex string
|
||||
byte[]? key = Tools.HexStringToByteArray(cleanHexKey);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates a PIC file path
|
||||
/// </summary>
|
||||
/// <param name="picPath">Path to PIC file</param>
|
||||
/// <returns>Output PIC byte array, null if not valid</returns>
|
||||
public static byte[]? ParsePICFile(string? picPath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(picPath))
|
||||
return null;
|
||||
|
||||
// Try read from PIC file
|
||||
try
|
||||
{
|
||||
if (!File.Exists(picPath))
|
||||
return null;
|
||||
|
||||
// PIC file must be at least 115 bytes long
|
||||
FileInfo picFile = new(picPath);
|
||||
if (picFile.Length < 115)
|
||||
return null;
|
||||
byte[] pic = new byte[115];
|
||||
|
||||
// Read 115 bytes from PIC file
|
||||
using FileStream fs = new(picPath, FileMode.Open, FileAccess.Read);
|
||||
using BinaryReader reader = new(fs);
|
||||
int numBytes = reader.Read(pic, 0, 115);
|
||||
if (numBytes != 115)
|
||||
return null;
|
||||
|
||||
// Validate that a PIC was read by checking first 6 bytes
|
||||
if (pic[0] != 0x10 ||
|
||||
pic[1] != 0x02 ||
|
||||
pic[2] != 0x00 ||
|
||||
pic[3] != 0x00 ||
|
||||
pic[4] != 0x44 ||
|
||||
pic[5] != 0x49)
|
||||
return null;
|
||||
|
||||
return pic;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Not concerned with error
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates a PIC
|
||||
/// </summary>
|
||||
/// <param name="inputPIC">String representing PIC</param>
|
||||
/// <returns>Output PIC byte array, null if not valid</returns>
|
||||
public static byte[]? ParsePIC(string? inputPIC)
|
||||
{
|
||||
if (string.IsNullOrEmpty(inputPIC))
|
||||
return null;
|
||||
|
||||
string cleanPIC = inputPIC!.Trim().Replace("\n", string.Empty);
|
||||
|
||||
if (cleanPIC.Length < 230)
|
||||
return null;
|
||||
|
||||
// Convert to byte array, null if invalid hex string
|
||||
byte[]? pic = Tools.HexStringToByteArray(cleanPIC.Substring(0, 230));
|
||||
|
||||
return pic;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates a string representing a layerbreak value (in sectors)
|
||||
/// </summary>
|
||||
/// <param name="inputLayerbreak">String representing layerbreak value</param>
|
||||
/// <param name="layerbreak">Output layerbreak value, null if not valid</param>
|
||||
/// <returns>True if layerbreak is valid, false otherwise</returns>
|
||||
public static long? ParseLayerbreak(string? inputLayerbreak)
|
||||
{
|
||||
if (string.IsNullOrEmpty(inputLayerbreak))
|
||||
return null;
|
||||
|
||||
if (!long.TryParse(inputLayerbreak, out long layerbreak))
|
||||
return null;
|
||||
|
||||
return ParseLayerbreak(layerbreak);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates a layerbreak value (in sectors)
|
||||
/// </summary>
|
||||
/// <param name="inputLayerbreak">Number representing layerbreak value</param>
|
||||
/// <param name="layerbreak">Output layerbreak value, null if not valid</param>
|
||||
/// <returns>True if layerbreak is valid, false otherwise</returns>
|
||||
public static long? ParseLayerbreak(long? layerbreak)
|
||||
{
|
||||
// Check that layerbreak is positive number and smaller than largest disc size (in sectors)
|
||||
if (layerbreak <= 0 || layerbreak > 24438784)
|
||||
return null;
|
||||
|
||||
return layerbreak;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a CRC32 hash hex string into uint32 representation
|
||||
/// </summary>
|
||||
/// <param name="inputLayerbreak">Hex string representing CRC32 hash</param>
|
||||
/// <param name="layerbreak">Output CRC32 value, null if not valid</param>
|
||||
/// <returns>True if CRC32 hash string is valid, false otherwise</returns>
|
||||
public static uint? ParseCRC32(string? inputCRC32)
|
||||
{
|
||||
if (string.IsNullOrEmpty(inputCRC32))
|
||||
return null;
|
||||
|
||||
byte[]? crc32 = Tools.HexStringToByteArray(inputCRC32);
|
||||
|
||||
if (crc32 == null || crc32.Length != 4)
|
||||
return null;
|
||||
|
||||
return (uint)(0x01000000 * crc32[0] + 0x00010000 * crc32[1] + 0x00000100 * crc32[2] + 0x00000001 * crc32[3]);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0-windows;net8.0-windows</TargetFrameworks>
|
||||
<TargetFrameworks>net8.0</TargetFrameworks>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
@@ -10,26 +10,26 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MPF\MPF.csproj" />
|
||||
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeCoverage" Version="17.9.0-preview-23531-01" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0-preview-23531-01" />
|
||||
<PackageReference Include="Microsoft.CodeCoverage" Version="17.10.0-release-24177-07" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0-release-24177-07" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="1.3.2" />
|
||||
<PackageReference Include="xunit" Version="2.6.2" />
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="1.3.6" />
|
||||
<PackageReference Include="xunit" Version="2.7.1" />
|
||||
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
|
||||
<PackageReference Include="xunit.analyzers" Version="1.6.0" />
|
||||
<PackageReference Include="xunit.assert" Version="2.6.2" />
|
||||
<PackageReference Include="xunit.core" Version="2.6.2" />
|
||||
<PackageReference Include="xunit.extensibility.core" Version="2.6.2" />
|
||||
<PackageReference Include="xunit.extensibility.execution" Version="2.6.2" />
|
||||
<PackageReference Include="xunit.runner.console" Version="2.6.2">
|
||||
<PackageReference Include="xunit.analyzers" Version="1.12.0" />
|
||||
<PackageReference Include="xunit.assert" Version="2.7.1" />
|
||||
<PackageReference Include="xunit.core" Version="2.7.1" />
|
||||
<PackageReference Include="xunit.extensibility.core" Version="2.7.1" />
|
||||
<PackageReference Include="xunit.extensibility.execution" Version="2.7.1" />
|
||||
<PackageReference Include="xunit.runner.console" Version="2.7.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.4">
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.8">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -16,6 +16,8 @@ namespace MPF.UI.Core
|
||||
DiscCategory discCategory => new Element<DiscCategory>(discCategory),
|
||||
InternalProgram internalProgram => new Element<InternalProgram>(internalProgram),
|
||||
MediaType mediaType => new Element<MediaType>(mediaType),
|
||||
RedumperReadMethod readMethod => new Element<RedumperReadMethod>(readMethod),
|
||||
RedumperSectorOrder sectorOrder => new Element<RedumperSectorOrder>(sectorOrder),
|
||||
RedumpSystem redumpSystem => new RedumpSystemComboBoxItem(redumpSystem),
|
||||
Region region => new Element<Region>(region),
|
||||
|
||||
@@ -35,6 +37,8 @@ namespace MPF.UI.Core
|
||||
Element<DiscCategory> dcElement => dcElement.Value,
|
||||
Element<InternalProgram> ipElement => ipElement.Value,
|
||||
Element<MediaType> mtElement => mtElement.Value,
|
||||
Element<RedumperReadMethod> rmElement => rmElement.Value,
|
||||
Element<RedumperSectorOrder> soElement => soElement.Value,
|
||||
RedumpSystemComboBoxItem rsElement => rsElement.Value,
|
||||
Element<Region> reValue => reValue.Value,
|
||||
_ => null,
|
||||
|
||||
@@ -6,14 +6,15 @@
|
||||
<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<ImportFrameworkWinFXTargets Condition="$(TargetFramework.StartsWith(`net3`))">true</ImportFrameworkWinFXTargets>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<VersionPrefix>3.1.0</VersionPrefix>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<UseWPF>true</UseWPF>
|
||||
<VersionPrefix>3.1.6</VersionPrefix>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
@@ -42,7 +43,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="1.3.2" />
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="1.3.6" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -75,9 +75,6 @@
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label x:Name="InputPathLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Content="Input Path"/>
|
||||
@@ -120,7 +117,7 @@
|
||||
<Button Name="CheckDumpButton" Height="25" Width="80" IsDefault="True" Content="Check Dump"
|
||||
IsEnabled="{Binding CheckDumpButtonEnabled}" Style="{DynamicResource CustomButtonStyle}" />
|
||||
<Button Name="CancelButton" Height="25" Width="80" IsCancel="True" Content="Cancel"
|
||||
Style="{DynamicResource CustomButtonStyle}" />
|
||||
IsEnabled="{Binding CancelButtonEnabled}" Style="{DynamicResource CustomButtonStyle}" />
|
||||
<Label/>
|
||||
<!-- Empty label for padding -->
|
||||
</UniformGrid>
|
||||
|
||||
@@ -132,6 +132,7 @@ namespace MPF.UI.Core.Windows
|
||||
WinForms.FileDialog fileDialog = new WinForms.OpenFileDialog
|
||||
{
|
||||
InitialDirectory = directory,
|
||||
Filter = "Disc Images|*.iso;*.cue;*.aaruf|All Files|*.*",
|
||||
};
|
||||
WinForms.DialogResult result = fileDialog.ShowDialog();
|
||||
|
||||
@@ -208,9 +209,17 @@ namespace MPF.UI.Core.Windows
|
||||
/// <summary>
|
||||
/// Handler for CheckDumpButton Click event
|
||||
/// </summary>
|
||||
#if NET40
|
||||
private void OnCheckDumpClick(object sender, EventArgs e)
|
||||
{
|
||||
string? errorMessage = CheckDumpViewModel.CheckDump(ShowDiscInformationWindow);
|
||||
var checkTask = CheckDumpViewModel.CheckDump(ShowDiscInformationWindow);
|
||||
checkTask.Wait();
|
||||
string? errorMessage = checkTask.Result;
|
||||
#else
|
||||
private async void OnCheckDumpClick(object sender, EventArgs e)
|
||||
{
|
||||
string? errorMessage = await CheckDumpViewModel.CheckDump(ShowDiscInformationWindow);
|
||||
#endif
|
||||
if (string.IsNullOrEmpty(errorMessage))
|
||||
{
|
||||
bool? checkAgain = DisplayUserMessage("Check Complete", "The dump has been processed successfully! Would you like to check another dump?", 2, false);
|
||||
|
||||
209
MPF.UI.Core/Windows/CreateIRDWindow.xaml
Normal file
209
MPF.UI.Core/Windows/CreateIRDWindow.xaml
Normal file
@@ -0,0 +1,209 @@
|
||||
<coreWindows:WindowBase x:Class="MPF.UI.Core.Windows.CreateIRDWindow"
|
||||
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:core="clr-namespace:MPF.UI.Core"
|
||||
xmlns:coreWindows="clr-namespace:MPF.UI.Core.Windows"
|
||||
xmlns:viewModels="clr-namespace:MPF.Core.UI.ViewModels;assembly=MPF.Core"
|
||||
mc:Ignorable="d"
|
||||
Title="Create PS3 IRD" Width="600" WindowStyle="None"
|
||||
WindowStartupLocation="CenterOwner" ResizeMode="CanMinimize" SizeToContent="Height"
|
||||
BorderBrush="DarkGray" BorderThickness="2">
|
||||
|
||||
<Window.DataContext>
|
||||
<viewModels:CreateIRDViewModel/>
|
||||
</Window.DataContext>
|
||||
<Window.Resources>
|
||||
<core:ElementConverter x:Key="ElementConverter" />
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<StackPanel Orientation="Vertical">
|
||||
<Grid Margin="0,2,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="25"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="50"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Image Grid.Column="0" Source="/Images/Icon.ico" Height="20" Width="20" Margin="1" />
|
||||
<Label Grid.Column="1" Grid.ColumnSpan="4" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" MouseDown="TitleMouseDown">
|
||||
<Label.Content>
|
||||
<Run FontWeight="Bold" Text="Create PS3 IRD" />
|
||||
</Label.Content>
|
||||
<Label.ContextMenu>
|
||||
<ContextMenu Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
|
||||
Foreground="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
|
||||
Style="{DynamicResource CustomContextMenuStyle}">
|
||||
<MenuItem Header="Minimize" Click="MinimizeButtonClick" Width="185"
|
||||
Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
|
||||
Foreground="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
|
||||
Template="{DynamicResource CustomMenuItemTemplate}"/>
|
||||
<MenuItem Header="Close" Click="CloseButtonClick" Width="185"
|
||||
Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
|
||||
Foreground="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
|
||||
Template="{DynamicResource CustomMenuItemTemplate}"/>
|
||||
</ContextMenu>
|
||||
</Label.ContextMenu>
|
||||
</Label>
|
||||
<Grid Grid.Column="5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button x:Name="MinimizeButton" Grid.Column="0" BorderThickness="0" Background="Transparent" Style="{DynamicResource CustomButtonStyle}" Click="MinimizeButtonClick">
|
||||
<Path Data="M 0,0 L 10,0" Stroke="{Binding Path=Foreground,RelativeSource={RelativeSource AncestorType={x:Type Button}}}" StrokeThickness="1"/>
|
||||
</Button>
|
||||
<Button x:Name="CloseButton" Grid.Column="1" BorderThickness="0" Background="Transparent" Style="{DynamicResource CustomButtonStyle}" Click="CloseButtonClick">
|
||||
<Path Data="M 0,0 L 12,12 M 0,12 L 12,0" Stroke="{Binding Path=Foreground,RelativeSource={RelativeSource AncestorType={x:Type Button}}}" StrokeThickness="1"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<GroupBox Margin="5,5,5,5" HorizontalAlignment="Stretch" Header="Input">
|
||||
<Grid Margin="5,5,5,5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="2.5*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label x:Name="InputPathLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Content="PS3 ISO Path"/>
|
||||
<TextBox x:Name="InputPathTextBox" Grid.Row="0" Grid.Column="1" Height="22" Width="345" HorizontalAlignment="Left" VerticalContentAlignment="Center"
|
||||
Text="{Binding InputPath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{Binding InputPathTextBoxEnabled}" />
|
||||
<Button x:Name="InputPathBrowseButton" Grid.Row="0" Grid.Column="1" Height="22" Width="50" HorizontalAlignment="Right" Content="Browse"
|
||||
IsEnabled="{Binding InputPathBrowseButtonEnabled}" Style="{DynamicResource CustomButtonStyle}"/>
|
||||
|
||||
<Label x:Name="LogPathLabel" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Content="*.getkey.log File Path"/>
|
||||
<TextBox x:Name="LogPathTextBox" Grid.Row="1" Grid.Column="1" Height="22" Width="345" HorizontalAlignment="Left" VerticalContentAlignment="Center"
|
||||
Text="{Binding LogPath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{Binding LogPathTextBoxEnabled}" />
|
||||
<Button x:Name="LogPathBrowseButton" Grid.Row="1" Grid.Column="1" Height="22" Width="50" HorizontalAlignment="Right" Content="Browse"
|
||||
IsEnabled="{Binding LogPathBrowseButtonEnabled}" Style="{DynamicResource CustomButtonStyle}"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<Expander Name="KeyExpander" BorderThickness="1" BorderBrush="#D5DFE5" Margin="5,5,5,5" HorizontalAlignment="Stretch"
|
||||
IsEnabled="{Binding LogPathNotProvided}" IsExpanded="False" Header="Manually define PS3 Disc Encryption Key">
|
||||
<Grid Margin="5,5,5,5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="2.5*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label x:Name="KeyLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Content="Hexadecimal Key"/>
|
||||
<TextBox x:Name="KeyTextBox" Grid.Row="0" Grid.Column="1" Height="22" Width="345" HorizontalAlignment="Left" VerticalContentAlignment="Center"
|
||||
Text="{Binding HexKey, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{Binding HexKeyTextBoxEnabled}" />
|
||||
|
||||
<Label x:Name="KeyPathLabel" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center"
|
||||
ToolTip="Typically a *.key file" Content="Key File Path"/>
|
||||
<TextBox x:Name="KeyPathTextBox" Grid.Row="1" Grid.Column="1" Height="22" Width="345" HorizontalAlignment="Left" VerticalContentAlignment="Center"
|
||||
Text="{Binding KeyPath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{Binding KeyPathTextBoxEnabled}" />
|
||||
<Button x:Name="KeyPathBrowseButton" Grid.Row="1" Grid.Column="1" Height="22" Width="50" HorizontalAlignment="Right" Content="Browse"
|
||||
IsEnabled="{Binding KeyPathBrowseButtonEnabled}" Style="{DynamicResource CustomButtonStyle}"/>
|
||||
|
||||
<Label x:Name="KeyStatusLabel" Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Content="Key Status"/>
|
||||
<Label x:Name="KeyStatusText" Grid.Row="2" Grid.Column="1" VerticalAlignment="Center" Content="{Binding KeyStatus}"/>
|
||||
</Grid>
|
||||
</Expander>
|
||||
|
||||
<Expander Name="DiscIDExpander" BorderThickness="1" BorderBrush="#D5DFE5" Margin="5,5,5,5" HorizontalAlignment="Stretch"
|
||||
IsEnabled="{Binding LogPathNotProvided}" IsExpanded="False" Header="Manually define PS3 Disc ID">
|
||||
<Grid Margin="5,5,5,5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="2.5*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label x:Name="DiscIDLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Content="Disc ID"/>
|
||||
<TextBox x:Name="DiscIDTextBox" Grid.Row="0" Grid.Column="1" Height="22" Width="345" HorizontalAlignment="Left" VerticalContentAlignment="Center"
|
||||
Text="{Binding DiscIDString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{Binding DiscIDTextBoxEnabled}" />
|
||||
|
||||
<Label x:Name="DiscIDStatusLabel" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Content="DiscID Status"/>
|
||||
<Label x:Name="DiscIDStatusText" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Content="{Binding DiscIDStatus}"/>
|
||||
</Grid>
|
||||
</Expander>
|
||||
|
||||
<Expander Name="PICExpander" BorderThickness="1" BorderBrush="#D5DFE5" Margin="5,5,5,5" HorizontalAlignment="Stretch"
|
||||
IsEnabled="{Binding LogPathNotProvided}" IsExpanded="False" Header="Manually define Permanent Information & Control (PIC)">
|
||||
<Grid Margin="5,5,5,5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="2.5*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label x:Name="LayerbreakLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Content="Layerbreak (sectors)"/>
|
||||
<TextBox x:Name="LayerbreakTextBox" Grid.Row="0" Grid.Column="1" Height="22" Width="345" HorizontalAlignment="Left" VerticalContentAlignment="Center"
|
||||
Text="{Binding LayerbreakString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{Binding LayerbreakTextBoxEnabled}" />
|
||||
|
||||
<Label x:Name="PICLabel" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Content="PIC"/>
|
||||
<TextBox x:Name="PICTextBox" Grid.Row="1" Grid.Column="1" Width="345" HorizontalAlignment="Left" VerticalContentAlignment="Top"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto"
|
||||
MinHeight="55" MaxHeight="146" AcceptsReturn="True"
|
||||
Text="{Binding PICString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{Binding PICTextBoxEnabled}" />
|
||||
|
||||
<Label x:Name="PICPathLabel" Grid.Row="2" Grid.Column="0" VerticalAlignment="Center"
|
||||
ToolTip="Typically a *.physical or *_PIC.bin file" Content="PIC File Path"/>
|
||||
<TextBox x:Name="PICPathTextBox" Grid.Row="2" Grid.Column="1" Height="22" Width="345" HorizontalAlignment="Left" VerticalContentAlignment="Center"
|
||||
Text="{Binding PICPath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{Binding PICPathTextBoxEnabled}" />
|
||||
<Button x:Name="PICPathBrowseButton" Grid.Row="2" Grid.Column="1" Height="22" Width="50" HorizontalAlignment="Right" Content="Browse"
|
||||
IsEnabled="{Binding PICPathBrowseButtonEnabled}" Style="{DynamicResource CustomButtonStyle}"/>
|
||||
|
||||
<Label x:Name="PICStatusLabel" Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" Content="PIC Status"/>
|
||||
<Label x:Name="PICStatusText" Grid.Row="3" Grid.Column="1" VerticalAlignment="Center" Content="{Binding PICStatus}"/>
|
||||
</Grid>
|
||||
</Expander>
|
||||
|
||||
<GroupBox Margin="5,5,5,5" HorizontalAlignment="Stretch" Header="Status">
|
||||
<UniformGrid Margin="5,5,5,5" Grid.ColumnSpan="2">
|
||||
<TextBlock x:Name="StatusLabel" VerticalAlignment="Center" HorizontalAlignment="Center"
|
||||
Text="{Binding CreateIRDStatus, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
|
||||
<!-- Create IRD / Cancel -->
|
||||
<GroupBox Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<UniformGrid Columns="4" Margin="5,5,5,5" Height="28">
|
||||
<Label/>
|
||||
<!-- Empty label for padding -->
|
||||
<Button Name="CreateIRDButton" Height="25" Width="80" IsDefault="True" Content="Create IRD"
|
||||
IsEnabled="{Binding CreateIRDButtonEnabled}" Style="{DynamicResource CustomButtonStyle}" />
|
||||
<Button Name="CancelButton" Height="25" Width="80" IsCancel="True" Content="Cancel"
|
||||
IsEnabled="{Binding CancelButtonEnabled}" Style="{DynamicResource CustomButtonStyle}" />
|
||||
<Label/>
|
||||
<!-- Empty label for padding -->
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</coreWindows:WindowBase>
|
||||
489
MPF.UI.Core/Windows/CreateIRDWindow.xaml.cs
Normal file
489
MPF.UI.Core/Windows/CreateIRDWindow.xaml.cs
Normal file
@@ -0,0 +1,489 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using MPF.Core.UI.ViewModels;
|
||||
using WPFCustomMessageBox;
|
||||
using WinForms = System.Windows.Forms;
|
||||
|
||||
#pragma warning disable IDE1006 // Naming Styles
|
||||
|
||||
namespace MPF.UI.Core.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for CreateIRDWindow.xaml
|
||||
/// </summary>
|
||||
public partial class CreateIRDWindow : WindowBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Read-only access to the current check dump view model
|
||||
/// </summary>
|
||||
public CreateIRDViewModel CreateIRDViewModel => DataContext as CreateIRDViewModel ?? new CreateIRDViewModel();
|
||||
|
||||
#if NET35
|
||||
|
||||
#region Settings
|
||||
|
||||
private Button? _InputPathBrowseButton => ItemHelper.FindChild<Button>(this, "InputPathBrowseButton");
|
||||
private TextBox? _InputPathTextBox => ItemHelper.FindChild<TextBox>(this, "InputPathTextBox");
|
||||
|
||||
private Button? _LogPathBrowseButton => ItemHelper.FindChild<Button>(this, "LogPathBrowseButton");
|
||||
private TextBox? _LogPathTextBox => ItemHelper.FindChild<TextBox>(this, "LogPathTextBox");
|
||||
private Button? _KeyPathBrowseButton => ItemHelper.FindChild<Button>(this, "KeyPathBrowseButton");
|
||||
private TextBox? _KeyPathTextBox => ItemHelper.FindChild<TextBox>(this, "KeyPathTextBox");
|
||||
private TextBox? _KeyTextBox => ItemHelper.FindChild<TextBox>(this, "KeyTextBox");
|
||||
private TextBox? _DiscIDTextBox => ItemHelper.FindChild<TextBox>(this, "DiscIDTextBox");
|
||||
private Button? _PICPathBrowseButton => ItemHelper.FindChild<Button>(this, "PICPathBrowseButton");
|
||||
private TextBox? _PICPathTextBox => ItemHelper.FindChild<TextBox>(this, "PICPathTextBox");
|
||||
private TextBox? _PICTextBox => ItemHelper.FindChild<TextBox>(this, "PICTextBox");
|
||||
private TextBox? _LayerbreakTextBox => ItemHelper.FindChild<TextBox>(this, "LayerbreakTextBox");
|
||||
|
||||
#endregion
|
||||
|
||||
#region Controls
|
||||
|
||||
private System.Windows.Controls.Button? _CreateIRDButton => ItemHelper.FindChild<System.Windows.Controls.Button>(this, "CreateIRDButton");
|
||||
private System.Windows.Controls.Button? _CancelButton => ItemHelper.FindChild<System.Windows.Controls.Button>(this, "CancelButton");
|
||||
|
||||
#endregion
|
||||
|
||||
#region Expanders
|
||||
|
||||
private Expander? _KeyExpander => ItemHelper.FindChild<Expander>(this, "KeyExpander");
|
||||
private Expander? _DiscIDExpander => ItemHelper.FindChild<Expander>(this, "DiscIDExpander");
|
||||
private Expander? _PICExpander => ItemHelper.FindChild<Expander>(this, "PICExpander");
|
||||
|
||||
#endregion
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public CreateIRDWindow(MainWindow parent)
|
||||
{
|
||||
#if NET40_OR_GREATER || NETCOREAPP
|
||||
InitializeComponent();
|
||||
#endif
|
||||
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
var chrome = new System.Windows.Shell.WindowChrome
|
||||
{
|
||||
CaptionHeight = 0,
|
||||
ResizeBorderThickness = new Thickness(0),
|
||||
};
|
||||
System.Windows.Shell.WindowChrome.SetWindowChrome(this, chrome);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for CheckDumpWindow OnContentRendered event
|
||||
/// </summary>
|
||||
protected override void OnContentRendered(EventArgs e)
|
||||
{
|
||||
base.OnContentRendered(e);
|
||||
|
||||
// Add the click handlers to the UI
|
||||
AddEventHandlers();
|
||||
}
|
||||
|
||||
#region UI Functionality
|
||||
|
||||
/// <summary>
|
||||
/// Add all event handlers
|
||||
/// </summary>
|
||||
public void AddEventHandlers()
|
||||
{
|
||||
// Main buttons
|
||||
#if NET35
|
||||
_CreateIRDButton!.Click += OnCreateIRDClick;
|
||||
_CancelButton!.Click += OnCancelClick;
|
||||
#else
|
||||
CreateIRDButton.Click += OnCreateIRDClick;
|
||||
CancelButton.Click += OnCancelClick;
|
||||
#endif
|
||||
|
||||
// User Area Click
|
||||
#if NET35
|
||||
_InputPathBrowseButton!.Click += InputPathBrowseButtonClick;
|
||||
_LogPathBrowseButton!.Click += LogPathBrowseButtonClick;
|
||||
_KeyPathBrowseButton!.Click += KeyPathBrowseButtonClick;
|
||||
_PICPathBrowseButton!.Click += PICPathBrowseButtonClick;
|
||||
#else
|
||||
InputPathBrowseButton.Click += InputPathBrowseButtonClick;
|
||||
LogPathBrowseButton.Click += LogPathBrowseButtonClick;
|
||||
KeyPathBrowseButton.Click += KeyPathBrowseButtonClick;
|
||||
PICPathBrowseButton.Click += PICPathBrowseButtonClick;
|
||||
#endif
|
||||
|
||||
// User Area TextChanged
|
||||
#if NET35
|
||||
_InputPathTextBox!.TextChanged += InputPathTextBoxTextChanged;
|
||||
_LogPathTextBox!.TextChanged += LogPathTextBoxTextChanged;
|
||||
_KeyPathTextBox!.TextChanged += KeyPathTextBoxTextChanged;
|
||||
_KeyTextBox!.TextChanged += KeyTextBoxTextChanged;
|
||||
_DiscIDTextBox!.TextChanged += DiscIDTextBoxTextChanged;
|
||||
_PICPathTextBox!.TextChanged += PICPathTextBoxTextChanged;
|
||||
_PICTextBox!.TextChanged += PICTextBoxTextChanged;
|
||||
_LayerbreakTextBox!.TextChanged += LayerbreakTextBoxTextChanged;
|
||||
#else
|
||||
InputPathTextBox.TextChanged += InputPathTextBoxTextChanged;
|
||||
LogPathTextBox.TextChanged += LogPathTextBoxTextChanged;
|
||||
KeyPathTextBox.TextChanged += KeyPathTextBoxTextChanged;
|
||||
KeyTextBox.TextChanged += KeyTextBoxTextChanged;
|
||||
DiscIDTextBox.TextChanged += DiscIDTextBoxTextChanged;
|
||||
PICPathTextBox.TextChanged += PICPathTextBoxTextChanged;
|
||||
PICTextBox.TextChanged += PICTextBoxTextChanged;
|
||||
LayerbreakTextBox.TextChanged += LayerbreakTextBoxTextChanged;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Browse for an input ISO file path
|
||||
/// </summary>
|
||||
public void BrowseISOFile()
|
||||
{
|
||||
// Get the current path, if possible
|
||||
string? currentPath = CreateIRDViewModel.InputPath;
|
||||
if (string.IsNullOrEmpty(currentPath) && !string.IsNullOrEmpty(CreateIRDViewModel.Options.DefaultOutputPath))
|
||||
currentPath = CreateIRDViewModel.Options.DefaultOutputPath!;
|
||||
if (string.IsNullOrEmpty(currentPath))
|
||||
currentPath = AppDomain.CurrentDomain.BaseDirectory!;
|
||||
|
||||
// Get the full directory
|
||||
var directory = Path.GetDirectoryName(Path.GetFullPath(currentPath));
|
||||
|
||||
WinForms.FileDialog fileDialog = new WinForms.OpenFileDialog
|
||||
{
|
||||
InitialDirectory = directory,
|
||||
Filter = "ISO|*.iso|All Files|*.*",
|
||||
};
|
||||
WinForms.DialogResult result = fileDialog.ShowDialog();
|
||||
|
||||
if (result == WinForms.DialogResult.OK)
|
||||
{
|
||||
CreateIRDViewModel.InputPath = fileDialog.FileName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Browse for an .getkey.log file path
|
||||
/// </summary>
|
||||
public void BrowseLogFile()
|
||||
{
|
||||
// Get the current path, if possible
|
||||
string? currentPath = CreateIRDViewModel.LogPath;
|
||||
if (string.IsNullOrEmpty(currentPath) && !string.IsNullOrEmpty(CreateIRDViewModel.Options.DefaultOutputPath))
|
||||
currentPath = CreateIRDViewModel.Options.DefaultOutputPath!;
|
||||
if (string.IsNullOrEmpty(currentPath))
|
||||
currentPath = AppDomain.CurrentDomain.BaseDirectory!;
|
||||
|
||||
// Get the full directory
|
||||
var directory = Path.GetDirectoryName(Path.GetFullPath(currentPath));
|
||||
|
||||
WinForms.FileDialog fileDialog = new WinForms.OpenFileDialog
|
||||
{
|
||||
InitialDirectory = directory,
|
||||
Filter = "GetKey Log|*.getkey.log|All Files|*.*",
|
||||
};
|
||||
WinForms.DialogResult result = fileDialog.ShowDialog();
|
||||
|
||||
if (result == WinForms.DialogResult.OK)
|
||||
{
|
||||
CreateIRDViewModel.LogPath = fileDialog.FileName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Browse for an key file path
|
||||
/// </summary>
|
||||
public void BrowseKeyFile()
|
||||
{
|
||||
// Get the current path, if possible
|
||||
string? currentPath = CreateIRDViewModel.LogPath;
|
||||
if (string.IsNullOrEmpty(currentPath) && !string.IsNullOrEmpty(CreateIRDViewModel.Options.DefaultOutputPath))
|
||||
currentPath = CreateIRDViewModel.Options.DefaultOutputPath!;
|
||||
if (string.IsNullOrEmpty(currentPath))
|
||||
currentPath = AppDomain.CurrentDomain.BaseDirectory!;
|
||||
|
||||
// Get the full directory
|
||||
var directory = Path.GetDirectoryName(Path.GetFullPath(currentPath));
|
||||
|
||||
WinForms.FileDialog fileDialog = new WinForms.OpenFileDialog
|
||||
{
|
||||
InitialDirectory = directory,
|
||||
Filter = "Key|*.key|All Files|*.*",
|
||||
};
|
||||
WinForms.DialogResult result = fileDialog.ShowDialog();
|
||||
|
||||
if (result == WinForms.DialogResult.OK)
|
||||
{
|
||||
CreateIRDViewModel.KeyPath = fileDialog.FileName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Browse for an IRD output path
|
||||
/// </summary>
|
||||
/// <returns>Output path if provided, else null</returns>
|
||||
public string? BrowseOutputFile()
|
||||
{
|
||||
// Get the current path, if possible
|
||||
string? currentPath = CreateIRDViewModel.InputPath;
|
||||
if (string.IsNullOrEmpty(currentPath) && !string.IsNullOrEmpty(CreateIRDViewModel.Options.DefaultOutputPath))
|
||||
currentPath = Path.Combine(CreateIRDViewModel.Options.DefaultOutputPath, "game.ird");
|
||||
else if (string.IsNullOrEmpty(currentPath))
|
||||
currentPath = "game.ird";
|
||||
if (string.IsNullOrEmpty(currentPath))
|
||||
currentPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory!, "game.ird");
|
||||
|
||||
// Get the full path
|
||||
currentPath = Path.GetFullPath(currentPath);
|
||||
|
||||
// Get the directory
|
||||
var directory = Path.GetDirectoryName(currentPath);
|
||||
|
||||
// Get the filename
|
||||
string filename = Path.ChangeExtension(Path.GetFileName(currentPath), ".ird");
|
||||
|
||||
WinForms.FileDialog fileDialog = new WinForms.SaveFileDialog
|
||||
{
|
||||
FileName = filename,
|
||||
InitialDirectory = directory,
|
||||
Filter = "IRD File|*.ird|All Files|*.*"
|
||||
};
|
||||
WinForms.DialogResult result = fileDialog.ShowDialog();
|
||||
if (result == WinForms.DialogResult.OK)
|
||||
return fileDialog.FileName;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Browse for an PIC file path
|
||||
/// </summary>
|
||||
public void BrowsePICFile()
|
||||
{
|
||||
// Get the current path, if possible
|
||||
string? currentPath = CreateIRDViewModel.LogPath;
|
||||
if (string.IsNullOrEmpty(currentPath) && !string.IsNullOrEmpty(CreateIRDViewModel.Options.DefaultOutputPath))
|
||||
currentPath = CreateIRDViewModel.Options.DefaultOutputPath!;
|
||||
if (string.IsNullOrEmpty(currentPath))
|
||||
currentPath = AppDomain.CurrentDomain.BaseDirectory!;
|
||||
|
||||
// Get the full directory
|
||||
var directory = Path.GetDirectoryName(Path.GetFullPath(currentPath));
|
||||
|
||||
WinForms.FileDialog fileDialog = new WinForms.OpenFileDialog
|
||||
{
|
||||
InitialDirectory = directory,
|
||||
Filter = "PIC|*.physical;*_PIC.bin;*.PIC|All Files|*.*",
|
||||
};
|
||||
WinForms.DialogResult result = fileDialog.ShowDialog();
|
||||
|
||||
if (result == WinForms.DialogResult.OK)
|
||||
{
|
||||
CreateIRDViewModel.PICPath = fileDialog.FileName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display a user message using a CustomMessageBox
|
||||
/// </summary>
|
||||
/// <param name="title">Title to display to the user</param>
|
||||
/// <param name="message">Message to display to the user</param>
|
||||
/// <param name="optionCount">Number of options to display</param>
|
||||
/// <param name="flag">true for inquiry, false otherwise</param>
|
||||
/// <returns>true for positive, false for negative, null for neutral</returns>
|
||||
public bool? DisplayUserMessage(string title, string message, int optionCount, bool flag)
|
||||
{
|
||||
// Set the correct button style
|
||||
var button = optionCount switch
|
||||
{
|
||||
1 => MessageBoxButton.OK,
|
||||
2 => MessageBoxButton.YesNo,
|
||||
3 => MessageBoxButton.YesNoCancel,
|
||||
|
||||
// This should not happen, but default to "OK"
|
||||
_ => MessageBoxButton.OK,
|
||||
};
|
||||
|
||||
// Set the correct icon
|
||||
MessageBoxImage image = flag ? MessageBoxImage.Question : MessageBoxImage.Exclamation;
|
||||
|
||||
// Display and get the result
|
||||
MessageBoxResult result = CustomMessageBox.Show(this, message, title, button, image);
|
||||
return result switch
|
||||
{
|
||||
MessageBoxResult.OK or MessageBoxResult.Yes => true,
|
||||
MessageBoxResult.No => false,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Handler for CreateIRDButton Click event
|
||||
/// </summary>
|
||||
private void OnCreateIRDClick(object sender, EventArgs e)
|
||||
{
|
||||
#if NET35
|
||||
if (_KeyExpander != null) _KeyExpander.IsExpanded = false;
|
||||
if (_DiscIDExpander != null) _DiscIDExpander.IsExpanded = false;
|
||||
if (_PICExpander != null) _PICExpander.IsExpanded = false;
|
||||
#else
|
||||
KeyExpander.IsExpanded = false;
|
||||
DiscIDExpander.IsExpanded = false;
|
||||
PICExpander.IsExpanded = false;
|
||||
#endif
|
||||
string tempStatus = CreateIRDViewModel.CreateIRDStatus;
|
||||
bool[] enabledFields = CreateIRDViewModel.DisableUIFields();
|
||||
CreateIRDViewModel.CreateIRDStatus = "Creating IRD... Please Wait";
|
||||
string? outputPath = BrowseOutputFile();
|
||||
string? errorMessage = "Please provide an output path";
|
||||
if (outputPath != null)
|
||||
{
|
||||
errorMessage = CreateIRDViewModel.CreateIRD(outputPath);
|
||||
}
|
||||
if (string.IsNullOrEmpty(errorMessage))
|
||||
{
|
||||
bool? checkAgain = DisplayUserMessage("IRD Create", "An IRD has been created successfully! Would you like to create another IRD?", 2, false);
|
||||
if (checkAgain == false)
|
||||
Close();
|
||||
else
|
||||
CreateIRDViewModel.ResetFields();
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayUserMessage("Failed to create IRD", errorMessage!, 1, false);
|
||||
CreateIRDViewModel.ReenableUIFields(enabledFields);
|
||||
CreateIRDViewModel.CreateIRDStatus = tempStatus;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for CancelButtom Click event
|
||||
/// </summary>
|
||||
private void OnCancelClick(object sender, EventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for DiscIDTextBox TextChanged event
|
||||
/// </summary>
|
||||
public void DiscIDTextBoxTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (CreateIRDViewModel.CanExecuteSelectionChanged)
|
||||
CreateIRDViewModel.ChangeDiscID();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for InputPathBrowseButton Click event
|
||||
/// </summary>
|
||||
public void InputPathBrowseButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
BrowseISOFile();
|
||||
if (CreateIRDViewModel.CanExecuteSelectionChanged)
|
||||
CreateIRDViewModel.ChangeInputPath();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for InputPathTextBox TextChanged event
|
||||
/// </summary>
|
||||
public void InputPathTextBoxTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (CreateIRDViewModel.CanExecuteSelectionChanged)
|
||||
CreateIRDViewModel.ChangeInputPath();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for LogPathBrowseButton Click event
|
||||
/// </summary>
|
||||
public void LogPathBrowseButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
BrowseLogFile();
|
||||
if (CreateIRDViewModel.CanExecuteSelectionChanged)
|
||||
CreateIRDViewModel.ChangeLogPath();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for LogPathTextBox TextChanged event
|
||||
/// </summary>
|
||||
public void LogPathTextBoxTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (CreateIRDViewModel.CanExecuteSelectionChanged)
|
||||
CreateIRDViewModel.ChangeLogPath();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for KeyPathBrowseButton Click event
|
||||
/// </summary>
|
||||
public void KeyPathBrowseButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
BrowseKeyFile();
|
||||
if (CreateIRDViewModel.CanExecuteSelectionChanged)
|
||||
CreateIRDViewModel.ChangeKeyPath();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for KeyPathTextBox TextChanged event
|
||||
/// </summary>
|
||||
public void KeyPathTextBoxTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (CreateIRDViewModel.CanExecuteSelectionChanged)
|
||||
CreateIRDViewModel.ChangeKeyPath();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for KeyTextBox TextChanged event
|
||||
/// </summary>
|
||||
public void KeyTextBoxTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (CreateIRDViewModel.CanExecuteSelectionChanged)
|
||||
CreateIRDViewModel.ChangeKey();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for PICPathBrowseButton Click event
|
||||
/// </summary>
|
||||
public void PICPathBrowseButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
BrowsePICFile();
|
||||
if (CreateIRDViewModel.CanExecuteSelectionChanged)
|
||||
CreateIRDViewModel.ChangePICPath();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for PICPathTextBox TextChanged event
|
||||
/// </summary>
|
||||
public void PICPathTextBoxTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (CreateIRDViewModel.CanExecuteSelectionChanged)
|
||||
CreateIRDViewModel.ChangePICPath();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for PICTextBox TextChanged event
|
||||
/// </summary>
|
||||
public void PICTextBoxTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (CreateIRDViewModel.CanExecuteSelectionChanged)
|
||||
CreateIRDViewModel.ChangePIC();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for LayerbreakTextBox TextChanged event
|
||||
/// </summary>
|
||||
public void LayerbreakTextBoxTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (CreateIRDViewModel.CanExecuteSelectionChanged)
|
||||
CreateIRDViewModel.ChangeLayerbreak();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -399,6 +399,23 @@
|
||||
<controls:UserInput x:Name="FullyMatchedID" Label="Fully Matched ID" IsReadOnly="True"
|
||||
Text="{Binding SubmissionInfo.FullyMatchedID, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="PartiallyMatchedIDs" Label="Partially Matched ID(s)" IsReadOnly="True"/>
|
||||
<controls:UserInput x:Name="HashData" Label="Hash Data" IsReadOnly="True"
|
||||
Text="{Binding SubmissionInfo.TracksAndWriteOffsets.ClrMameProData, Mode=TwoWay}" TextHeight="75" TextWrapping="NoWrap"
|
||||
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
|
||||
<controls:UserInput x:Name="HashDataSize" Label="Size" IsReadOnly="True"
|
||||
Text="{Binding SubmissionInfo.SizeAndChecksums.Size, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="HashDataCRC" Label="CRC-32" IsReadOnly="True"
|
||||
Text="{Binding SubmissionInfo.SizeAndChecksums.CRC32, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="HashDataMD5" Label="MD5" IsReadOnly="True"
|
||||
Text="{Binding SubmissionInfo.SizeAndChecksums.MD5, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="HashDataSHA1" Label="SHA-1" IsReadOnly="True"
|
||||
Text="{Binding SubmissionInfo.SizeAndChecksums.SHA1, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="HashDataLayerbreak1" Label="Layerbreak 1" IsReadOnly="True"
|
||||
Text="{Binding SubmissionInfo.SizeAndChecksums.Layerbreak, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="HashDataLayerbreak2" Label="Layerbreak 2" IsReadOnly="True"
|
||||
Text="{Binding SubmissionInfo.SizeAndChecksums.Layerbreak2, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="HashDataLayerbreak3" Label="Layerbreak 3" IsReadOnly="True"
|
||||
Text="{Binding SubmissionInfo.SizeAndChecksums.Layerbreak3, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="AntiModchip" Label="Anti-Modchip" IsReadOnly="True"
|
||||
Text="{Binding SubmissionInfo.CopyProtection.AntiModchip, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="DiscOffset" Label="Disc Offset" IsReadOnly="True"
|
||||
|
||||
@@ -77,6 +77,14 @@ namespace MPF.UI.Core.Windows
|
||||
|
||||
private UserInput? _FullyMatchedID => ItemHelper.FindChild<UserInput>(this, "FullyMatchedID");
|
||||
private UserInput? _PartiallyMatchedIDs => ItemHelper.FindChild<UserInput>(this, "PartiallyMatchedIDs");
|
||||
private UserInput? _HashData => ItemHelper.FindChild<UserInput>(this, "HashData");
|
||||
private UserInput? _HashDataSize => ItemHelper.FindChild<UserInput>(this, "HashDataSize");
|
||||
private UserInput? _HashDataCRC => ItemHelper.FindChild<UserInput>(this, "HashDataCRC");
|
||||
private UserInput? _HashDataMD5 => ItemHelper.FindChild<UserInput>(this, "HashDataMD5");
|
||||
private UserInput? _HashDataSHA1 => ItemHelper.FindChild<UserInput>(this, "HashDataSHA1");
|
||||
private UserInput? _HashDataLayerbreak1 => ItemHelper.FindChild<UserInput>(this, "HashDataLayerbreak1");
|
||||
private UserInput? _HashDataLayerbreak2 => ItemHelper.FindChild<UserInput>(this, "HashDataLayerbreak2");
|
||||
private UserInput? _HashDataLayerbreak3 => ItemHelper.FindChild<UserInput>(this, "HashDataLayerbreak3");
|
||||
private UserInput? _AntiModchip => ItemHelper.FindChild<UserInput>(this, "AntiModchip");
|
||||
private UserInput? _DiscOffset => ItemHelper.FindChild<UserInput>(this, "DiscOffset");
|
||||
private UserInput? _DMIHash => ItemHelper.FindChild<UserInput>(this, "DMIHash");
|
||||
@@ -295,6 +303,22 @@ namespace MPF.UI.Core.Windows
|
||||
_PartiallyMatchedIDs!.Visibility = Visibility.Collapsed;
|
||||
else
|
||||
_PartiallyMatchedIDs!.Text = string.Join(", ", submissionInfo.PartiallyMatchedIDs.Select(i => i.ToString()).ToArray());
|
||||
if (string.IsNullOrEmpty(submissionInfo.TracksAndWriteOffsets?.ClrMameProData))
|
||||
_HashData!.Visibility = Visibility.Collapsed;
|
||||
if (submissionInfo.SizeAndChecksums?.Size == null || submissionInfo.SizeAndChecksums.Size == 0)
|
||||
_HashDataSize!.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrEmpty(submissionInfo.SizeAndChecksums?.CRC32))
|
||||
_HashDataCRC!.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrEmpty(submissionInfo.SizeAndChecksums?.MD5))
|
||||
_HashDataMD5!.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrEmpty(submissionInfo.SizeAndChecksums?.SHA1))
|
||||
_HashDataSHA1!.Visibility = Visibility.Collapsed;
|
||||
if (submissionInfo.SizeAndChecksums?.Layerbreak == null || submissionInfo.SizeAndChecksums.Layerbreak == 0)
|
||||
_HashDataLayerbreak1!.Visibility = Visibility.Collapsed;
|
||||
if (submissionInfo.SizeAndChecksums?.Layerbreak2 == null || submissionInfo.SizeAndChecksums.Layerbreak2 == 0)
|
||||
_HashDataLayerbreak2!.Visibility = Visibility.Collapsed;
|
||||
if (submissionInfo.SizeAndChecksums?.Layerbreak3 == null || submissionInfo.SizeAndChecksums.Layerbreak3 == 0)
|
||||
_HashDataLayerbreak3!.Visibility = Visibility.Collapsed;
|
||||
if (submissionInfo.CopyProtection?.AntiModchip == null)
|
||||
_AntiModchip!.Visibility = Visibility.Collapsed;
|
||||
if (submissionInfo.TracksAndWriteOffsets?.OtherWriteOffsets == null)
|
||||
@@ -352,6 +376,22 @@ namespace MPF.UI.Core.Windows
|
||||
PartiallyMatchedIDs.Visibility = Visibility.Collapsed;
|
||||
else
|
||||
PartiallyMatchedIDs.Text = string.Join(", ", submissionInfo.PartiallyMatchedIDs.Select(i => i.ToString()).ToArray());
|
||||
if (string.IsNullOrEmpty(submissionInfo.TracksAndWriteOffsets?.ClrMameProData))
|
||||
HashData!.Visibility = Visibility.Collapsed;
|
||||
if (submissionInfo.SizeAndChecksums?.Size == null)
|
||||
HashDataSize!.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrEmpty(submissionInfo.SizeAndChecksums?.CRC32))
|
||||
HashDataCRC!.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrEmpty(submissionInfo.SizeAndChecksums?.MD5))
|
||||
HashDataMD5!.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrEmpty(submissionInfo.SizeAndChecksums?.SHA1))
|
||||
HashDataSHA1!.Visibility = Visibility.Collapsed;
|
||||
if (submissionInfo.SizeAndChecksums?.Layerbreak == null || submissionInfo.SizeAndChecksums.Layerbreak == 0)
|
||||
HashDataLayerbreak1!.Visibility = Visibility.Collapsed;
|
||||
if (submissionInfo.SizeAndChecksums?.Layerbreak2 == null || submissionInfo.SizeAndChecksums.Layerbreak2 == 0)
|
||||
HashDataLayerbreak2!.Visibility = Visibility.Collapsed;
|
||||
if (submissionInfo.SizeAndChecksums?.Layerbreak3 == null || submissionInfo.SizeAndChecksums.Layerbreak3 == 0)
|
||||
HashDataLayerbreak3!.Visibility = Visibility.Collapsed;
|
||||
if (submissionInfo.CopyProtection?.AntiModchip == null)
|
||||
AntiModchip.Visibility = Visibility.Collapsed;
|
||||
if (submissionInfo.TracksAndWriteOffsets?.OtherWriteOffsets == null)
|
||||
@@ -437,16 +477,16 @@ namespace MPF.UI.Core.Windows
|
||||
|
||||
#if NET35
|
||||
_L1Info!.Header = "Label Side";
|
||||
_L1MasteringRing!.Visibility = Visibility.Collapsed;
|
||||
_L1MasteringSID!.Visibility = Visibility.Collapsed;
|
||||
_L1Toolstamp!.Visibility = Visibility.Collapsed;
|
||||
_L1MasteringRing!.Label = "Mastering Ring";
|
||||
_L1MasteringSID!.Label = "Mastering SID";
|
||||
_L1Toolstamp!.Label = "Mastering SID";
|
||||
_L1MouldSID!.Label = "Mould SID";
|
||||
_L1AdditionalMould!.Label = "Additional Mould";
|
||||
#else
|
||||
L1Info.Header = "Label Side";
|
||||
L1MasteringRing.Visibility = Visibility.Collapsed;
|
||||
L1MasteringSID.Visibility = Visibility.Collapsed;
|
||||
L1Toolstamp.Visibility = Visibility.Collapsed;
|
||||
L1MasteringRing.Label = "Mastering Ring";
|
||||
L1MasteringSID.Label = "Mastering SID";
|
||||
L1Toolstamp.Label = "Mastering SID";
|
||||
L1MouldSID.Label = "Mould SID";
|
||||
L1AdditionalMould.Label = "Additional Mould";
|
||||
#endif
|
||||
@@ -647,16 +687,16 @@ namespace MPF.UI.Core.Windows
|
||||
|
||||
#if NET35
|
||||
_L1Info!.Header = "Label Side";
|
||||
_L1MasteringRing!.Visibility = Visibility.Collapsed;
|
||||
_L1MasteringSID!.Visibility = Visibility.Collapsed;
|
||||
_L1Toolstamp!.Visibility = Visibility.Collapsed;
|
||||
_L1MasteringRing!.Label = "Mastering Ring";
|
||||
_L1MasteringSID!.Label = "Mastering SID";
|
||||
_L1Toolstamp!.Label = "Toolstamp/Mastering Code";
|
||||
_L1MouldSID!.Label = "Mould SID";
|
||||
_L1AdditionalMould!.Label = "Additional Mould";
|
||||
#else
|
||||
L1Info.Header = "Label Side";
|
||||
L1MasteringRing.Visibility = Visibility.Collapsed;
|
||||
L1MasteringSID.Visibility = Visibility.Collapsed;
|
||||
L1Toolstamp.Visibility = Visibility.Collapsed;
|
||||
L1MasteringRing.Label = "Mastering Ring";
|
||||
L1MasteringSID.Label = "Mastering SID";
|
||||
L1Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
L1MouldSID.Label = "Mould SID";
|
||||
L1AdditionalMould.Label = "Additional Mould";
|
||||
#endif
|
||||
|
||||
@@ -54,6 +54,11 @@
|
||||
Foreground="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
|
||||
Template="{DynamicResource CustomMenuItemTemplate}"
|
||||
IsEnabled="{Binding CheckDumpMenuItemEnabled}"/>
|
||||
<MenuItem x:Name="CreateIRDMenuItem" Header="_Create PS3 IRD" HorizontalAlignment="Left" Width="185"
|
||||
Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
|
||||
Foreground="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
|
||||
Template="{DynamicResource CustomMenuItemTemplate}"
|
||||
IsEnabled="{Binding CreateIRDMenuItemEnabled}"/>
|
||||
<MenuItem x:Name="OptionsMenuItem" Header="_Options" HorizontalAlignment="Left" Width="185"
|
||||
Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
|
||||
Foreground="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace MPF.UI.Core.Windows
|
||||
private MenuItem? _CheckForUpdatesMenuItem => ItemHelper.FindChild<MenuItem>(this, "CheckForUpdatesMenuItem");
|
||||
private MenuItem? _DebugViewMenuItem => ItemHelper.FindChild<MenuItem>(this, "DebugViewMenuItem");
|
||||
private MenuItem? _CheckDumpMenuItem => ItemHelper.FindChild<MenuItem>(this, "CheckDumpMenuItem");
|
||||
private MenuItem? _CreateIRDMenuItem => ItemHelper.FindChild<MenuItem>(this, "CreateIRDMenuItem");
|
||||
private MenuItem? _OptionsMenuItem => ItemHelper.FindChild<MenuItem>(this, "OptionsMenuItem");
|
||||
|
||||
#endregion
|
||||
@@ -141,6 +142,7 @@ namespace MPF.UI.Core.Windows
|
||||
_CheckForUpdatesMenuItem!.Click += CheckForUpdatesClick;
|
||||
_DebugViewMenuItem!.Click += DebugViewClick;
|
||||
_CheckDumpMenuItem!.Click += CheckDumpMenuItemClick;
|
||||
_CreateIRDMenuItem!.Click += CreateIRDMenuItemClick;
|
||||
_OptionsMenuItem!.Click += OptionsMenuItemClick;
|
||||
#else
|
||||
AboutMenuItem.Click += AboutClick;
|
||||
@@ -148,6 +150,7 @@ namespace MPF.UI.Core.Windows
|
||||
CheckForUpdatesMenuItem.Click += CheckForUpdatesClick;
|
||||
DebugViewMenuItem.Click += DebugViewClick;
|
||||
CheckDumpMenuItem.Click += CheckDumpMenuItemClick;
|
||||
CreateIRDMenuItem.Click += CreateIRDMenuItemClick;
|
||||
OptionsMenuItem.Click += OptionsMenuItemClick;
|
||||
#endif
|
||||
|
||||
@@ -341,6 +344,31 @@ namespace MPF.UI.Core.Windows
|
||||
checkDumpWindow.Show();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show the Create IRD window
|
||||
/// </summary>
|
||||
public void ShowCreateIRDWindow()
|
||||
{
|
||||
// Hide MainWindow while Create IRD UI is open
|
||||
this.Hide();
|
||||
|
||||
var createIRDWindow = new CreateIRDWindow(this)
|
||||
{
|
||||
Focusable = true,
|
||||
Owner = this,
|
||||
ShowActivated = true,
|
||||
ShowInTaskbar = true,
|
||||
WindowStartupLocation = WindowStartupLocation.CenterOwner,
|
||||
};
|
||||
|
||||
createIRDWindow.Closed += delegate {
|
||||
// Unhide Main window after Create IRD window has been closed
|
||||
this.Show();
|
||||
this.Activate();
|
||||
};
|
||||
createIRDWindow.Show();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show the Options window
|
||||
/// </summary>
|
||||
@@ -420,6 +448,12 @@ namespace MPF.UI.Core.Windows
|
||||
public void CheckDumpMenuItemClick(object sender, RoutedEventArgs e) =>
|
||||
ShowCheckDumpWindow();
|
||||
|
||||
/// <summary>
|
||||
/// Handler for CreateIRDMenuItem Click event
|
||||
/// </summary>
|
||||
public void CreateIRDMenuItemClick(object sender, RoutedEventArgs e) =>
|
||||
ShowCreateIRDWindow();
|
||||
|
||||
/// <summary>
|
||||
/// Handler for CheckForUpdatesMenuItem Click event
|
||||
/// </summary>
|
||||
|
||||
@@ -191,7 +191,7 @@
|
||||
<TabItem Header="Dumping" Style="{DynamicResource CustomTabItemStyle}">
|
||||
<StackPanel>
|
||||
<GroupBox Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Dumping">
|
||||
<UniformGrid Columns="2" Rows="7">
|
||||
<UniformGrid Columns="2" Rows="8">
|
||||
<CheckBox VerticalAlignment="Center" Content="Show Separate Window"
|
||||
IsChecked="{Binding Options.ToolsInSeparateWindow}"
|
||||
ToolTip="Show program output in separate command window instead of in the log. Enable this if you have a weaker system as there is an increased processing load otherwise." Margin="0,4"
|
||||
@@ -261,6 +261,11 @@
|
||||
IsChecked="{Binding Options.DeleteUnnecessaryFiles}"
|
||||
ToolTip="Delete unnecesary output files to reduce space" Margin="0,4"
|
||||
/>
|
||||
|
||||
<CheckBox VerticalAlignment="Center" Content="Create PS3 IRD After Dumping"
|
||||
IsChecked="{Binding Options.CreateIRDAfterDumping}"
|
||||
ToolTip="Automatically creates an IRD file after dumping a PS3 disc" Margin="0,4"
|
||||
/>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
|
||||
@@ -365,7 +370,7 @@
|
||||
/>
|
||||
|
||||
<Label Content="Reread Tries:" VerticalAlignment="Center" HorizontalAlignment="Right"/>
|
||||
<TextBox VerticalAlignment="Center" VerticalContentAlignment="Center"
|
||||
<TextBox VerticalAlignment="Center" VerticalContentAlignment="Center" Width="200" HorizontalAlignment="Left"
|
||||
Text="{Binding Options.AaruRereadCount}"
|
||||
ToolTip="Specifies how many rereads are attempted for sector and subchannel errors"
|
||||
/>
|
||||
@@ -401,19 +406,19 @@
|
||||
<Label/> <!-- Empty label for padding -->
|
||||
|
||||
<Label Content="Multi-Sector Read Value:" VerticalAlignment="Center" HorizontalAlignment="Right"/>
|
||||
<TextBox VerticalAlignment="Center" VerticalContentAlignment="Center"
|
||||
<TextBox VerticalAlignment="Center" VerticalContentAlignment="Center" Width="200" HorizontalAlignment="Left"
|
||||
Text="{Binding Options.DICMultiSectorReadValue}" IsEnabled="{Binding Options.DICMultiSectorRead}"
|
||||
ToolTip="Set the default value for the /mr flag"
|
||||
/>
|
||||
|
||||
<Label Content="CD Reread Tries:" VerticalAlignment="Center" HorizontalAlignment="Right"/>
|
||||
<TextBox VerticalAlignment="Center" VerticalContentAlignment="Center"
|
||||
<TextBox VerticalAlignment="Center" VerticalContentAlignment="Center" Width="200" HorizontalAlignment="Left"
|
||||
Text="{Binding Options.DICRereadCount}"
|
||||
ToolTip="Specifies how many rereads are attempted on C2 error [CD only]"
|
||||
/>
|
||||
|
||||
<Label Content="DVD/HD-DVD/BD Reread Tries:" VerticalAlignment="Center" HorizontalAlignment="Right"/>
|
||||
<TextBox VerticalAlignment="Center" VerticalContentAlignment="Center"
|
||||
<TextBox VerticalAlignment="Center" VerticalContentAlignment="Center" Width="200" HorizontalAlignment="Left"
|
||||
Text="{Binding Options.DICDVDRereadCount}"
|
||||
ToolTip="Specifies how many rereads are attempted on read error [DVD/HD-DVD/BD only]"
|
||||
/>
|
||||
@@ -421,7 +426,7 @@
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Redumper">
|
||||
<UniformGrid Columns="2" Rows="3">
|
||||
<UniformGrid Columns="2" Rows="5">
|
||||
<CheckBox VerticalAlignment="Center" Content="Enable Debug Output"
|
||||
IsChecked="{Binding Options.RedumperEnableDebug}"
|
||||
ToolTip="Enable debug output in logs" Margin="0,4"
|
||||
@@ -432,20 +437,32 @@
|
||||
ToolTip="Enable verbose output in logs" Margin="0,4"
|
||||
/>
|
||||
|
||||
<CheckBox VerticalAlignment="Center" Content="Enable BE Drive Reading"
|
||||
IsChecked="{Binding Options.RedumperUseBEReading}"
|
||||
ToolTip="Enable setting drive read method to BE_CDDA by default" Margin="0,4"
|
||||
<Label Content="Reread Tries:" VerticalAlignment="Center" HorizontalAlignment="Right"/>
|
||||
<TextBox VerticalAlignment="Center" VerticalContentAlignment="Center" Width="200" HorizontalAlignment="Left"
|
||||
Text="{Binding Options.RedumperRereadCount}"
|
||||
ToolTip="Specifies how many rereads are attempted on read error"
|
||||
/>
|
||||
|
||||
<CheckBox VerticalAlignment="Center" Content="Non-Redump Options" Click="NonRedumpModeClicked"
|
||||
IsChecked="{Binding Options.RedumperNonRedumpMode}"
|
||||
ToolTip="Enable non-redump options" Margin="0,4"
|
||||
/>
|
||||
|
||||
<CheckBox VerticalAlignment="Center" Content="Set Generic Drive Type"
|
||||
IsChecked="{Binding Options.RedumperUseGenericDriveType}"
|
||||
IsChecked="{Binding Options.RedumperUseGenericDriveType}" IsEnabled="{Binding Options.RedumperNonRedumpMode}"
|
||||
ToolTip="Enable setting drive type to Generic by default" Margin="0,4"
|
||||
/>
|
||||
|
||||
<Label Content="Reread Tries:" VerticalAlignment="Center" HorizontalAlignment="Right"/>
|
||||
<TextBox VerticalAlignment="Center" VerticalContentAlignment="Center"
|
||||
Text="{Binding Options.RedumperRereadCount}"
|
||||
ToolTip="Specifies how many rereads are attempted on read error"
|
||||
<Label VerticalAlignment="Center" Content="Default Read Method:" HorizontalAlignment="Right" />
|
||||
<ComboBox x:Name="DefaultRedumperReadMethodComboBox" Height="22" Width="200" HorizontalAlignment="Left"
|
||||
ItemsSource="{Binding RedumperReadMethods}" SelectedItem="{Binding Options.RedumperReadMethod, Converter={StaticResource ElementConverter}, Mode=TwoWay}"
|
||||
Style="{DynamicResource CustomComboBoxStyle}" IsEnabled="{Binding Options.RedumperNonRedumpMode}"
|
||||
/>
|
||||
|
||||
<Label VerticalAlignment="Center" Content="Default Sector Order:" HorizontalAlignment="Right" />
|
||||
<ComboBox x:Name="DefaultRedumperSectorOrderComboBox" Height="22" Width="200" HorizontalAlignment="Left"
|
||||
ItemsSource="{Binding RedumperSectorOrders}" SelectedItem="{Binding Options.RedumperSectorOrder, Converter={StaticResource ElementConverter}, Mode=TwoWay}"
|
||||
Style="{DynamicResource CustomComboBoxStyle}" IsEnabled="{Binding Options.RedumperNonRedumpMode}"
|
||||
/>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
|
||||
@@ -214,7 +214,7 @@ namespace MPF.UI.Core.Windows
|
||||
CustomMessageBox.Show(this, message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
@@ -224,6 +224,17 @@ namespace MPF.UI.Core.Windows
|
||||
private void BrowseForPathClick(object sender, EventArgs e) =>
|
||||
BrowseForPath(this, sender as System.Windows.Controls.Button);
|
||||
|
||||
/// <summary>
|
||||
/// Alert user of non-redump mode implications
|
||||
/// </summary>
|
||||
private void NonRedumpModeClicked(object sender, EventArgs e)
|
||||
{
|
||||
if (OptionsViewModel.Options.RedumperNonRedumpMode)
|
||||
CustomMessageBox.Show(this, "All logs generated with these options will not be acceptable for Redump submission", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
else
|
||||
OptionsViewModel.NonRedumpModeUnChecked();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for AcceptButton Click event
|
||||
/// </summary>
|
||||
|
||||
19
MPF.sln
19
MPF.sln
@@ -13,9 +13,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
appveyor.yml = appveyor.yml
|
||||
CHANGELIST.md = CHANGELIST.md
|
||||
.github\ISSUE_TEMPLATE\feature-request.md = .github\ISSUE_TEMPLATE\feature-request.md
|
||||
.github\ISSUE_TEMPLATE\informational.md = .github\ISSUE_TEMPLATE\informational.md
|
||||
.github\ISSUE_TEMPLATE\issue-report.md = .github\ISSUE_TEMPLATE\issue-report.md
|
||||
publish-nix.sh = publish-nix.sh
|
||||
publish-win.ps1 = publish-win.ps1
|
||||
README.md = README.md
|
||||
@@ -27,6 +24,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MPF.UI.Core", "MPF.UI.Core\
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MPF", "MPF", "{4160167D-681D-480B-ABC6-06AC869E5769}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ISSUE_TEMPLATE", "ISSUE_TEMPLATE", "{ADC5FDD7-F43F-4F9C-B222-19AA1D64D3D4}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.github\ISSUE_TEMPLATE\feature-request.md = .github\ISSUE_TEMPLATE\feature-request.md
|
||||
.github\ISSUE_TEMPLATE\informational.md = .github\ISSUE_TEMPLATE\informational.md
|
||||
.github\ISSUE_TEMPLATE\issue-report.md = .github\ISSUE_TEMPLATE\issue-report.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{440776E0-E6E2-46C6-8E85-09E64A8FC7D6}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.github\workflows\build_check.yml = .github\workflows\build_check.yml
|
||||
.github\workflows\build_ui.yml = .github\workflows\build_ui.yml
|
||||
.github\workflows\check_pr.yml = .github\workflows\check_pr.yml
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -63,6 +74,8 @@ Global
|
||||
{8CFDE289-E171-4D49-A40D-5293265C1253} = {4160167D-681D-480B-ABC6-06AC869E5769}
|
||||
{70B1265D-FE49-472A-A83D-0B462152D37A} = {4160167D-681D-480B-ABC6-06AC869E5769}
|
||||
{EA3768DB-694A-4653-82E4-9FF71B8963F3} = {4160167D-681D-480B-ABC6-06AC869E5769}
|
||||
{ADC5FDD7-F43F-4F9C-B222-19AA1D64D3D4} = {4D1DCF5A-F0B0-4E81-A05B-F1A7D37C9D9D}
|
||||
{440776E0-E6E2-46C6-8E85-09E64A8FC7D6} = {4D1DCF5A-F0B0-4E81-A05B-F1A7D37C9D9D}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {73C62E6A-6584-4D93-83B5-ECB1FBDB469B}
|
||||
|
||||
@@ -2,20 +2,21 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0-windows;net6.0-windows;net7.0-windows;net8.0-windows</TargetFrameworks>
|
||||
<TargetFrameworks>net40;net452;net462;net472;net48;netcoreapp3.1;net5.0-windows;net6.0-windows;net7.0-windows;net8.0-windows</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<ApplicationIcon>Images\Icon.ico</ApplicationIcon>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<ImportFrameworkWinFXTargets Condition="$(TargetFramework.StartsWith(`net3`))">true</ImportFrameworkWinFXTargets>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<VersionPrefix>3.1.0</VersionPrefix>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<UseWPF>true</UseWPF>
|
||||
<VersionPrefix>3.1.6</VersionPrefix>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
@@ -69,10 +70,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BinaryObjectScanner" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="3.0.2" GeneratePathProperty="true">
|
||||
<PackageReference Include="BinaryObjectScanner" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="3.1.8" GeneratePathProperty="true">
|
||||
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="1.3.2" />
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="1.3.6" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
24
README.md
24
README.md
@@ -2,7 +2,9 @@
|
||||
|
||||
Redumper/Aaru/DiscImageCreator UI in C#
|
||||
|
||||
[](https://ci.appveyor.com/project/mnadareski/MPF/build/artifacts)
|
||||
[](https://ci.appveyor.com/project/mnadareski/MPF)
|
||||
[](https://github.com/SabreTools/MPF/actions/workflows/build_ui.yml)
|
||||
[](https://github.com/SabreTools/MPF/actions/workflows/build_check.yml)
|
||||
|
||||
This is a community project, so if you have some time and knowledge to give, we'll be glad to add you as a contributor to this project. If you have any suggestions, issues, bugs, or crashes, please look at the [Issues](https://github.com/SabreTools/MPF/issues) page first to see if it has been reported before and try out the latest AppVeyor WIP build below to see if it has already been addressed. If it hasn't, please open an issue that's as descriptive as you can be. Help me make this a better program for everyone :)
|
||||
|
||||
@@ -10,7 +12,7 @@ This is a community project, so if you have some time and knowledge to give, we'
|
||||
|
||||
For the most recent stable build, download the latest release here: [Releases Page](https://github.com/SabreTools/MPF/releases)
|
||||
|
||||
For the latest AppVeyor WIP build here: [AppVeyor](https://ci.appveyor.com/project/mnadareski/MPF/build/artifacts)
|
||||
For the latest WIP build here: [Rolling Release](https://github.com/SabreTools/MPF/releases/tag/rolling)
|
||||
|
||||
## Media Preservation Frontend UI (MPF)
|
||||
|
||||
@@ -33,8 +35,6 @@ MPF.Check is a commandline-only program that allows users to generate submission
|
||||
|
||||
Both MPF UI and MPF.Check have the same system requirements for running, with the exception that MPF UI is Windows-only.
|
||||
|
||||
- [Supported OS versions for .NET 6](https://github.com/dotnet/core/blob/main/release-notes/6.0/supported-os.md)
|
||||
- Requires [.NET 6.0 Runtime](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) if built without bundled runtime
|
||||
- [Supported OS versions for .NET 8](https://github.com/dotnet/core/blob/main/release-notes/8.0/supported-os.md)
|
||||
- Requires [.NET 8.0 Runtime](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) if built without bundled runtime
|
||||
|
||||
@@ -42,30 +42,28 @@ Ensure that your operating system and runtimes are as up-to-date as possible, si
|
||||
|
||||
## Build Instructions
|
||||
|
||||
To build for .NET 6.0 or .NET 8.0, ensure that the [.NET 8.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) (or later) is installed and included in your `PATH`. Then, run the following commands from command prompt, Powershell, Terminal, or shell:
|
||||
To build for .NET 8.0, ensure that the [.NET 8.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) (or later) is installed and included in your `PATH`. Then, run the following commands from command prompt, Powershell, Terminal, or shell:
|
||||
|
||||
**MPF UI (Windows only):**
|
||||
|
||||
```bash
|
||||
dotnet build MPF/MPF.csproj --framework [net6.0-windows|net8.0-windows] --runtime win-x64
|
||||
dotnet build MPF/MPF.csproj --framework net8.0-windows --runtime [win-x86|win-x64]
|
||||
```
|
||||
|
||||
**MPF.Check (Windows, OSX, Linux):**
|
||||
|
||||
```bash
|
||||
dotnet build MPF.Check/MPF.Check.csproj --framework [net6.0|net8.0] --runtime [win-x64|linux-x64|osx-x64]
|
||||
dotnet build MPF.Check/MPF.Check.csproj --framework net8.0 --runtime [win-x86|win-x64|linux-x64|osx-x64]
|
||||
```
|
||||
|
||||
Choose one of `win-x64`, `linux-x64`, or `osx-x64` depending on the machine you are targeting.
|
||||
Choose one of `win-x86`, `win-x64`, `linux-x64`, or `osx-x64` depending on the machine you are targeting.
|
||||
|
||||
### Build Scripts
|
||||
|
||||
Windows users may run `publish-win.ps1` and Linux users may run `publish-nix.sh` to perform a full release build.
|
||||
Windows users may run `publish-win.ps1` and Linux users may run `publish-nix.sh` to perform a full release build. Both scripts will build and package all variants of MPF UI and MPF.Check with commandline switches to control what is included.
|
||||
|
||||
- `publish-win.ps1` will build and package all variants of MPF UI and MPF.Check
|
||||
- The script requires [7-zip commandline](https://www.7-zip.org/download.html) and [Git for Windows](https://git-scm.com/downloads) to be installed and in `PATH`
|
||||
- `publish-nix.sh` will _only_ build and package all variants of MPF.Check
|
||||
- The script requires `zip` and `git` to be installed and in `PATH`
|
||||
- `publish-win.ps1` requires [7-zip commandline](https://www.7-zip.org/download.html) and [Git for Windows](https://git-scm.com/downloads) to be installed and in `PATH`
|
||||
- `publish-nix.sh` requires `zip` and `git` to be installed and in `PATH`
|
||||
|
||||
## Information
|
||||
|
||||
|
||||
69
appveyor.yml
69
appveyor.yml
@@ -1,5 +1,5 @@
|
||||
# version format
|
||||
version: 3.1.0-{build}
|
||||
version: 3.1.6-{build}
|
||||
|
||||
# pull request template
|
||||
pull_requests:
|
||||
@@ -10,58 +10,7 @@ image: Visual Studio 2022
|
||||
|
||||
# build step
|
||||
build_script:
|
||||
- dotnet restore
|
||||
|
||||
# .NET 6.0 Debug
|
||||
- dotnet publish MPF\MPF.csproj -f net6.0-windows -r win-x64 -c Debug --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true
|
||||
- dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r win-x64 -c Debug --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true
|
||||
- dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r linux-x64 -c Debug --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true
|
||||
- dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r osx-x64 -c Debug --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true
|
||||
|
||||
# .NET 6.0 Release
|
||||
- dotnet publish MPF\MPF.csproj -f net6.0-windows -r win-x64 -c Release --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
|
||||
- dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r win-x64 -c Release --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
|
||||
- dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r linux-x64 -c Release --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
|
||||
- dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r osx-x64 -c Release --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
|
||||
|
||||
# .NET 8.0 Debug
|
||||
- dotnet publish MPF\MPF.csproj -f net8.0-windows -r win-x64 -c Debug --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true
|
||||
- dotnet publish MPF.Check\MPF.Check.csproj -f net8.0 -r win-x64 -c Debug --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true
|
||||
- dotnet publish MPF.Check\MPF.Check.csproj -f net8.0 -r linux-x64 -c Debug --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true
|
||||
- dotnet publish MPF.Check\MPF.Check.csproj -f net8.0 -r osx-x64 -c Debug --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true
|
||||
|
||||
# .NET 8.0 Release
|
||||
- dotnet publish MPF\MPF.csproj -f net8.0-windows -r win-x64 -c Release --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
|
||||
- dotnet publish MPF.Check\MPF.Check.csproj -f net8.0 -r win-x64 -c Release --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
|
||||
- dotnet publish MPF.Check\MPF.Check.csproj -f net8.0 -r linux-x64 -c Release --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
|
||||
- dotnet publish MPF.Check\MPF.Check.csproj -f net8.0 -r osx-x64 -c Release --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
|
||||
|
||||
# post-build step
|
||||
after_build:
|
||||
|
||||
# Aaru
|
||||
- ps: appveyor DownloadFile https://github.com/aaru-dps/Aaru/releases/download/v5.3.2/aaru-5.3.2_windows_x64.zip
|
||||
- 7z x aaru-5.3.2_windows_x64.zip -oMPF\bin\Debug\net8.0-windows\win-x64\publish\Programs\Aaru *
|
||||
|
||||
# DiscImageCreator
|
||||
- ps: appveyor DownloadFile https://github.com/saramibreak/DiscImageCreator/files/11660558/DiscImageCreator_20230606.zip
|
||||
- 7z e DiscImageCreator_20230606.zip -oMPF\bin\Debug\net8.0-windows\win-x64\publish\Programs\Creator Release_ANSI\*
|
||||
|
||||
# Redumper
|
||||
- ps: appveyor DownloadFile https://github.com/superg/redumper/releases/download/build_311/redumper-2024.01.08_build311-win64.zip
|
||||
- 7z e redumper-2024.01.08_build311-win64.zip -oMPF\bin\Debug\net8.0-windows\win-x64\publish\Programs\Redumper redumper-2024.01.08_build311-win64\bin\*
|
||||
|
||||
# Create MPF Debug archives
|
||||
- cd %APPVEYOR_BUILD_FOLDER%\MPF\bin\Debug\net8.0-windows\win-x64\publish\
|
||||
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF_%APPVEYOR_BUILD_NUMBER%_net8.0_win-x64_debug.zip *
|
||||
|
||||
# Create MPF.Check Debug archives
|
||||
- cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Debug\net8.0\win-x64\publish\
|
||||
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_%APPVEYOR_BUILD_NUMBER%_net8.0_win-x64_debug.zip *
|
||||
- cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Debug\net8.0\linux-x64\publish\
|
||||
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_%APPVEYOR_BUILD_NUMBER%_net8.0_linux-x64_debug.zip *
|
||||
- cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Debug\net8.0\osx-x64\publish\
|
||||
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_%APPVEYOR_BUILD_NUMBER%_net8.0_osx-x64_debug.zip *
|
||||
- dotnet build
|
||||
|
||||
# success/failure tracking
|
||||
on_success:
|
||||
@@ -69,16 +18,4 @@ on_success:
|
||||
- ps: ./send.ps1 success $env:WEBHOOK_URL
|
||||
on_failure:
|
||||
- ps: Invoke-RestMethod https://raw.githubusercontent.com/DiscordHooks/appveyor-discord-webhook/master/send.ps1 -o send.ps1
|
||||
- ps: ./send.ps1 failure $env:WEBHOOK_URL
|
||||
|
||||
# artifact linking
|
||||
artifacts:
|
||||
- path: MPF_%APPVEYOR_BUILD_NUMBER%_net8.0_win-x64_debug.zip
|
||||
name: MPF (.NET 8.0, Debug, Windows x64)
|
||||
|
||||
- path: MPF.Check_%APPVEYOR_BUILD_NUMBER%_net8.0_win-x64_debug.zip
|
||||
name: MPF.Check (.NET 8.0, Debug, Windows x64)
|
||||
- path: MPF.Check_%APPVEYOR_BUILD_NUMBER%_net8.0_linux-x64_debug.zip
|
||||
name: MPF.Check (.NET 8.0, Debug, Linux x64)
|
||||
- path: MPF.Check_%APPVEYOR_BUILD_NUMBER%_net8.0_osx-x64_debug.zip
|
||||
name: MPF.Check (.NET 8.0, Debug, OSX x64)
|
||||
- ps: ./send.ps1 failure $env:WEBHOOK_URL
|
||||
127
publish-nix.sh
127
publish-nix.sh
@@ -12,12 +12,11 @@
|
||||
|
||||
# Optional parameters
|
||||
USE_ALL=false
|
||||
INCLUDE_PROGRAMS=false # TODO: Figure out how to exclude folders with `zip`
|
||||
INCLUDE_PROGRAMS=false
|
||||
NO_BUILD=false
|
||||
NO_ARCHIVE=false
|
||||
while getopts "upba" OPTION
|
||||
do
|
||||
case $OPTION in
|
||||
while getopts "upba" OPTION; do
|
||||
case $OPTION in
|
||||
u)
|
||||
USE_ALL=true
|
||||
;;
|
||||
@@ -41,17 +40,16 @@ done
|
||||
BUILD_FOLDER=$PWD
|
||||
|
||||
# Set the current commit hash
|
||||
COMMIT=`git log --pretty=%H -1`
|
||||
COMMIT=$(git log --pretty=%H -1)
|
||||
|
||||
# Create the build matrix arrays
|
||||
UI_FRAMEWORKS=("net6.0-windows" "net8.0-windows")
|
||||
UI_RUNTIMES=("win-x64")
|
||||
CHECK_FRAMEWORKS=("net6.0" "net8.0")
|
||||
CHECK_RUNTIMES=("win-x64" "linux-x64" "osx-x64")
|
||||
UI_FRAMEWORKS=("net8.0-windows")
|
||||
UI_RUNTIMES=("win-x86" "win-x64")
|
||||
CHECK_FRAMEWORKS=("net8.0")
|
||||
CHECK_RUNTIMES=("win-x86" "win-x64" "linux-x64" "osx-x64")
|
||||
|
||||
# Use expanded lists, if requested
|
||||
if [ $USE_ALL = true ]
|
||||
then
|
||||
if [ $USE_ALL = true ]; then
|
||||
UI_FRAMEWORKS=("net40" "net452" "net462" "net472" "net48" "netcoreapp3.1" "net5.0-windows" "net6.0-windows" "net7.0-windows" "net8.0-windows")
|
||||
UI_RUNTIMES=("win-x86" "win-x64")
|
||||
CHECK_FRAMEWORKS=("net20" "net35" "net40" "net452" "net462" "net472" "net48" "netcoreapp3.1" "net5.0" "net6.0" "net7.0" "net8.0")
|
||||
@@ -64,50 +62,60 @@ VALID_CROSS_PLATFORM_FRAMEWORKS=("netcoreapp3.1" "net5.0" "net6.0" "net7.0" "net
|
||||
VALID_CROSS_PLATFORM_RUNTIMES=("win-arm64" "linux-x64" "linux-arm64" "osx-x64")
|
||||
|
||||
# Only build if requested
|
||||
if [ $NO_BUILD = false ]
|
||||
then
|
||||
if [ $NO_BUILD = false ]; then
|
||||
# Restore Nuget packages for all builds
|
||||
echo "Restoring Nuget packages"
|
||||
dotnet restore
|
||||
|
||||
# Build UI
|
||||
for FRAMEWORK in "${UI_FRAMEWORKS[@]}"
|
||||
do
|
||||
for RUNTIME in "${UI_RUNTIMES[@]}"
|
||||
do
|
||||
for FRAMEWORK in "${UI_FRAMEWORKS[@]}"; do
|
||||
for RUNTIME in "${UI_RUNTIMES[@]}"; do
|
||||
# If we have an invalid combination of framework and runtime
|
||||
if [[ ! $(echo ${VALID_CROSS_PLATFORM_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]; then
|
||||
if [[ $(echo ${VALID_CROSS_PLATFORM_RUNTIMES[@]} | fgrep -w $RUNTIME) ]]; then
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# Only .NET 5 and above can publish to a single file
|
||||
if [[ $(echo ${SINGLE_FILE_CAPABLE[@]} | fgrep -w $FRAMEWORK) ]]
|
||||
then
|
||||
dotnet publish MPF/MPF.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
|
||||
if [[ $(echo ${SINGLE_FILE_CAPABLE[@]} | fgrep -w $FRAMEWORK) ]]; then
|
||||
# Only include Debug if building all
|
||||
if [ $USE_ALL = true ]; then
|
||||
dotnet publish MPF/MPF.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
|
||||
fi
|
||||
dotnet publish MPF/MPF.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
|
||||
else
|
||||
dotnet publish MPF/MPF.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT
|
||||
# Only include Debug if building all
|
||||
if [ $USE_ALL = true ]; then
|
||||
dotnet publish MPF/MPF.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT
|
||||
fi
|
||||
dotnet publish MPF/MPF.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:DebugType=None -p:DebugSymbols=false
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
# Build Check
|
||||
for FRAMEWORK in "${CHECK_FRAMEWORKS[@]}"
|
||||
do
|
||||
for RUNTIME in "${CHECK_RUNTIMES[@]}"
|
||||
do
|
||||
for FRAMEWORK in "${CHECK_FRAMEWORKS[@]}"; do
|
||||
for RUNTIME in "${CHECK_RUNTIMES[@]}"; do
|
||||
# If we have an invalid combination of framework and runtime
|
||||
if [[ ! $(echo ${VALID_CROSS_PLATFORM_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]
|
||||
then
|
||||
if [[ $(echo ${VALID_CROSS_PLATFORM_RUNTIMES[@]} | fgrep -w $RUNTIME) ]]
|
||||
then
|
||||
if [[ ! $(echo ${VALID_CROSS_PLATFORM_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]; then
|
||||
if [[ $(echo ${VALID_CROSS_PLATFORM_RUNTIMES[@]} | fgrep -w $RUNTIME) ]]; then
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# Only .NET 5 and above can publish to a single file
|
||||
if [[ $(echo ${SINGLE_FILE_CAPABLE[@]} | fgrep -w $FRAMEWORK) ]]
|
||||
then
|
||||
dotnet publish MPF.Check/MPF.Check.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
|
||||
if [[ $(echo ${SINGLE_FILE_CAPABLE[@]} | fgrep -w $FRAMEWORK) ]]; then
|
||||
# Only include Debug if building all
|
||||
if [ $USE_ALL = true ]; then
|
||||
dotnet publish MPF.Check/MPF.Check.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
|
||||
fi
|
||||
dotnet publish MPF.Check/MPF.Check.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
|
||||
else
|
||||
dotnet publish MPF.Check/MPF.Check.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT
|
||||
# Only include Debug if building all
|
||||
if [ $USE_ALL = true ]; then
|
||||
dotnet publish MPF.Check/MPF.Check.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT
|
||||
fi
|
||||
dotnet publish MPF.Check/MPF.Check.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:DebugType=None -p:DebugSymbols=false
|
||||
fi
|
||||
done
|
||||
@@ -115,50 +123,43 @@ then
|
||||
fi
|
||||
|
||||
# Only create archives if requested
|
||||
if [ $NO_ARCHIVE = false ]
|
||||
then
|
||||
if [ $NO_ARCHIVE = false ]; then
|
||||
# Create UI archives
|
||||
for FRAMEWORK in "${UI_FRAMEWORKS[@]}"
|
||||
do
|
||||
echo "Framework: $FRAMEWORK"
|
||||
for RUNTIME in "${UI_RUNTIMES[@]}"
|
||||
do
|
||||
echo "Runtime: $RUNTIME"
|
||||
cd $BUILD_FOLDER/MPF/bin/Debug/${FRAMEWORK}/${RUNTIME}/publish/
|
||||
echo "PWD: $PWD"
|
||||
if [ $INCLUDE_PROGRAMS = true ]
|
||||
then
|
||||
zip -r $BUILD_FOLDER/MPF_${FRAMEWORK}_${RUNTIME}_debug.zip .
|
||||
else
|
||||
zip -r $BUILD_FOLDER/MPF_${FRAMEWORK}_${RUNTIME}_debug.zip . -x 'Programs/\*'
|
||||
for FRAMEWORK in "${UI_FRAMEWORKS[@]}"; do
|
||||
for RUNTIME in "${UI_RUNTIMES[@]}"; do
|
||||
# Only include Debug if building all
|
||||
if [ $USE_ALL = true ]; then
|
||||
cd $BUILD_FOLDER/MPF/bin/Debug/${FRAMEWORK}/${RUNTIME}/publish/
|
||||
if [ $INCLUDE_PROGRAMS = true ]; then
|
||||
zip -r $BUILD_FOLDER/MPF_${FRAMEWORK}_${RUNTIME}_debug.zip .
|
||||
else
|
||||
zip -r $BUILD_FOLDER/MPF_${FRAMEWORK}_${RUNTIME}_debug.zip . -x 'Programs/\*'
|
||||
fi
|
||||
fi
|
||||
cd $BUILD_FOLDER/MPF/bin/Release/${FRAMEWORK}/${RUNTIME}/publish/
|
||||
echo "PWD: $PWD"
|
||||
if [ $INCLUDE_PROGRAMS = true ]
|
||||
then
|
||||
if [ $INCLUDE_PROGRAMS = true ]; then
|
||||
zip -r $BUILD_FOLDER/MPF_${FRAMEWORK}_${RUNTIME}_release.zip .
|
||||
else
|
||||
zip -r $BUILD_FOLDER/MPF_${FRAMEWORK}_${RUNTIME}_release.zip . -x 'Programs/\*'
|
||||
zip -r $BUILD_FOLDER/MPF_${FRAMEWORK}_${RUNTIME}_release.zip . -x 'Programs/\*'
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
# Create Check archives
|
||||
for FRAMEWORK in "${CHECK_FRAMEWORKS[@]}"
|
||||
do
|
||||
for RUNTIME in "${CHECK_RUNTIMES[@]}"
|
||||
do
|
||||
for FRAMEWORK in "${CHECK_FRAMEWORKS[@]}"; do
|
||||
for RUNTIME in "${CHECK_RUNTIMES[@]}"; do
|
||||
# If we have an invalid combination of framework and runtime
|
||||
if [[ ! $(echo ${VALID_CROSS_PLATFORM_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]
|
||||
then
|
||||
if [[ $(echo ${VALID_CROSS_PLATFORM_RUNTIMES[@]} | fgrep -w $RUNTIME) ]]
|
||||
then
|
||||
if [[ ! $(echo ${VALID_CROSS_PLATFORM_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]; then
|
||||
if [[ $(echo ${VALID_CROSS_PLATFORM_RUNTIMES[@]} | fgrep -w $RUNTIME) ]]; then
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
cd $BUILD_FOLDER/MPF.Check/bin/Debug/${FRAMEWORK}/${RUNTIME}/publish/
|
||||
zip -r $BUILD_FOLDER/MPF.Check_${FRAMEWORK}_${RUNTIME}_debug.zip .
|
||||
# Only include Debug if building all
|
||||
if [ $USE_ALL = true ]; then
|
||||
cd $BUILD_FOLDER/MPF.Check/bin/Debug/${FRAMEWORK}/${RUNTIME}/publish/
|
||||
zip -r $BUILD_FOLDER/MPF.Check_${FRAMEWORK}_${RUNTIME}_debug.zip .
|
||||
fi
|
||||
cd $BUILD_FOLDER/MPF.Check/bin/Release/${FRAMEWORK}/${RUNTIME}/publish/
|
||||
zip -r $BUILD_FOLDER/MPF.Check_${FRAMEWORK}_${RUNTIME}_release.zip .
|
||||
done
|
||||
@@ -166,4 +167,4 @@ then
|
||||
|
||||
# Reset the directory
|
||||
cd $BUILD_FOLDER
|
||||
fi
|
||||
fi
|
||||
|
||||
203
publish-win.ps1
203
publish-win.ps1
@@ -14,15 +14,15 @@ param(
|
||||
[Alias("UseAll")]
|
||||
[switch]$USE_ALL,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[Parameter(Mandatory = $false)]
|
||||
[Alias("IncludePrograms")]
|
||||
[switch]$INCLUDE_PROGRAMS,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[Parameter(Mandatory = $false)]
|
||||
[Alias("NoBuild")]
|
||||
[switch]$NO_BUILD,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[Parameter(Mandatory = $false)]
|
||||
[Alias("NoArchive")]
|
||||
[switch]$NO_ARCHIVE
|
||||
)
|
||||
@@ -34,14 +34,13 @@ $BUILD_FOLDER = $PSScriptRoot
|
||||
$COMMIT = git log --pretty=format:"%H" -1
|
||||
|
||||
# Create the build matrix arrays
|
||||
$UI_FRAMEWORKS = @('net6.0-windows', 'net8.0-windows')
|
||||
$UI_RUNTIMES = @('win-x64')
|
||||
$CHECK_FRAMEWORKS = @('net6.0', 'net8.0')
|
||||
$CHECK_RUNTIMES = @('win-x64', 'linux-x64', 'osx-x64')
|
||||
$UI_FRAMEWORKS = @('net8.0-windows')
|
||||
$UI_RUNTIMES = @('win-x86', 'win-x64')
|
||||
$CHECK_FRAMEWORKS = @('net8.0')
|
||||
$CHECK_RUNTIMES = @('win-x86', 'win-x64', 'linux-x64', 'osx-x64')
|
||||
|
||||
# Use expanded lists, if requested
|
||||
if ($USE_ALL.IsPresent)
|
||||
{
|
||||
if ($USE_ALL.IsPresent) {
|
||||
$UI_FRAMEWORKS = @('net40', 'net452', 'net462', 'net472', 'net48', 'netcoreapp3.1', 'net5.0-windows', 'net6.0-windows', 'net7.0-windows', 'net8.0-windows')
|
||||
$UI_RUNTIMES = @('win-x86', 'win-x64')
|
||||
$CHECK_FRAMEWORKS = @('net20', 'net35', 'net40', 'net452', 'net462', 'net472', 'net48', 'netcoreapp3.1', 'net5.0', 'net6.0', 'net7.0', 'net8.0')
|
||||
@@ -54,104 +53,108 @@ $VALID_CROSS_PLATFORM_FRAMEWORKS = @('netcoreapp3.1', 'net5.0', 'net6.0', 'net7.
|
||||
$VALID_CROSS_PLATFORM_RUNTIMES = @('win-arm64', 'linux-x64', 'linux-arm64', 'osx-x64')
|
||||
|
||||
# Only build if requested
|
||||
if (!$NO_BUILD.IsPresent)
|
||||
{
|
||||
# Restore Nuget packages for all builds
|
||||
Write-Host "Restoring Nuget packages"
|
||||
dotnet restore
|
||||
if (!$NO_BUILD.IsPresent) {
|
||||
# Restore Nuget packages for all builds
|
||||
Write-Host "Restoring Nuget packages"
|
||||
dotnet restore
|
||||
|
||||
# Build UI
|
||||
foreach ($FRAMEWORK in $UI_FRAMEWORKS)
|
||||
{
|
||||
foreach ($RUNTIME in $UI_RUNTIMES)
|
||||
{
|
||||
# Only .NET 5 and above can publish to a single file
|
||||
if ($SINGLE_FILE_CAPABLE -contains $FRAMEWORK)
|
||||
{
|
||||
dotnet publish MPF\MPF.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
|
||||
dotnet publish MPF\MPF.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
|
||||
}
|
||||
else
|
||||
{
|
||||
dotnet publish MPF\MPF.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT
|
||||
dotnet publish MPF\MPF.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:DebugType=None -p:DebugSymbols=false
|
||||
}
|
||||
}
|
||||
}
|
||||
# Build UI
|
||||
foreach ($FRAMEWORK in $UI_FRAMEWORKS) {
|
||||
foreach ($RUNTIME in $UI_RUNTIMES) {
|
||||
# If we have an invalid combination of framework and runtime
|
||||
if ($VALID_CROSS_PLATFORM_FRAMEWORKS -notcontains $FRAMEWORK -and $VALID_CROSS_PLATFORM_RUNTIMES -contains $RUNTIME) {
|
||||
continue
|
||||
}
|
||||
|
||||
# Build Check
|
||||
foreach ($FRAMEWORK in $CHECK_FRAMEWORKS)
|
||||
{
|
||||
foreach ($RUNTIME in $CHECK_RUNTIMES)
|
||||
{
|
||||
# If we have an invalid combination of framework and runtime
|
||||
if ($VALID_CROSS_PLATFORM_FRAMEWORKS -notcontains $FRAMEWORK -and $VALID_CROSS_PLATFORM_RUNTIMES -contains $RUNTIME)
|
||||
{
|
||||
continue
|
||||
}
|
||||
# Only .NET 5 and above can publish to a single file
|
||||
if ($SINGLE_FILE_CAPABLE -contains $FRAMEWORK) {
|
||||
# Only include Debug if building all
|
||||
if ($USE_ALL.IsPresent) {
|
||||
dotnet publish MPF\MPF.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
|
||||
}
|
||||
dotnet publish MPF\MPF.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
|
||||
}
|
||||
else {
|
||||
# Only include Debug if building all
|
||||
if ($USE_ALL.IsPresent) {
|
||||
dotnet publish MPF\MPF.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT
|
||||
}
|
||||
dotnet publish MPF\MPF.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:DebugType=None -p:DebugSymbols=false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Only .NET 5 and above can publish to a single file
|
||||
if ($SINGLE_FILE_CAPABLE -contains $FRAMEWORK)
|
||||
{
|
||||
dotnet publish MPF.Check\MPF.Check.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
|
||||
dotnet publish MPF.Check\MPF.Check.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
|
||||
}
|
||||
else
|
||||
{
|
||||
dotnet publish MPF.Check\MPF.Check.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT
|
||||
dotnet publish MPF.Check\MPF.Check.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:DebugType=None -p:DebugSymbols=false
|
||||
}
|
||||
}
|
||||
}
|
||||
# Build Check
|
||||
foreach ($FRAMEWORK in $CHECK_FRAMEWORKS) {
|
||||
foreach ($RUNTIME in $CHECK_RUNTIMES) {
|
||||
# If we have an invalid combination of framework and runtime
|
||||
if ($VALID_CROSS_PLATFORM_FRAMEWORKS -notcontains $FRAMEWORK -and $VALID_CROSS_PLATFORM_RUNTIMES -contains $RUNTIME) {
|
||||
continue
|
||||
}
|
||||
|
||||
# Only .NET 5 and above can publish to a single file
|
||||
if ($SINGLE_FILE_CAPABLE -contains $FRAMEWORK) {
|
||||
# Only include Debug if building all
|
||||
if ($USE_ALL.IsPresent) {
|
||||
dotnet publish MPF.Check\MPF.Check.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
|
||||
}
|
||||
dotnet publish MPF.Check\MPF.Check.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
|
||||
}
|
||||
else {
|
||||
# Only include Debug if building all
|
||||
if ($USE_ALL.IsPresent) {
|
||||
dotnet publish MPF.Check\MPF.Check.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT
|
||||
}
|
||||
dotnet publish MPF.Check\MPF.Check.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:DebugType=None -p:DebugSymbols=false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Only create archives if requested
|
||||
if (!$NO_ARCHIVE.IsPresent)
|
||||
{
|
||||
# Create UI archives
|
||||
foreach ($FRAMEWORK in $UI_FRAMEWORKS)
|
||||
{
|
||||
foreach ($RUNTIME in $UI_RUNTIMES)
|
||||
{
|
||||
Set-Location -Path $BUILD_FOLDER\MPF\bin\Debug\${FRAMEWORK}\${RUNTIME}\publish\
|
||||
if ($INCLUDE_PROGRAMS.IsPresent)
|
||||
{
|
||||
7z a -tzip $BUILD_FOLDER\MPF_${FRAMEWORK}_${RUNTIME}_debug.zip *
|
||||
}
|
||||
else
|
||||
{
|
||||
7z a -tzip -x!Programs\* $BUILD_FOLDER\MPF_${FRAMEWORK}_${RUNTIME}_debug.zip *
|
||||
}
|
||||
Set-Location -Path $BUILD_FOLDER\MPF\bin\Release\${FRAMEWORK}\${RUNTIME}\publish\
|
||||
if ($INCLUDE_PROGRAMS.IsPresent)
|
||||
{
|
||||
7z a -tzip $BUILD_FOLDER\MPF_${FRAMEWORK}_${RUNTIME}_release.zip *
|
||||
}
|
||||
else
|
||||
{
|
||||
7z a -tzip -x!Programs\* $BUILD_FOLDER\MPF_${FRAMEWORK}_${RUNTIME}_release.zip *
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$NO_ARCHIVE.IsPresent) {
|
||||
# Create UI archives
|
||||
foreach ($FRAMEWORK in $UI_FRAMEWORKS) {
|
||||
foreach ($RUNTIME in $UI_RUNTIMES) {
|
||||
# Only include Debug if building all
|
||||
if ($USE_ALL.IsPresent) {
|
||||
Set-Location -Path $BUILD_FOLDER\MPF\bin\Debug\${FRAMEWORK}\${RUNTIME}\publish\
|
||||
if ($INCLUDE_PROGRAMS.IsPresent) {
|
||||
7z a -tzip $BUILD_FOLDER\MPF_${FRAMEWORK}_${RUNTIME}_debug.zip *
|
||||
}
|
||||
else {
|
||||
7z a -tzip -x!Programs\* $BUILD_FOLDER\MPF_${FRAMEWORK}_${RUNTIME}_debug.zip *
|
||||
}
|
||||
}
|
||||
|
||||
Set-Location -Path $BUILD_FOLDER\MPF\bin\Release\${FRAMEWORK}\${RUNTIME}\publish\
|
||||
if ($INCLUDE_PROGRAMS.IsPresent) {
|
||||
7z a -tzip $BUILD_FOLDER\MPF_${FRAMEWORK}_${RUNTIME}_release.zip *
|
||||
}
|
||||
else {
|
||||
7z a -tzip -x!Programs\* $BUILD_FOLDER\MPF_${FRAMEWORK}_${RUNTIME}_release.zip *
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Create Check archives
|
||||
foreach ($FRAMEWORK in $CHECK_FRAMEWORKS)
|
||||
{
|
||||
foreach ($RUNTIME in $CHECK_RUNTIMES)
|
||||
{
|
||||
# If we have an invalid combination of framework and runtime
|
||||
if ($VALID_CROSS_PLATFORM_FRAMEWORKS -notcontains $FRAMEWORK -and $VALID_CROSS_PLATFORM_RUNTIMES -contains $RUNTIME)
|
||||
{
|
||||
continue
|
||||
}
|
||||
# Create Check archives
|
||||
foreach ($FRAMEWORK in $CHECK_FRAMEWORKS) {
|
||||
foreach ($RUNTIME in $CHECK_RUNTIMES) {
|
||||
# If we have an invalid combination of framework and runtime
|
||||
if ($VALID_CROSS_PLATFORM_FRAMEWORKS -notcontains $FRAMEWORK -and $VALID_CROSS_PLATFORM_RUNTIMES -contains $RUNTIME) {
|
||||
continue
|
||||
}
|
||||
|
||||
Set-Location -Path $BUILD_FOLDER\MPF.Check\bin\Debug\${FRAMEWORK}\${RUNTIME}\publish\
|
||||
7z a -tzip $BUILD_FOLDER\MPF.Check_${FRAMEWORK}_${RUNTIME}_debug.zip *
|
||||
Set-Location -Path $BUILD_FOLDER\MPF.Check\bin\Release\${FRAMEWORK}\${RUNTIME}\publish\
|
||||
7z a -tzip $BUILD_FOLDER\MPF.Check_${FRAMEWORK}_${RUNTIME}_release.zip *
|
||||
}
|
||||
}
|
||||
# Only include Debug if building all
|
||||
if ($USE_ALL.IsPresent) {
|
||||
Set-Location -Path $BUILD_FOLDER\MPF.Check\bin\Debug\${FRAMEWORK}\${RUNTIME}\publish\
|
||||
7z a -tzip $BUILD_FOLDER\MPF.Check_${FRAMEWORK}_${RUNTIME}_debug.zip *
|
||||
}
|
||||
Set-Location -Path $BUILD_FOLDER\MPF.Check\bin\Release\${FRAMEWORK}\${RUNTIME}\publish\
|
||||
7z a -tzip $BUILD_FOLDER\MPF.Check_${FRAMEWORK}_${RUNTIME}_release.zip *
|
||||
}
|
||||
}
|
||||
|
||||
# Reset the directory
|
||||
Set-Location -Path $PSScriptRoot
|
||||
# Reset the directory
|
||||
Set-Location -Path $PSScriptRoot
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user