Skip to content

Commit

Permalink
Merge branch 'feature/avalonia'
Browse files Browse the repository at this point in the history
  • Loading branch information
13xforever committed Aug 7, 2023
2 parents 03b7da6 + 536eaf4 commit f08ef0a
Show file tree
Hide file tree
Showing 65 changed files with 4,013 additions and 179 deletions.
7 changes: 0 additions & 7 deletions IrdLibraryClient/ApiConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,4 @@ namespace IrdLibraryClient;
public static class ApiConfig
{
public static readonly CancellationTokenSource Cts = new();
public static readonly string IrdCachePath = "./ird/";

static ApiConfig()
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
IrdCachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ,"ps3-iso-dumper/ird/");
}
}
11 changes: 8 additions & 3 deletions IrdLibraryClient/Log.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,16 @@ static Log()
{
var path = Path.Combine("logs", DateTime.Now.ToString("yyyy-MM-dd") + ".log");
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ps3-iso-dumper", path);
path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "ps3-iso-dumper", path);
var folder = Path.GetDirectoryName(path) ?? ".";
if (!Directory.Exists(folder))
Directory.CreateDirectory(folder);
var filestream = File.Open(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read);
var filestream = File.Open(path, new FileStreamOptions
{
Mode = FileMode.OpenOrCreate,
Access = FileAccess.Write,
Options = FileOptions.Asynchronous | FileOptions.SequentialScan,
});
filestream.Seek(0, SeekOrigin.End);
FileLog = new(filestream, new UTF8Encoding(false));
LogPath = path;
Expand Down Expand Up @@ -61,7 +66,7 @@ private static void LogInternal(Exception? e, string message, LogLevel level, Co
try
{
#if DEBUG
const LogLevel minLevel = LogLevel.TRACE;
const LogLevel minLevel = LogLevel.TRACE;
#else
const LogLevel minLevel = LogLevel.DEBUG;
#endif
Expand Down
19 changes: 19 additions & 0 deletions Ps3DiscDumper.sln
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,53 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Deploy", "Deploy", "{BA0C92
ProjectSection(SolutionItems) = preProject
azure-pipelines.yml = azure-pipelines.yml
publish.ps1 = publish.ps1
README.md = README.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UI.Avalonia", "UI.Avalonia\UI.Avalonia.csproj", "{EBFEB92B-CF70-48C2-B1B4-80CC21EFA072}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
Linux|Any CPU = Linux|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F58970E2-7861-4635-BBAA-2E081D1B68F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F58970E2-7861-4635-BBAA-2E081D1B68F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F58970E2-7861-4635-BBAA-2E081D1B68F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F58970E2-7861-4635-BBAA-2E081D1B68F0}.Release|Any CPU.Build.0 = Release|Any CPU
{F58970E2-7861-4635-BBAA-2E081D1B68F0}.Linux|Any CPU.ActiveCfg = Debug|Any CPU
{F58970E2-7861-4635-BBAA-2E081D1B68F0}.Linux|Any CPU.Build.0 = Debug|Any CPU
{EC25C188-51BB-4665-B79B-2AE17CABB01E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EC25C188-51BB-4665-B79B-2AE17CABB01E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC25C188-51BB-4665-B79B-2AE17CABB01E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC25C188-51BB-4665-B79B-2AE17CABB01E}.Release|Any CPU.Build.0 = Release|Any CPU
{EC25C188-51BB-4665-B79B-2AE17CABB01E}.Linux|Any CPU.ActiveCfg = Debug|Any CPU
{EC25C188-51BB-4665-B79B-2AE17CABB01E}.Linux|Any CPU.Build.0 = Debug|Any CPU
{C8C058F0-01DA-41B9-BBAA-6787C5C755F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C8C058F0-01DA-41B9-BBAA-6787C5C755F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C8C058F0-01DA-41B9-BBAA-6787C5C755F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C8C058F0-01DA-41B9-BBAA-6787C5C755F1}.Release|Any CPU.Build.0 = Release|Any CPU
{C8C058F0-01DA-41B9-BBAA-6787C5C755F1}.Linux|Any CPU.ActiveCfg = Debug|Any CPU
{C8C058F0-01DA-41B9-BBAA-6787C5C755F1}.Linux|Any CPU.Build.0 = Debug|Any CPU
{F5041E4B-77E7-4783-8A74-41BFD49FB9E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F5041E4B-77E7-4783-8A74-41BFD49FB9E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F5041E4B-77E7-4783-8A74-41BFD49FB9E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F5041E4B-77E7-4783-8A74-41BFD49FB9E8}.Release|Any CPU.Build.0 = Release|Any CPU
{F5041E4B-77E7-4783-8A74-41BFD49FB9E8}.Linux|Any CPU.ActiveCfg = Debug|Any CPU
{F5041E4B-77E7-4783-8A74-41BFD49FB9E8}.Linux|Any CPU.Build.0 = Debug|Any CPU
{874BD35B-DFDF-40BE-BB6F-EC36059E40EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{874BD35B-DFDF-40BE-BB6F-EC36059E40EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{874BD35B-DFDF-40BE-BB6F-EC36059E40EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{874BD35B-DFDF-40BE-BB6F-EC36059E40EB}.Release|Any CPU.Build.0 = Release|Any CPU
{874BD35B-DFDF-40BE-BB6F-EC36059E40EB}.Linux|Any CPU.ActiveCfg = Debug|Any CPU
{EBFEB92B-CF70-48C2-B1B4-80CC21EFA072}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EBFEB92B-CF70-48C2-B1B4-80CC21EFA072}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBFEB92B-CF70-48C2-B1B4-80CC21EFA072}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBFEB92B-CF70-48C2-B1B4-80CC21EFA072}.Release|Any CPU.Build.0 = Release|Any CPU
{EBFEB92B-CF70-48C2-B1B4-80CC21EFA072}.Linux|Any CPU.ActiveCfg = Linux|Any CPU
{EBFEB92B-CF70-48C2-B1B4-80CC21EFA072}.Linux|Any CPU.Build.0 = Linux|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
108 changes: 77 additions & 31 deletions Ps3DiscDumper/Dumper.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Management;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Runtime.InteropServices;
using System.Text;
using System.Runtime.Versioning;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading;
Expand All @@ -27,9 +27,13 @@ namespace Ps3DiscDumper;

public class Dumper: IDisposable
{
public const string Version = "3.3.6";
public const string Version = "4.0.0";

static Dumper() => Log.Info("PS3 Disc Dumper v" + Version);

private static readonly Regex VersionParts = new(@"(?<ver>\d+(\.\d+){0,2})[ \-]*(?<pre>.*)", RegexOptions.Singleline | RegexOptions.ExplicitCapture);
private static readonly Regex ScsiInfoParts = new(@"Host: .+$\s*Vendor: (?<vendor>.+?)\s* Model: (?<model>.+?)\s* Rev: (?<revision>.+)$\s*Type: \s*(?<type>.+?)\s* ANSI ?SCSI revision: (?<scsi_rev>.+?)\s*$",
RegexOptions.Multiline | RegexOptions.ExplicitCapture);
private static readonly HashSet<char> InvalidChars = new(Path.GetInvalidFileNameChars().Concat(Path.GetInvalidPathChars()));
private static readonly char[] MultilineSplit = {'\r', '\n'};
private long currentSector;
Expand All @@ -47,20 +51,31 @@ public class Dumper: IDisposable
private byte[] sectorIV;
private Stream driveStream;
private static readonly byte[] Iso9660PrimaryVolumeDescriptorHeader = {0x01, 0x43, 0x44, 0x30, 0x30, 0x31, 0x01, 0x00};

private static readonly JsonSerializerOptions JsonOptions = new()
{
PropertyNamingPolicy = new SnakeCasePolicy(),
WriteIndented = true,
};
public static readonly NameValueCollection RegionMapping = new()
{
["A"] = "ASIA",
["E"] = "EU",
["H"] = "HK",
["J"] = "JP",
["K"] = "KR",
["P"] = "JP",
["T"] = "JP",
["U"] = "US",
};

public ParamSfo ParamSfo { get; private set; }
public string ProductCode { get; private set; }
public string DiscVersion { get; private set; }
public string Title { get; private set; }
public string OutputDir { get; private set; }
public char Drive { get; set; }
private string input;
public string SelectedPhysicalDevice { get; private set; }
public string InputDevicePath { get; private set; }
private List<FileRecord> filesystemStructure;
private List<DirRecord> emptyDirStructure;
private CDReader discReader;
Expand Down Expand Up @@ -96,6 +111,7 @@ public long CurrentSector
}
}

[SupportedOSPlatform("Windows")]
private List<string> EnumeratePhysicalDrivesWindows()
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
Expand All @@ -105,14 +121,21 @@ private List<string> EnumeratePhysicalDrivesWindows()
#if !NATIVE
try
{
using var mgmtObjSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMedia");
var drives = mgmtObjSearcher.Get();
using var physicalMediaQuery = new ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMedia");
var drives = physicalMediaQuery.Get();
foreach (var drive in drives)
{
var tag = drive.Properties["Tag"].Value as string;
if (tag?.IndexOf("CDROM", StringComparison.InvariantCultureIgnoreCase) > -1)
if (drive.Properties["Tag"].Value is string tag
&& tag.StartsWith(@"\\.\CDROM"))
physicalDrives.Add(tag);
}
using var cdromQuery = new ManagementObjectSearcher("SELECT * FROM Win32_CDROMDrive");
drives = cdromQuery.Get();
foreach (var drive in drives)
{
// Name and Caption are the same, so idk if they can be different
Log.Info($"Found optical media drive {drive.Properties["Name"].Value} ({drive.Properties["Drive"].Value})");
}
}
catch (Exception e)
{
Expand All @@ -127,12 +150,27 @@ private List<string> EnumeratePhysicalDrivesWindows()
return physicalDrives;
}

[SupportedOSPlatform("Linux")]
private List<string> EnumeratePhysicalDrivesLinux()
{
var cdInfo = "";
try
{
cdInfo = File.ReadAllText("/proc/sys/dev/cdrom/info");
if (File.Exists("/proc/scsi/scsi"))
{
var scsiInfo = File.ReadAllText("/proc/scsi/scsi");
if (scsiInfo is { Length: > 0 })
{
foreach (Match m in ScsiInfoParts.Matches(scsiInfo))
{
if (m.Groups["type"].Value is not "CD-ROM")
continue;

Log.Info($"Found optical media drive {m.Groups["vendor"].Value} {m.Groups["model"].Value}");
}
}
}
}
catch (Exception e)
{
Expand Down Expand Up @@ -176,10 +214,13 @@ private void CheckParamSfo(ParamSfo sfo)

public void DetectDisc(string inDir = "", Func<Dumper, string> outputDirFormatter = null)
{
outputDirFormatter ??= d => PatternFormatter.Format($"%{Patterns.Title}% [%{Patterns.ProductCode}%]", new()
outputDirFormatter ??= d => PatternFormatter.Format(SettingsProvider.Settings.DumpNameTemplate, new()
{
[Patterns.ProductCode] = d.ProductCode,
[Patterns.ProductCodeLetters] = d.ProductCode?[..4],
[Patterns.ProductCodeNumbers] = d.ProductCode?[4..],
[Patterns.Title] = d.Title,
[Patterns.Region] = RegionMapping[d.ProductCode?[2..3] ?? ""],
});
string discSfbPath = null;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
Expand All @@ -193,7 +234,7 @@ public void DetectDisc(string inDir = "", Func<Dumper, string> outputDirFormatte
if (!File.Exists(discSfbPath))
continue;

input = drive.Name;
InputDevicePath = drive.Name;
Drive = drive.Name[0];
break;
}
Expand All @@ -203,7 +244,7 @@ public void DetectDisc(string inDir = "", Func<Dumper, string> outputDirFormatte
discSfbPath = Path.Combine(inDir, "PS3_DISC.SFB");
if (File.Exists(discSfbPath))
{
input = Path.GetPathRoot(discSfbPath);
InputDevicePath = Path.GetPathRoot(discSfbPath);
Drive = discSfbPath[0];
}
}
Expand All @@ -215,20 +256,20 @@ public void DetectDisc(string inDir = "", Func<Dumper, string> outputDirFormatte
: DriveInfo.GetDrives().Where(d => d.DriveType == DriveType.CDRom).Select(d => d.RootDirectory.FullName);
discSfbPath = mountList.SelectMany(mp => IOEx.GetFilepaths(mp, "PS3_DISC.SFB", 2)) .FirstOrDefault();
if (!string.IsNullOrEmpty(discSfbPath))
input = Path.GetDirectoryName(discSfbPath)!;
InputDevicePath = Path.GetDirectoryName(discSfbPath)!;
}
else
throw new NotImplementedException("Current OS is not supported");

if (string.IsNullOrEmpty(input) || string.IsNullOrEmpty(discSfbPath))
if (string.IsNullOrEmpty(InputDevicePath) || string.IsNullOrEmpty(discSfbPath))
throw new DriveNotFoundException("No valid PS3 disc was detected. Disc must be detected and mounted.");

Log.Info("Selected disc: " + input);
Log.Info("Selected disc: " + InputDevicePath);
discSfbData = File.ReadAllBytes(discSfbPath);
var titleId = CheckDiscSfb(discSfbData);
var paramSfoPath = Path.Combine(input, "PS3_GAME", "PARAM.SFO");
var paramSfoPath = Path.Combine(InputDevicePath, "PS3_GAME", "PARAM.SFO");
if (!File.Exists(paramSfoPath))
throw new InvalidOperationException($"Specified folder is not a valid PS3 disc root (param.sfo is missing): {input}");
throw new InvalidOperationException($"Specified folder is not a valid PS3 disc root (param.sfo is missing): {InputDevicePath}");

using (var stream = File.Open(paramSfoPath, FileMode.Open, FileAccess.Read, FileShare.Read))
ParamSfo = ParamSfo.ReadFrom(stream);
Expand All @@ -237,10 +278,10 @@ public void DetectDisc(string inDir = "", Func<Dumper, string> outputDirFormatte
Log.Warn($"Product codes in ps3_disc.sfb ({titleId}) and in param.sfo ({ProductCode}) do not match");

// todo: maybe use discutils instead to read TOC as one block
var files = IOEx.GetFilepaths(input, "*", SearchOption.AllDirectories);
var files = IOEx.GetFilepaths(InputDevicePath, "*", SearchOption.AllDirectories);
DiscFilenames = new();
var totalFilesize = 0L;
var rootLength = input.Length;
var rootLength = InputDevicePath.Length;
foreach (var f in files)
{
try { totalFilesize += new FileInfo(f).Length; } catch { }
Expand Down Expand Up @@ -296,8 +337,6 @@ public async Task FindDiscKeyAsync(string discKeyCachePath)
if (untestedKeys.Count == 0)
throw new KeyNotFoundException("No valid disc decryption key was found");

// select physical device
string physicalDevice = null;
List<string> physicalDrives = new List<string>();
Log.Trace("Trying to enumerate physical drives...");
try
Expand All @@ -324,7 +363,12 @@ public async Task FindDiscKeyAsync(string discKeyCachePath)
try
{
Log.Trace($"Checking physical drive {drive}...");
await using var discStream = File.Open(drive, FileMode.Open, FileAccess.Read, FileShare.Read);
await using var discStream = File.Open(drive, new FileStreamOptions
{
Mode = FileMode.Open,
Access = FileAccess.Read,
Options = FileOptions.Asynchronous | FileOptions.SequentialScan
});
var tmpDiscReader = new CDReader(discStream, true, true);
if (tmpDiscReader.FileExists("PS3_DISC.SFB"))
{
Expand All @@ -339,7 +383,7 @@ public async Task FindDiscKeyAsync(string discKeyCachePath)
discStream.ReadExact(buf, 0, buf.Length);
if (buf.SequenceEqual(discSfbData))
{
physicalDevice = drive;
SelectedPhysicalDevice = drive;
break;
}
Log.Trace("SFB content check failed, skipping the drive");
Expand All @@ -351,11 +395,11 @@ public async Task FindDiscKeyAsync(string discKeyCachePath)
Log.Debug($"Skipping drive {drive}: {e.Message}");
}
}
if (physicalDevice == null)
throw new AccessViolationException("Couldn't get physical access to the drive");
if (SelectedPhysicalDevice == null)
throw new AccessViolationException("Direct disk access to the drive was denied");

Log.Debug($"Selected physical drive {physicalDevice}");
driveStream = File.Open(physicalDevice, FileMode.Open, FileAccess.Read, FileShare.Read);
Log.Debug($"Selected physical drive {SelectedPhysicalDevice}");
driveStream = File.Open(SelectedPhysicalDevice, FileMode.Open, FileAccess.Read, FileShare.Read);

// find disc license file
discReader = new(driveStream, true, true);
Expand Down Expand Up @@ -416,7 +460,9 @@ public async Task FindDiscKeyAsync(string discKeyCachePath)

lock (AllKnownDiscKeys)
AllKnownDiscKeys.TryGetValue(discKey, out allMatchingKeys);
var discKeyInfo = allMatchingKeys?.First();
var discKeyInfo = allMatchingKeys?.FirstOrDefault(k => k.FullPath.Contains(ProductCode, StringComparison.OrdinalIgnoreCase) && k.FullPath.EndsWith(".ird", StringComparison.OrdinalIgnoreCase))
?? allMatchingKeys?.FirstOrDefault(k => k.FullPath.EndsWith(".ird", StringComparison.OrdinalIgnoreCase))
?? allMatchingKeys?.First();
DiscKeyFilename = Path.GetFileName(discKeyInfo?.FullPath);
DiscKeyType = discKeyInfo?.KeyType ?? default;
}
Expand Down Expand Up @@ -504,7 +550,7 @@ public async Task DumpAsync(string output)
Log.Info($"Reading {file.TargetFileName} ({file.Length.AsStorageUnit()})");
CurrentFileNumber++;
var convertedFilename = Path.DirectorySeparatorChar == '\\' ? file.TargetFileName : file.TargetFileName.Replace('\\', Path.DirectorySeparatorChar);
var inputFilename = Path.Combine(input, convertedFilename);
var inputFilename = Path.Combine(InputDevicePath, convertedFilename);

if (!File.Exists(inputFilename))
{
Expand Down Expand Up @@ -646,8 +692,8 @@ select v.Files[file.TargetFileName].Hashes
return (latestVer, latest);
}

if (latestBetaVer > latestVer
|| (latestVer == latestBetaVer
if (latestBetaVer > curVer
|| (latestBetaVer == curVer
&& curVerPre is {Length: >0}
&& (latestBetaVerPre is {Length: >0} && StringComparer.OrdinalIgnoreCase.Compare(latestBetaVerPre, curVerPre) > 0
|| latestBetaVerStr is null or "")))
Expand Down
2 changes: 1 addition & 1 deletion Ps3DiscDumper/Ps3DiscDumper.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.Management" Version="7.0.1" />
<PackageReference Include="System.Management" Version="7.0.2" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading

0 comments on commit f08ef0a

Please sign in to comment.