Make the GUI version functional!

This commit is contained in:
Li 2023-04-23 20:15:11 +12:00
parent c14a5cc73c
commit e726931b86
48 changed files with 1336 additions and 143 deletions

View File

@ -1,8 +1,8 @@
using Li.Progress;
using GameBuilder.Pops;
using GameBuilder.Psp;
using GameBuilder.VersionKey;
using LibChovy;
using LibChovy.VersionKey;
namespace ChovySign_CLI
{

View File

@ -1,8 +1,8 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ChovySign_GUI.App">
<Application.Styles>
<FluentTheme Mode="Light"/>
<Application.Styles>
<FluentTheme Mode="Light"/>
<!-- Checkbox Styling -->
<Style Selector="CheckBox:checked /template/ ContentPresenter">
@ -150,8 +150,148 @@
</Setter>
</Style>
<!-- ComboBox -->
<Style Selector="ComboBox">
<Setter Property="Foreground">
<Setter.Value>LightGreen</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>#3f3f3f</Setter.Value>
</Setter>
<Setter Property="BorderBrush">
<Setter.Value>LightGreen</Setter.Value>
</Setter>
<Setter Property="BorderThickness">
<Setter.Value>1</Setter.Value>
</Setter>
</Style>
<Style Selector="ComboBox:pointerover">
<Setter Property="Foreground">
<Setter.Value>Green</Setter.Value>
</Setter>
</Style>
<Style Selector="ComboBox:pointerover /template/ TextBlock">
<Setter Property="Foreground">
<Setter.Value>Green</Setter.Value>
</Setter>
</Style>
<Style Selector="ComboBox:pointerover /template/ Border">
<Setter Property="Background">
<Setter.Value>#1f1f1f</Setter.Value>
</Setter>
<Setter Property="BorderBrush">
<Setter.Value>Green</Setter.Value>
</Setter>
</Style>
<Style Selector="ComboBoxItem:pointerover /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground">
<Setter.Value>Green</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>#1f1f1f</Setter.Value>
</Setter>
</Style>
<Style Selector="ComboBoxItem:selected /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground">
<Setter.Value>Black</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>LightGreen</Setter.Value>
</Setter>
</Style>
<Style Selector="ComboBoxItem:selected:pointerover /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground">
<Setter.Value>Black</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>Green</Setter.Value>
</Setter>
</Style>
<Style Selector="ComboBoxItem">
<Setter Property="Foreground">
<Setter.Value>LightGreen</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>#3f3f3f</Setter.Value>
</Setter>
<Setter Property="BorderBrush">
<Setter.Value>LightGreen</Setter.Value>
</Setter>
<Setter Property="BorderThickness">
<Setter.Value>1</Setter.Value>
</Setter>
</Style>
<!-- ListBox -->
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground">
<Setter.Value>Green</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>#1f1f1f</Setter.Value>
</Setter>
</Style>
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground">
<Setter.Value>Black</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>LightGreen</Setter.Value>
</Setter>
</Style>
<Style Selector="ListBoxItem:selected:pointerover /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground">
<Setter.Value>Black</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>Green</Setter.Value>
</Setter>
</Style>
<Style Selector="ListBoxItem">
<Setter Property="Foreground">
<Setter.Value>LightGreen</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>#3f3f3f</Setter.Value>
</Setter>
<Setter Property="BorderBrush">
<Setter.Value>LightGreen</Setter.Value>
</Setter>
<Setter Property="BorderThickness">
<Setter.Value>1</Setter.Value>
</Setter>
</Style>
<Style Selector="ListBox">
<Setter Property="Foreground">
<Setter.Value>LightGreen</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>#3f3f3f</Setter.Value>
</Setter>
<Setter Property="BorderBrush">
<Setter.Value>LightGreen</Setter.Value>
</Setter>
<Setter Property="BorderThickness">
<Setter.Value>1</Setter.Value>
</Setter>
</Style>
<!-- TabControl -->
<Style Selector="TabControl">
<Setter Property="Background">
<Setter.Value>Black</Setter.Value>

View File

@ -6,10 +6,14 @@
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<ApplicationManifest>app.manifest</ApplicationManifest>
<RootNamespace>ChovySign_GUI</RootNamespace>
<AssemblyName>ChovySign v2</AssemblyName>
<ApplicationIcon>ICON.ICO</ApplicationIcon>
<Authors>SquallATF, Li, Dots-Tb</Authors>
</PropertyGroup>
<ItemGroup>
<None Remove=".gitignore" />
<None Remove="DEFAULTICON.PNG" />
<None Remove="Icon.png" />
<None Remove="Popup\Global\KeySelector\ACTRIFMETHOD.PNG" />
<None Remove="Popup\Global\KeySelector\EBOOTMETHOD.PNG" />
<None Remove="Popup\Global\KeySelector\EBOOTMETHOD1.png" />
@ -19,6 +23,7 @@
<None Remove="UMD.png" />
</ItemGroup>
<ItemGroup>
<AvaloniaResource Include="ICON.PNG" />
<AvaloniaResource Include="Popup\Global\KeySelector\ACTRIFMETHOD.PNG" />
<AvaloniaResource Include="Popup\Global\KeySelector\EBOOTMETHOD1.PNG" />
<AvaloniaResource Include="Popup\Global\KeySelector\EBOOTMETHOD2.PNG" />
@ -28,6 +33,9 @@
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</AvaloniaResource>
</ItemGroup>
<ItemGroup>
<Content Include="ICON.ICO" />
</ItemGroup>
<ItemGroup>
<TrimmerRootDescriptor Include="Roots.xml" />

View File

@ -15,8 +15,8 @@
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="7*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="75" />
</Grid.ColumnDefinitions>
<TextBox Name="filePath" HorizontalAlignment="Stretch" VerticalAlignment="Center" Watermark="(None)" Grid.Column="0"/>
<Button Name="browseButton" Content="Browse" HorizontalAlignment="Center" VerticalAlignment="Center" Click="browseClick" Grid.Column="1"/>

View File

@ -2,6 +2,7 @@ using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Org.BouncyCastle.Tls.Crypto;
using System;
using System.Collections.Generic;
using System.IO;
@ -14,6 +15,7 @@ namespace ChovySign_GUI.Global
{
private string fileTypeName;
private string extension;
private bool directory;
public event EventHandler<EventArgs>? FileChanged;
@ -45,6 +47,19 @@ namespace ChovySign_GUI.Global
fileTypeName = value;
}
}
public bool IsDirectory
{
get
{
return this.directory;
}
set
{
this.directory = value;
}
}
public string Watermark
{
get
@ -73,7 +88,10 @@ namespace ChovySign_GUI.Global
{
get
{
return (File.Exists(this.filePath.Text) && Path.GetExtension(this.filePath.Text).Equals("." + Extension, StringComparison.InvariantCultureIgnoreCase));
if (!this.IsDirectory)
return (File.Exists(this.filePath.Text) && Path.GetExtension(this.filePath.Text).Equals("." + Extension, StringComparison.InvariantCultureIgnoreCase));
else
return (Directory.Exists(this.filePath.Text));
}
}
public string FilePath
@ -85,45 +103,75 @@ namespace ChovySign_GUI.Global
}
set
{
if (File.Exists(value))
this.filePath.Text = value;
if (!this.IsDirectory)
{
if (File.Exists(value))
this.filePath.Text = value;
else
this.filePath.Text = "";
}
else
this.filePath.Text = "";
{
if (Directory.Exists(value))
this.filePath.Text = value;
else
this.filePath.Text = "";
}
}
}
private async void browseClick(object sender, RoutedEventArgs e)
{
Window? currentWindow = this.VisualRoot as Window;
if (currentWindow is not Window) throw new Exception("could not find current window");
Button? btn = sender as Button;
if (btn is Button)
{
btn.IsEnabled = false;
OpenFileDialog browseDialog = new OpenFileDialog();
if (extension != "")
if (this.IsDirectory)
{
browseDialog.Filters = new List<FileDialogFilter>();
FileDialogFilter filter = new FileDialogFilter();
filter.Extensions.Add(extension);
filter.Name = fileTypeName;
browseDialog.Filters.Add(filter);
browseDialog.Title = "Select a " + fileTypeName + " file.";
// open directory
OpenFolderDialog browseDialog = new OpenFolderDialog();
if (this.ContainsFile) browseDialog.Directory = this.FilePath;
browseDialog.Title = "Select directory.";
string? directory = await browseDialog.ShowAsync(currentWindow);
if(directory is not null)
this.FilePath = directory;
}
else
{
browseDialog.Title = "Select a file.";
// open file
OpenFileDialog browseDialog = new OpenFileDialog();
if (extension != "")
{
browseDialog.Filters = new List<FileDialogFilter>();
FileDialogFilter filter = new FileDialogFilter();
filter.Extensions.Add(extension);
filter.Name = fileTypeName;
browseDialog.Filters.Add(filter);
browseDialog.Title = "Select " + fileTypeName;
}
else
{
browseDialog.Title = "Select a file.";
}
if (this.ContainsFile) browseDialog.Directory = Path.GetDirectoryName(this.FilePath);
string[]? selectedFiles = await browseDialog.ShowAsync(currentWindow);
if (selectedFiles is not null && selectedFiles.Length > 0)
this.FilePath = selectedFiles.First();
}
Window? currentWindow = this.VisualRoot as Window;
if (currentWindow is not Window) throw new Exception("could not find current window");
string[]? selectedFiles = await browseDialog.ShowAsync(currentWindow);
if (selectedFiles is not null && selectedFiles.Length > 0)
this.FilePath = selectedFiles.First();
btn.IsEnabled = true;
OnFileChanged(new EventArgs());
}
}

View File

@ -5,30 +5,31 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="40"
x:Class="ChovySign_GUI.Global.KeySelector">
<!-- key selector -->
<Border Padding="10 2" HorizontalAlignment="Stretch" VerticalAlignment="Top">
<Border Padding="10 3" HorizontalAlignment="Stretch" VerticalAlignment="Top">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>
<Grid HorizontalAlignment="Stretch" Grid.Column="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="10*" />
</Grid.ColumnDefinitions>
<Label HorizontalAlignment="Left" VerticalAlignment="Center" Content="Rif:" Grid.Column="0"/>
<TextBox HorizontalAlignment="Stretch" Watermark="GAME.RIF" Name="zRif" Grid.Column="1"/>
</Grid>
<Grid HorizontalAlignment="Stretch" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="10*" />
</Grid.ColumnDefinitions>
<Label HorizontalAlignment="Left" VerticalAlignment="Center" Content="Key:" Grid.Column="0"/>
<TextBox HorizontalAlignment="Stretch" Watermark="Version Key" Name="vKey" Grid.Column="1"/>
<TextBox HorizontalAlignment="Stretch" MaxLength="32" Watermark="Version Key" Name="vKey" Grid.Column="1"/>
</Grid>
<Button Name="getKeys" Click="getKeysClick" Content="Get Keys" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="2"/>
</Grid>
</Border>
</UserControl>

View File

@ -1,18 +1,33 @@
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Remote.Protocol.Input;
using ChovySign_GUI.Popup.Global;
using ChovySign_GUI.Popup.Global.KeySelector;
using GameBuilder.Psp;
using GameBuilder.VersionKey;
using Ionic.Zlib;
using Li.Utilities;
using LibChovy.Config;
using LibChovy.VersionKey;
using SixLabors.ImageSharp.PixelFormats;
using System;
using System.ComponentModel;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using Vita.ContentManager;
using Vita.PsvImgTools;
using static ChovySign_GUI.Popup.Global.MessageBox;
using static PspCrypto.SceNpDrm;
namespace ChovySign_GUI.Global
{
public partial class KeySelector : UserControl
{
private string licenseDataConfigKey
{
get
@ -28,20 +43,83 @@ namespace ChovySign_GUI.Global
}
}
private bool lastValid;
private int keyIndex = 1;
private NpDrmRif? npRif;
private byte[]? versionKey;
public bool IsValid
{
get
{
try
{
if (vKey.Text is null) return false;
if (vKey.Text.Length != 32) return false;
if (zRif.Text is null) return false;
if (zRif.Text.Length <= 0) return false;
byte[] key = MathUtil.StringToByteArray(vKey.Text);
byte[] rif = new NpDrmRif(zRif.Text).Rif;
if (rif.Length <= 0) return false;
return (VersionKey is not null && Rif is not null);
}
catch { return false; };
}
}
public byte[]? VersionKey
{
get
{
return versionKey;
}
set
{
if (value is null) return;
versionKey = value;
ChovyConfig.CurrentConfig.SetBytes(versionKeyConfigKey, versionKey);
vKey.Text = BitConverter.ToString(versionKey).Replace("-", "");
OnVersionKeyChanged(new EventArgs());
}
}
public byte[]? Rif
{
get
{
if (npRif is null) return null;
return npRif.Rif;
}
set
{
if (value is null) return;
npRif = new NpDrmRif(value);
zRif.Text = npRif.ZRif;
ChovyConfig.CurrentConfig.SetBytes(licenseDataConfigKey, npRif.Rif);
OnRifChanged(new EventArgs());
}
}
private void reloadCfg()
{
byte[]? licenseData = ChovyConfig.CurrentConfig.GetBytes(licenseDataConfigKey);
byte[]? vKeyData = ChovyConfig.CurrentConfig.GetBytes(versionKeyConfigKey);
byte[]? rifData = ChovyConfig.CurrentConfig.GetBytes(licenseDataConfigKey);
byte[]? vkeyData = ChovyConfig.CurrentConfig.GetBytes(versionKeyConfigKey);
if(vkeyData is not null)
{
vKey.Text = BitConverter.ToString(vkeyData).Replace("-", "");
versionKey = vkeyData;
}
if (licenseData is not null)
zRif.Text = new NpDrmRif(licenseData).ZRif;
if (vKeyData is not null)
vKey.Text = BitConverter.ToString(vKeyData).Replace("-", "");
if (rifData is not null)
{
npRif = new NpDrmRif(rifData);
zRif.Text = npRif.ZRif;
}
}
private async void getKeysClick(object sender, RoutedEventArgs e)
@ -57,32 +135,68 @@ namespace ChovySign_GUI.Global
KeyObtainMethods keyObt = new KeyObtainMethods();
keyObt.KeyIndex = keyIndex;
VersionKeyMethod method = await keyObt.ShowDialog<VersionKeyMethod>(currentWindow);
VersionKeyMethod? method = await keyObt.ShowDialog<VersionKeyMethod>(currentWindow);
if (method is null) return;
byte[]? key = null;
NpDrmInfo? key = null;
NpDrmRif? rif = null;
switch (method)
{
case VersionKeyMethod.ACT_RIF_METHOD:
ActRifMethodGUI actRifMethodGUI = new ActRifMethodGUI();
byte[][]? keys = await actRifMethodGUI.ShowDialog<byte[][]>(currentWindow);
NpDrmInfo[]? keys = await actRifMethodGUI.ShowDialog<NpDrmInfo[]>(currentWindow);
if (keys is null) break;
key = keys[keyIndex];
rif = actRifMethodGUI.Rif;
break;
case VersionKeyMethod.EBOOT_PBP_METHOD:
CmaBackupPicker ebootBackupSelector = new CmaBackupPicker();
ebootBackupSelector.BackupType = ((keyIndex == 1) ? "PSGAME" : "PGAME");
string? gameBackupFolder = await ebootBackupSelector.ShowDialog<string>(currentWindow);
string accountId = ebootBackupSelector.AccountId;
if (gameBackupFolder is null) break;
if (accountId == "") break;
key = CMAVersionKeyHelper.GetKeyFromGamePsvimg(gameBackupFolder, accountId);
rif = CMAVersionKeyHelper.GetRifFromLicensePsvimg(gameBackupFolder, accountId);
break;
case VersionKeyMethod.KEYS_TXT_METHOD:
CmaBackupPicker pspLicenseBackupSelector = new CmaBackupPicker();
pspLicenseBackupSelector.BackupType = "PGAME";
pspLicenseBackupSelector.Filter = KeysTxtMethod.TitleIds;
gameBackupFolder = await pspLicenseBackupSelector.ShowDialog<string>(currentWindow);
accountId = pspLicenseBackupSelector.AccountId;
if (gameBackupFolder is null) break;
if (accountId == "") break;
rif = CMAVersionKeyHelper.GetRifFromLicensePsvimg(gameBackupFolder, accountId);
if (rif is null) break;
key = KeysTxtMethod.GetVersionKey(rif.ContentId, this.KeyIndex);
break;
}
if (key is not null)
{
ChovyConfig.CurrentConfig.SetBytes(versionKeyConfigKey, key);
vKey.Text = BitConverter.ToString(key).Replace("-", "");
if (key.KeyIndex != this.keyIndex)
{
await MessageBox.Show(currentWindow, "VersionKey obtained, but had keyindex: " + key.KeyIndex + " however keyindex " + this.keyIndex + " was required.", "KeyIndex mismatch!", MessageBoxButtons.Ok);
return;
}
VersionKey = key.VersionKey;
}
if (rif is not null)
{
ChovyConfig.CurrentConfig.SetBytes(licenseDataConfigKey, rif.Rif);
zRif.Text = rif.ZRif;
}
Rif = rif.Rif;
btn.IsEnabled = true;
}
@ -99,10 +213,77 @@ namespace ChovySign_GUI.Global
reloadCfg();
}
}
public event EventHandler<EventArgs>? VersionKeyChanged;
protected virtual void OnVersionKeyChanged(EventArgs e)
{
if (IsValid != lastValid) OnValidStateChanged(new EventArgs());
if (VersionKeyChanged is not null)
VersionKeyChanged(this, e);
}
public event EventHandler<EventArgs>? RifChanged;
protected virtual void OnRifChanged(EventArgs e)
{
if (IsValid != lastValid) OnValidStateChanged(new EventArgs());
if (RifChanged is not null)
RifChanged(this, e);
}
public event EventHandler<EventArgs>? ValidStateChanged;
protected virtual void OnValidStateChanged(EventArgs e)
{
lastValid = IsValid;
if (ValidStateChanged is not null)
ValidStateChanged(this, e);
}
public KeySelector()
{
InitializeComponent();
reloadCfg();
lastValid = IsValid;
zRif.KeyDown += onZrifKeyDown;
zRif.KeyUp += onZrifKeyDown;
vKey.KeyDown += onVkeyKeyDown;
vKey.KeyUp += onVkeyKeyDown;
}
private void onVkeyKeyDown(object? sender, Avalonia.Input.KeyEventArgs e)
{
TextBox? txt = sender as TextBox;
if (txt is null) return;
if (lastValid != IsValid)
OnValidStateChanged(new EventArgs());
try
{
if (txt.Text is null) return;
if (txt.Text.Length != 32) return;
this.VersionKey = MathUtil.StringToByteArray(txt.Text);
}
catch { };
}
private void onZrifKeyDown(object? sender, KeyEventArgs e)
{
TextBox? txt = sender as TextBox;
if (txt is null) return;
if (lastValid != IsValid)
OnValidStateChanged(new EventArgs());
try
{
byte[] rifBytes = new NpDrmRif(txt.Text).Rif;
if (rifBytes.Length != 0) this.Rif = rifBytes;
}
catch { };
}
}
}

View File

@ -0,0 +1,16 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="80"
x:Class="ChovySign_GUI.Global.LabeledComboBox"
Height="60">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Label Name="lblTxt" Content="Label:" VerticalAlignment="Bottom" Grid.Row="0"/>
<ComboBox Name="comboBox" HorizontalAlignment="Stretch" VerticalAlignment="Center" Grid.Row="1"/>
</Grid>
</UserControl>

View File

@ -0,0 +1,81 @@
using Avalonia.Controls;
using System;
using System.Collections.Generic;
namespace ChovySign_GUI.Global
{
public partial class LabeledComboBox : UserControl
{
private List<string> items;
public string Label
{
get
{
string? lbl = this.lblTxt.Content as string;
if (lbl is null) return "";
else return lbl;
}
set
{
this.lblTxt.Content = value;
}
}
public int SelectedIndex
{
get
{
return this.comboBox.SelectedIndex;
}
set
{
this.comboBox.SelectedIndex = value;
OnSelectionChanged(new EventArgs());
}
}
public string SelectedItem
{
get
{
string? itm = this.comboBox.SelectedItem as string;
if (itm is null) return "";
else return itm;
}
set
{
this.comboBox.SelectedItem = value;
OnSelectionChanged(new EventArgs());
}
}
public string[] Items
{
set
{
this.comboBox.Items = value;
}
}
public event EventHandler<EventArgs>? SelectionChanged;
protected virtual void OnSelectionChanged(EventArgs e)
{
if (SelectionChanged is not null)
SelectionChanged(this, e);
}
public LabeledComboBox()
{
InitializeComponent();
this.comboBox.SelectionChanged += onComboBoxSelectionChange;
}
private void onComboBoxSelectionChange(object? sender, SelectionChangedEventArgs e)
{
OnSelectionChanged(new EventArgs());
}
}
}

View File

@ -11,6 +11,6 @@
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Label Name="lblTxt" Content="Label:" VerticalAlignment="Bottom" Grid.Row="0"/>
<TextBox Name="txtBox" HorizontalAlignment="Stretch" VerticalAlignment="Center" MaxLength="128" Grid.Row="1"/>
<TextBox Name="txtBox" HorizontalAlignment="Stretch" VerticalAlignment="Center" Grid.Row="1"/>
</Grid>
</UserControl>

View File

@ -8,9 +8,10 @@ namespace ChovySign_GUI.Global
{
public partial class LabeledTextBox : UserControl
{
public event EventHandler<EventArgs>? TextChanged;
private string lastTxt;
private string? allowedChars;
public event EventHandler<EventArgs>? TextChanged;
protected virtual void OnTextChanged(EventArgs e)
{
if (TextChanged is not null)
@ -95,6 +96,7 @@ namespace ChovySign_GUI.Global
InitializeComponent();
lastTxt = this.txtBox.Text;
allowedChars = null;
this.txtBox.KeyDown += onKeyUp;
this.txtBox.KeyUp += onKeyUp;
}

View File

@ -10,14 +10,14 @@
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Label Name="progressStatus" Content="Progress %" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Grid.Row="0"/>
<Label Name="statusLbl" Content="Progress %" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Grid.Row="0"/>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="15*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<ProgressBar HorizontalAlignment="Stretch" VerticalAlignment="Top" Height="30" Grid.Column="0"/>
<Button Name="goButton" Content="Go!" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Column="1"/>
<ProgressBar Name="progressVal" Maximum="100" Minimum="0" HorizontalAlignment="Stretch" VerticalAlignment="Top" Height="30" Grid.Column="0"/>
<Button Name="goButton" Click="goClick" Content="Go!" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Column="1"/>
</Grid>
</Grid>

View File

@ -1,12 +1,66 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Threading;
using ChovySign_GUI.Popup.Global;
using Li.Progress;
using LibChovy;
using System;
using System.Threading.Tasks;
using static ChovySign_GUI.Popup.Global.MessageBox;
namespace ChovySign_GUI.Global
{
public partial class ProgressStatus : UserControl
{
public ChovySignParameters? Parameters = null;
private ChovySign chovySign;
public ProgressStatus()
{
InitializeComponent();
chovySign = new ChovySign();
chovySign.RegisterCallback(onProgress);
}
public event EventHandler<EventArgs>? BeforeStart;
protected virtual void OnBeforeStart(EventArgs e)
{
if (BeforeStart is not null)
BeforeStart(this, e);
}
public event EventHandler<EventArgs>? Finished;
protected virtual void OnFinished(EventArgs e)
{
if (Finished is not null)
Finished(this, e);
}
private async void goClick(object sender, RoutedEventArgs e)
{
Window? currentWindow = this.VisualRoot as Window;
if (currentWindow is not Window) throw new Exception("could not find current window");
this.goButton.IsEnabled = false;
OnBeforeStart(new EventArgs());
if(Parameters is null) { await MessageBox.Show(currentWindow, "ChovySignParameters was null, cannot start!", "Invalid Parameters", MessageBoxButtons.Ok); return; }
await Task.Run(() => { chovySign.Go(Parameters); });
OnFinished(new EventArgs());
this.goButton.IsEnabled = true;
}
private void onProgress(ProgressInfo inf)
{
Dispatcher.UIThread.Post(() =>
{
this.statusLbl.Content = inf.CurrentProcess + " (" + inf.Done + "/" + inf.Remain + ") " + inf.ProgressInt + "%";
this.progressVal.Value = inf.Progress;
});
}
}
}

BIN
ChovySign-GUI/ICON.ICO Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
ChovySign-GUI/ICON.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -6,7 +6,7 @@
xmlns:Psp="clr-namespace:ChovySign_GUI.Psp"
mc:Ignorable="d" d:DesignWidth="850" d:DesignHeight="950"
x:Class="ChovySign_GUI.MainWindow"
Title="Chovy Sign V2">
Title="Chovy Sign V2" Icon="/ICON.PNG">
<Grid>
<TabControl>

View File

@ -0,0 +1,30 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Global="clr-namespace:ChovySign_GUI.Global"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ChovySign_GUI.Popup.Global.CmaBackupPicker"
Title="Select a Content Manager Backup." Icon="/ICON.PNG">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="75"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<Grid VerticalAlignment="Top" Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Global:BrowseButton Name="cmaDir" Label="CMA Directory" IsDirectory="True" Grid.Column="0" HorizontalAlignment="Stretch"/>
<Global:LabeledComboBox Name="accId" Label="Account ID" Grid.Column="1" HorizontalAlignment="Stretch"/>
</Grid>
<ListBox Name="backupList" VerticalAlignment="Stretch" Grid.Row="1"/>
<Button Name="selectBtn" Click="selectBtnClick" Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Center">Select "Content Manager" Backup</Button>
<Label Name="lookingInLbl" Content="Looking in:" Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left"/>
</Grid>
</Window>

View File

@ -0,0 +1,218 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using ChovySign_GUI.Global;
using GameBuilder.Psp;
using LibChovy.Config;
using Org.BouncyCastle.Utilities.Bzip2;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Vita.ContentManager;
namespace ChovySign_GUI.Popup.Global
{
public partial class CmaBackupPicker : Window
{
private const string lookingInLabelText = "Looking in: ";
private string[]? gameDirectories;
private string backupSubFolder = "";
private string[]? filter;
private string? cmaAccountId = null;
private string? cmaBackupDir = null;
private const string backupPickerCmaDirectoryConfigKey = "BACKUP_PICKER_CMA_DIRECTORY";
public string[] Filter
{
set
{
this.filter = value;
reloadBackupsList();
}
}
public string AccountId
{
get
{
if (cmaAccountId is null) return "";
else return cmaAccountId;
}
set
{
cmaAccountId = value;
}
}
public string BackupDir
{
get
{
if(cmaBackupDir is null)
{
string? savedBackupFolder = ChovyConfig.CurrentConfig.GetString(backupPickerCmaDirectoryConfigKey);
if (savedBackupFolder is null) savedBackupFolder = SettingsReader.BackupsFolder;
cmaBackupDir = savedBackupFolder;
}
return cmaBackupDir;
}
set
{
if (Directory.Exists(value))
{
cmaBackupDir = value;
ChovyConfig.CurrentConfig.SetString(backupPickerCmaDirectoryConfigKey, cmaBackupDir);
}
}
}
private string accountIdSearchFolder
{
get
{
string searchIn = Path.Combine(BackupDir, this.BackupType);
return searchIn;
}
}
private string backupSearchFolder
{
get
{
if (AccountId == "") return accountIdSearchFolder;
return Path.Combine(accountIdSearchFolder, AccountId);
}
}
public string BackupType
{
get
{
return backupSubFolder;
}
set
{
backupSubFolder = value;
lookingInLbl.Content = lookingInLabelText + backupSubFolder;
reloadAccountIdsList();
reloadBackupsList();
}
}
private void reloadAccountIdsList()
{
try
{
string[] usedAccountIds = Directory.GetDirectories(accountIdSearchFolder);
List<string> accountIdLst = new List<string>();
foreach (string accountId in usedAccountIds)
{
string aid = Path.GetFileName(accountId);
if (aid.Length != 16) continue;
accountIdLst.Add(aid);
}
this.accId.Items = accountIdLst.ToArray();
if (accountIdLst.Count > 0)
this.accId.SelectedIndex = 0;
}
catch { };
this.selectBtn.IsEnabled = false;
}
private void selectBtnClick(object sender, RoutedEventArgs e)
{
if (gameDirectories is null) { this.Close(); return; }
if (this.backupList.SelectedIndex == -1) { this.Close(); return; }
string selectedDir = gameDirectories[this.backupList.SelectedIndex];
if (Directory.Exists(selectedDir))
this.Close(selectedDir);
else
this.Close();
}
private void reloadBackupsList()
{
this.selectBtn.IsEnabled = false;
this.backupList.Items = new string[0];
try
{
if(!Directory.Exists(backupSearchFolder)) { return; }
string[] gameBackupDirectories = Directory.GetDirectories(backupSearchFolder);
List<string> filteredGameDirectories = new List<string>();
List<string> gameList = new List<string>();
foreach (string gameDirectory in gameBackupDirectories)
{
string paramFile = Path.Combine(gameDirectory, "sce_sys", "param.sfo");
if (File.Exists(paramFile))
{
try
{
Sfo psfo = Sfo.ReadSfo(File.ReadAllBytes(paramFile));
string? discId = psfo["DISC_ID"] as string;
string? title = psfo["TITLE"] as string;
if (discId is null) continue;
if (title is null) continue;
// filter games set in "Filter" property.
if (filter is not null)
if (!filter.Any(discId.Contains)) continue;
gameList.Add(discId + " - " + title);
filteredGameDirectories.Add(gameDirectory);
}
catch { continue; };
}
}
this.gameDirectories = filteredGameDirectories.ToArray();
this.backupList.Items = gameList;
}
catch { }
}
public CmaBackupPicker()
{
InitializeComponent();
this.cmaDir.FilePath = BackupDir;
this.backupSubFolder = "APP";
this.accId.SelectionChanged += onAccountSelectionChanged;
this.cmaDir.FileChanged += onCmaDirChanged;
this.backupList.SelectionChanged += onSelectedBackupChanged;
reloadAccountIdsList();
reloadBackupsList();
}
private void onSelectedBackupChanged(object? sender, SelectionChangedEventArgs e)
{
ListBox? lstBox = sender as ListBox;
if (lstBox.SelectedIndex == -1) selectBtn.IsEnabled = false;
else selectBtn.IsEnabled = true;
}
private void onAccountSelectionChanged(object? sender, System.EventArgs e)
{
LabeledComboBox? cbox = sender as LabeledComboBox;
if (cbox is null) return;
AccountId = cbox.SelectedItem;
reloadBackupsList();
}
private void onCmaDirChanged(object? sender, System.EventArgs e)
{
BrowseButton? button = sender as BrowseButton;
if (button is null) return;
if (button.ContainsFile)
{
BackupDir = button.FilePath;
reloadAccountIdsList();
reloadBackupsList();
}
}
}
}

View File

@ -3,10 +3,11 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Global="clr-namespace:ChovySign_GUI.Global"
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="200"
mc:Ignorable="d" d:DesignWidth="450" d:DesignHeight="200"
x:Class="ChovySign_GUI.Popup.Global.KeySelector.ActRifMethodGUI"
SizeToContent="Height" MinWidth="600" MinHeight="200" CanResize="False"
Title="Act/Rif Method">
SizeToContent="Height" Width="450" Height="200"
MinWidth="450" MinHeight="200" CanResize="False"
Title="Act/Rif Method" Icon="/ICON.PNG">
<Grid>
<Grid.RowDefinitions>

View File

@ -1,10 +1,10 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using ChovySign_GUI.Global;
using GameBuilder.Psp;
using GameBuilder.VersionKey;
using Li.Utilities;
using LibChovy.Config;
using LibChovy.VersionKey;
using GameBuilder.Psp;
using Li.Utilities;
using System;
using System.IO;
using static ChovySign_GUI.Popup.Global.MessageBox;
@ -104,7 +104,7 @@ namespace ChovySign_GUI.Popup.Global.KeySelector
private void keyGenClick(object sender, RoutedEventArgs e)
{
byte[][] keys = new byte[0x5][];
NpDrmInfo[] keys = new NpDrmInfo[0x5];
Window? currentWindow = this.VisualRoot as Window;
if (currentWindow is not Window) throw new Exception("could not find current window");
@ -118,7 +118,7 @@ namespace ChovySign_GUI.Popup.Global.KeySelector
// generate keys
for (int i = 0; i < 0x5; i++)
keys[i] = ActRifMethod.GetVersionKey(act, rif, idps, i).VersionKey;
keys[i] = ActRifMethod.GetVersionKey(act, rif, idps, i);
this.rif = new NpDrmRif(rif);

View File

@ -5,7 +5,7 @@
mc:Ignorable="d" d:DesignWidth="1400" d:DesignHeight="150"
x:Class="ChovySign_GUI.Popup.Global.KeySelector.KeyObtainMethods"
Title="VersionKey Obtain Method" SizeToContent="WidthAndHeight"
MaxWidth="1400" MaxHeight="150">
MaxWidth="1400" MaxHeight="150" Icon="/ICON.PNG">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5*"/>

View File

@ -1,6 +1,6 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using GameBuilder.VersionKey;
using LibChovy.VersionKey;
namespace ChovySign_GUI.Popup.Global.KeySelector
{

View File

@ -3,9 +3,10 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ChovySign_GUI.Popup.Global.MessageBox" SizeToContent="WidthAndHeight" CanResize="False">
x:Class="ChovySign_GUI.Popup.Global.MessageBox"
SizeToContent="WidthAndHeight" CanResize="False" Icon="/ICON.PNG">
<StackPanel HorizontalAlignment="Center">
<TextBlock HorizontalAlignment="Center" Name="Text"/>
<TextBlock Foreground="LightGreen" HorizontalAlignment="Center" Name="Text"/>
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Name="Buttons">
<StackPanel.Styles>
<Style Selector="Button">

View File

@ -22,10 +22,10 @@ namespace ChovySign_GUI.Ps1
List<string> discList = new List<string>();
if (discCue1.ContainsFile) discList.Add(discCue1.FilePath);
else if (discCue2.ContainsFile) discList.Add(discCue2.FilePath);
else if (discCue3.ContainsFile) discList.Add(discCue3.FilePath);
else if (discCue4.ContainsFile) discList.Add(discCue4.FilePath);
else if (discCue5.ContainsFile) discList.Add(discCue5.FilePath);
if (discCue2.ContainsFile) discList.Add(discCue2.FilePath);
if (discCue3.ContainsFile) discList.Add(discCue3.FilePath);
if (discCue4.ContainsFile) discList.Add(discCue4.FilePath);
if (discCue5.ContainsFile) discList.Add(discCue5.FilePath);
return discList.ToArray();
}

View File

@ -19,7 +19,7 @@
<RowDefinition Height="52"/>
<RowDefinition Height="52"/>
</Grid.RowDefinitions>
<Global:LabeledTextBox HorizontalAlignment="Stretch" Name="gameTitle" Label="Title:" Watermark="The BEST PlayStation 1 Game" Grid.Row="0"/>
<Global:LabeledTextBox HorizontalAlignment="Stretch" Name="gameTitle" Label="Title:" Watermark="The BEST PlayStation 1 Game" MaxLength="128" Grid.Row="0"/>
<Global:BrowseButton HorizontalAlignment="Stretch" Name="iconFile" Extension="png" FileTypeName="Portable Network Graphics" Watermark="(Default)" Label="icon0.png:" Grid.Row="1"/>
<Global:BrowseButton HorizontalAlignment="Stretch" Name="pic0File" Extension="png" FileTypeName="Portable Network Graphics" Watermark="(Default)" Label="pic0.png:" Grid.Row="2"/>
<Global:BrowseButton HorizontalAlignment="Stretch" Name="pic1File" Extension="png" FileTypeName="Portable Network Graphics" Watermark="(Default)" Label="pic1.png:" Grid.Row="3"/>

View File

@ -20,6 +20,18 @@ namespace ChovySign_GUI.Ps1
private byte[] pic0Cache;
private byte[] pic1Cache;
public string Title
{
get
{
if (this.gameTitle.Text is null) return "";
return this.gameTitle.Text;
}
set
{
this.gameTitle.Text = value;
}
}
public byte[] Icon0
{
get
@ -73,7 +85,7 @@ namespace ChovySign_GUI.Ps1
try
{
DiscInfo disc = new DiscInfo(cueFile);
this.gameTitle.Text = disc.DiscName;
Title = disc.DiscName;
byte[] newCover = await Downloader.DownloadCover(disc);
loadIcon(newCover);
@ -129,6 +141,12 @@ namespace ChovySign_GUI.Ps1
Pic1 = await doLoad(button, 480, 272);
}
public event EventHandler<EventArgs>? TitleChanged;
protected virtual void OnTitleChanged(EventArgs e)
{
if (TitleChanged is not null)
TitleChanged(this, e);
}
public GameInfoSelector()
{
InitializeComponent();
@ -142,8 +160,13 @@ namespace ChovySign_GUI.Ps1
this.pic0File.FileChanged += onPic0Change;
this.pic1File.FileChanged += onPic1Change;
this.gameTitle.TextChanged += onTitleChange;
}
private void onTitleChange(object? sender, EventArgs e)
{
OnTitleChanged(new EventArgs());
}
}
}

View File

@ -29,6 +29,7 @@
</Grid>
<!-- Credits -->
<CheckBox Name="devkitAccount" Content="I have a DevKit, TestKit or IDU Vita" VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
<Label Content="Li, Dots TB, SquallATF, Motoharu, Davee" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
</Grid>
</UserControl>

View File

@ -1,27 +1,140 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using ChovySign_GUI.Global;
using ChovySign_GUI.Popup.Global;
using GameBuilder.Psp;
using LibChovy;
using LibChovy.Config;
using System;
using System.Linq;
using Vita.ContentManager;
using static ChovySign_GUI.Popup.Global.MessageBox;
namespace ChovySign_GUI.Ps1
{
public partial class Ps1Tab : UserControl
{
private const string useDevkitModeConfigKey = "USE_DEVKIT_ACCOUNT_ID";
private async void onDevkitModeChecked(object? sender, RoutedEventArgs e)
{
CheckBox? checkBox = sender as CheckBox;
if (checkBox is null) return;
bool? devMode = checkBox.IsChecked;
if (devMode is null) devMode = false;
Window? currentWindow = this.VisualRoot as Window;
if (currentWindow is not Window) throw new Exception("could not find current window");
MessageBoxResult res = await MessageBox.Show(currentWindow, "This option will force the CMA Account ID to be all 0's\nWhich is how it is on Devkit, Testkit and IDU Firmware\nEnabling this if you have a retail firmware will result in the games just *not* showing up\n\nIf you DON'T know what this means, DON'T enable this.\ndo you want to continue?", "Are you sure?", MessageBoxButtons.YesNo);
if (res == MessageBoxResult.Yes)
{
ChovyConfig.CurrentConfig.SetBool(useDevkitModeConfigKey, (bool)devMode);
}
else
{
e.Handled = true;
checkBox.IsChecked = false;
}
}
private void onDevkitModeUnchecked(object? sender, RoutedEventArgs e)
{
CheckBox? checkBox = sender as CheckBox;
if (checkBox is null) return;
bool? devMode = checkBox.IsChecked;
if (devMode is null) devMode = false;
ChovyConfig.CurrentConfig.SetBool(useDevkitModeConfigKey, (bool)devMode);
}
public Ps1Tab()
{
InitializeComponent();
discSelector.DiscsSelected += onDiscSelected;
devkitAccount.IsChecked = ChovyConfig.CurrentConfig.GetBool(useDevkitModeConfigKey);
devkitAccount.Unchecked += onDevkitModeUnchecked;
devkitAccount.Checked += onDevkitModeChecked;
progressStatus.IsEnabled = false;
discSelector.DiscsSelected += onDiscSelected;
keySelector.ValidStateChanged += onKeyValidityChanged;
gameInfo.TitleChanged += onTitleChanged;
progressStatus.BeforeStart += onProcessStarting;
progressStatus.Finished += onProcessFinished;
check();
}
private void onDiscSelected(object? sender, System.EventArgs e)
private async void onProcessFinished(object? sender, EventArgs e)
{
keySelector.IsEnabled = true;
discSelector.IsEnabled = true;
gameInfo.IsEnabled = true;
Window? currentWindow = this.VisualRoot as Window;
if (currentWindow is not Window) throw new Exception("could not find current window");
await MessageBox.Show(currentWindow, "Finished creating PS1 Game!\nCan now go restore it to your PSVita using Content Manager.", "Done!", MessageBoxButtons.Ok);
}
private void onProcessStarting(object? sender, EventArgs e)
{
keySelector.IsEnabled = false;
discSelector.IsEnabled = false;
gameInfo.IsEnabled = false;
if (keySelector.Rif is null) return;
if (keySelector.VersionKey is null) return;
NpDrmRif rifInfo = new NpDrmRif(keySelector.Rif);
NpDrmInfo drmInfo = new NpDrmInfo(keySelector.VersionKey, rifInfo.ContentId, keySelector.KeyIndex);
PspParameters pspParameters = new PspParameters(drmInfo, rifInfo);
PopsParameters popsParameters = new PopsParameters(drmInfo, rifInfo);
foreach (string disc in discSelector.Discs)
popsParameters.AddCd(disc);
popsParameters.Name = gameInfo.Title;
popsParameters.Icon0 = gameInfo.Icon0;
popsParameters.Pic0 = gameInfo.Pic0;
popsParameters.Pic1 = gameInfo.Pic1;
if (devkitAccount.IsChecked == true)
popsParameters.Account = new Account(0);
progressStatus.Parameters = popsParameters;
}
private void onTitleChanged(object? sender, EventArgs e)
{
check();
}
private void check()
{
this.progressStatus.IsEnabled = (discSelector.AnyDiscsSelected && keySelector.IsValid && gameInfo.Title != "");
}
private void onKeyValidityChanged(object? sender, EventArgs e)
{
KeySelector? keySelector = sender as KeySelector;
if (keySelector is null) return;
check();
}
private async void onDiscSelected(object? sender, EventArgs e)
{
CueSelector? cueSelector = sender as CueSelector;
if (cueSelector is null) return;
if (cueSelector.AnyDiscsSelected)
_ = this.gameInfo.GetGameInfo(cueSelector.Discs.First());
else
progressStatus.IsEnabled = false;
await this.gameInfo.GetGameInfo(cueSelector.Discs.First());
check();
}
}
}

View File

@ -18,7 +18,7 @@
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Image HorizontalAlignment="Center" VerticalAlignment="Center" Width="120" Source="/Psp/UMD.PNG" Grid.Row="0"/>
<CheckBox Content="Compress PBP" HorizontalAlignment="Center" Grid.Row="1"/>
<CheckBox Name="compressPbp" Content="Compress PBP" HorizontalAlignment="Center" Grid.Row="1"/>
</Grid>
<Global:BrowseButton Name="umdFile" Extension="iso" FileTypeName="Universal Media Disc 'UMD' Disc Image (ISO9660)" Label="UMD Image:" Grid.Column="1"/>
</Grid>

View File

@ -1,12 +1,54 @@
using Avalonia.Controls;
using GameBuilder.Psp;
using System;
namespace ChovySign_GUI.Psp
{
public partial class IsoSelector : UserControl
{
public event EventHandler<EventArgs>? UmdChanged;
protected virtual void OnUmdChanged(EventArgs e)
{
if (UmdChanged is not null)
UmdChanged(this, e);
}
public bool Compress
{
get
{
if (this.compressPbp.IsChecked is null) return false;
return (bool)this.compressPbp.IsChecked;
}
set
{
this.compressPbp.IsChecked = value;
}
}
public bool HasUmd
{
get
{
return this.umdFile.ContainsFile;
}
}
public UmdInfo? Umd
{
get
{
if (!this.umdFile.ContainsFile) return null;
return new UmdInfo(this.umdFile.FilePath);
}
}
public IsoSelector()
{
InitializeComponent();
this.umdFile.FileChanged += onUmdFileChanged;
}
private void onUmdFileChanged(object? sender, EventArgs e)
{
OnUmdChanged(new EventArgs());
}
}
}

View File

@ -26,6 +26,7 @@
</Grid>
<!-- Credits -->
<CheckBox Name="devkitAccount" Content="I have a DevKit, TestKit or IDU Vita" VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
<Label Content="Li, Dots TB, SquallATF, Motoharu, Davee" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
</Grid>
</UserControl>

View File

@ -1,14 +1,109 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using ChovySign_GUI.Popup.Global;
using GameBuilder.Psp;
using LibChovy;
using LibChovy.Config;
using System;
using Vita.ContentManager;
using static ChovySign_GUI.Popup.Global.MessageBox;
namespace ChovySign_GUI.Psp
{
public partial class PspTab : UserControl
{
private const string useDevkitModeConfigKey = "USE_DEVKIT_ACCOUNT_ID";
private async void onDevkitModeChecked(object? sender, RoutedEventArgs e)
{
CheckBox? checkBox = sender as CheckBox;
if (checkBox is null) return;
bool? devMode = checkBox.IsChecked;
if (devMode is null) devMode = false;
Window? currentWindow = this.VisualRoot as Window;
if (currentWindow is not Window) throw new Exception("could not find current window");
MessageBoxResult res = await MessageBox.Show(currentWindow, "This option will force the CMA Account ID to be all 0's\nWhich is how it is on Devkit, Testkit and IDU Firmware\nEnabling this if you have a retail firmware will result in the games just *not* showing up\n\nIf you DON'T know what this means, DON'T enable this.\ndo you want to continue?", "Are you sure?", MessageBoxButtons.YesNo);
if (res == MessageBoxResult.Yes)
{
ChovyConfig.CurrentConfig.SetBool(useDevkitModeConfigKey, (bool)devMode);
}
else
{
e.Handled = true;
checkBox.IsChecked = false;
}
}
private void onDevkitModeUnchecked(object? sender, RoutedEventArgs e)
{
CheckBox? checkBox = sender as CheckBox;
if (checkBox is null) return;
bool? devMode = checkBox.IsChecked;
if (devMode is null) devMode = false;
ChovyConfig.CurrentConfig.SetBool(useDevkitModeConfigKey, (bool)devMode);
}
private void check()
{
this.progressStatus.IsEnabled = (this.keySelector.IsValid && this.isoSelector.HasUmd);
}
public PspTab()
{
InitializeComponent();
devkitAccount.IsChecked = ChovyConfig.CurrentConfig.GetBool(useDevkitModeConfigKey);
devkitAccount.Unchecked += onDevkitModeUnchecked;
devkitAccount.Checked += onDevkitModeChecked;
this.progressStatus.IsEnabled = false;
keySelector.ValidStateChanged += onValidStateChange;
isoSelector.UmdChanged += onUmdChanged;
progressStatus.BeforeStart += onProcessStarting;
progressStatus.Finished += onProcessFinished;
check();
}
private async void onProcessFinished(object? sender, EventArgs e)
{
keySelector.IsEnabled = true;
isoSelector.IsEnabled = true;
Window? currentWindow = this.VisualRoot as Window;
if (currentWindow is not Window) throw new Exception("could not find current window");
await MessageBox.Show(currentWindow, "Finished creating PSP Game!\nCan now go restore it to your PSVita using Content Manager.", "Done!", MessageBoxButtons.Ok);
}
private void onProcessStarting(object? sender, EventArgs e)
{
keySelector.IsEnabled = false;
isoSelector.IsEnabled = false;
if (keySelector.Rif is null) return;
if (keySelector.VersionKey is null) return;
NpDrmRif rifInfo = new NpDrmRif(keySelector.Rif);
NpDrmInfo drmInfo = new NpDrmInfo(keySelector.VersionKey, rifInfo.ContentId, keySelector.KeyIndex);
PspParameters pspParameters = new PspParameters(drmInfo, rifInfo);
UmdInfo? umd = isoSelector.Umd;
if (umd is null) return;
pspParameters.Umd = umd;
pspParameters.Compress = isoSelector.Compress;
progressStatus.Parameters = pspParameters;
}
private void onUmdChanged(object? sender, EventArgs e)
{
check();
}
private void onValidStateChange(object? sender, EventArgs e)
{
check();
}
}
}

View File

@ -80,16 +80,6 @@ namespace GameBuilder {
}
}
/// <summary>
/// Looks up a localized string similar to EP9000-NPEG00005_00-0000000000000001 51409FAC25DEAD80B44A9DAF0EB6A335 A0B1439B8E76B90AB2169978750B1E84 5AB0B5E2C32EE3BAFEF80ADE35BD7888 0B8450E063523674011C6B2B94829F7A
///.
/// </summary>
public static string KEYSTXT {
get {
return ResourceManager.GetString("KEYSTXT", resourceCulture);
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>

View File

@ -124,9 +124,6 @@
<data name="DATAPSPSDCFG" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\DATAPSPSDCFG.BIN;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="KEYSTXT" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\KEYS.TXT;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="SIMPLE" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\SIMPLE.PNG;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>

View File

@ -1,31 +0,0 @@
using GameBuilder.Psp;
using Li.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GameBuilder.VersionKey
{
public class KeysTxtMethod
{
public static NpDrmInfo GetVersionKey(string contentId, int keyIndex)
{
using (TextReader txt = new StringReader(Resources.KEYSTXT))
{
for(string? line = txt.ReadLine();
line is not null;
line = txt.ReadLine())
{
line = line.ReplaceLineEndings("");
string[] data = line.Split(' ');
if (data[0].Equals(contentId, StringComparison.InvariantCultureIgnoreCase))
return new NpDrmInfo(MathUtil.StringToByteArray(data[1 + keyIndex]), contentId, keyIndex);
}
}
throw new Exception("content id is not in keys.txt");
}
}
}

View File

@ -1,4 +1,5 @@
using GameBuilder.Psp;
using LibChovy.Config;
using System;
using System.Collections.Generic;
using System.Linq;
@ -14,6 +15,7 @@ namespace LibChovy
{
this.DrmInfo = drmInfo;
this.DrmRif = rif;
this.Account = new Account(DrmRif.AccountId);
this.CreatePsvImg = true;
this.FirmwareVersion = 0x3600000;

View File

@ -93,6 +93,10 @@ namespace LibChovy
if (pic1 is null) return Resources.PIC1;
else return pic1;
}
set
{
pic1 = value;
}
}
public void AddCd(string cd)

View File

@ -70,6 +70,16 @@ namespace LibChovy {
}
}
/// <summary>
/// Looks up a localized string similar to EP9000-NPEG00005_00-0000000000000001 51409FAC25DEAD80B44A9DAF0EB6A335 A0B1439B8E76B90AB2169978750B1E84 5AB0B5E2C32EE3BAFEF80ADE35BD7888 0B8450E063523674011C6B2B94829F7A
///.
/// </summary>
public static string KEYSTXT {
get {
return ResourceManager.GetString("KEYSTXT", resourceCulture);
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>

View File

@ -121,6 +121,9 @@
<data name="ICON0" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\ICON0.PNG;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="KEYSTXT" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\KEYS.TXT;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="PIC0" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\PIC0.PNG;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>

View File

@ -1,5 +1,4 @@
using GameBuilder.Psp;
using Org.BouncyCastle.Asn1.Pkcs;
using PspCrypto;
using System;
using System.Collections.Generic;
@ -7,7 +6,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GameBuilder.VersionKey
namespace LibChovy.VersionKey
{
public class ActRifMethod
{

View File

@ -0,0 +1,61 @@
using GameBuilder.Psp;
using Li.Utilities;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Vita.ContentManager;
using Vita.PsvImgTools;
namespace LibChovy.VersionKey
{
public class CMAVersionKeyHelper
{
public static PSVIMGFileStream? GetFileFromPsvImg(string psvImgFile, string fileToOpen, byte[] cmaKey)
{
try
{
FileStream psvImgFileStream = File.OpenRead(psvImgFile);
PSVIMGStream psvImgStream = new PSVIMGStream(psvImgFileStream, cmaKey);
PSVIMGFileStream fileStream = new PSVIMGFileStream(psvImgStream, fileToOpen);
return fileStream;
}
catch { return null; }
}
public static NpDrmInfo? GetKeyFromGamePsvimg(string gameBackupFolder, string accountId)
{
string gamePsvimgFile = Path.Combine(gameBackupFolder, "game", "game.psvimg");
if (!File.Exists(gamePsvimgFile)) return null;
byte[] accountIdBin = MathUtil.StringToByteArray(accountId);
byte[] cmaKey = KeyGenerator.GenerateKey(accountIdBin);
using (PSVIMGFileStream? pbp = GetFileFromPsvImg(gamePsvimgFile, "/EBOOT.PBP", cmaKey))
{
if (pbp is null) return null;
return EbootPbpMethod.GetVersionKey(pbp);
}
}
public static NpDrmRif? GetRifFromLicensePsvimg(string gameBackupFolder, string accountId)
{
string licensePsvImgFile = Path.Combine(gameBackupFolder, "license", "license.psvimg");
if (!File.Exists(licensePsvImgFile)) return null;
byte[] accountIdBin = MathUtil.StringToByteArray(accountId);
byte[] cmaKey = KeyGenerator.GenerateKey(accountIdBin);
using (PSVIMGFileStream? rif = GetFileFromPsvImg(licensePsvImgFile, ".RIF", cmaKey))
{
if (rif is null) return null;
byte[] rifData = new byte[rif.Length];
rif.Read(rifData, 0x00, rifData.Length);
return new NpDrmRif(rifData);
}
}
}
}

View File

@ -8,7 +8,7 @@ using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace GameBuilder.VersionKey
namespace LibChovy.VersionKey
{
public class EbootPbpMethod
{

View File

@ -0,0 +1,69 @@
using GameBuilder.Psp;
using Li.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LibChovy.VersionKey
{
public class KeysTxtMethod
{
public static string[] TitleIds
{
get
{
List<string> titleIds = new List<string>();
string[] contentIds = ContentIds;
foreach (string contentId in contentIds)
titleIds.Add(contentId.Substring(7, 9));
return titleIds.ToArray();
}
}
public static string[] ContentIds
{
get
{
List<string> contentIds = new List<string>();
using (TextReader txt = new StringReader(Resources.KEYSTXT))
{
for (string? line = txt.ReadLine();
line is not null;
line = txt.ReadLine())
{
line = line.ReplaceLineEndings("");
string[] data = line.Split(' ');
if (data.Length != 4) continue;
contentIds.Add(data[0]);
}
}
return contentIds.ToArray();
}
}
public static NpDrmInfo GetVersionKey(string contentId, int keyIndex)
{
using (TextReader txt = new StringReader(Resources.KEYSTXT))
{
for(string? line = txt.ReadLine();
line is not null;
line = txt.ReadLine())
{
line = line.ReplaceLineEndings("");
string[] data = line.Split(' ');
if (data.Length != 4) continue;
if (data[0].Equals(contentId, StringComparison.InvariantCultureIgnoreCase))
return new NpDrmInfo(MathUtil.StringToByteArray(data[1 + keyIndex]), contentId, keyIndex);
}
}
throw new Exception("content id is not in keys.txt");
}
}
}

View File

@ -4,12 +4,12 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GameBuilder.VersionKey
namespace LibChovy.VersionKey
{
public enum VersionKeyMethod
{
ACT_RIF_METHOD = 0,
EBOOT_PBP_METHOD = 1,
ACT_RIF_METHOD = 1,
EBOOT_PBP_METHOD = 2,
KEYS_TXT_METHOD = 3
}
}

View File

@ -1039,8 +1039,7 @@ namespace PspCrypto
return -0x7f78ffff;
}
Span<byte> secureTick = BitConverter.GetBytes(ksceRtcGetCurrentSecureTick()); //stackalloc byte[8] { 0xD4, 0x7A, 0x2C, 0x13, 0x64, 0x59, 0xE2, 0x00 };
//RandomNumberGenerator.Fill(secureTick);
Span<byte> secureTick = BitConverter.GetBytes(ksceRtcGetCurrentSecureTick());
ebootSig.Fill(0);
sceEbootPbp.SwVer = swVer;

View File

@ -4,7 +4,7 @@ using static Vita.PsvImgTools.SceIoStat;
namespace Vita.PsvImgTools
{
class PSVIMGFileStream : Stream
public class PSVIMGFileStream : Stream
{
long length = 0;
@ -12,11 +12,14 @@ namespace Vita.PsvImgTools
long endPos = 0;
long position = 0;
PSVIMGStream psvStream;
private PSVIMGStream psvStream;
public PSVIMGFileStream(PSVIMGStream psv, string Path)
{
psvStream = psv;
findFile(Path);
if (Path.First() == '/')
findFile(Path);
else
findFileMatching(Path);
}
public void WriteToFile(string FilePath)
@ -276,6 +279,12 @@ namespace Vita.PsvImgTools
return header;
}
public override void Close()
{
psvStream.Dispose();
base.Close();
}
private PsvImgTailer readTailer()
{
PsvImgTailer tailer = new PsvImgTailer();
@ -284,6 +293,33 @@ namespace Vita.PsvImgTools
_read(tailer.bEnd, 0x00, 12);
return tailer;
}
private void findFileMatching(string path)
{
_seek(0x00, SeekOrigin.Begin);
while (psvStream.Position < psvStream.Length)
{
PsvImgHeader header = readHeader();
long size = (long)header.Statistics.Size;
long padding = PSVIMGPadding.GetPadding(size);
if (header.Path.Contains(path, StringComparison.InvariantCultureIgnoreCase))
{
length = size;
startPos = psvStream.Position;
endPos = startPos + length;
return;
}
else
{
_seek(size + padding, SeekOrigin.Current);
PsvImgTailer tailer = readTailer();
}
}
throw new FileNotFoundException("Cannot find file specified");
}
private void findFile(string path)
{
_seek(0x00, SeekOrigin.Begin);
@ -293,7 +329,7 @@ namespace Vita.PsvImgTools
long size = (long)header.Statistics.Size;
long padding = PSVIMGPadding.GetPadding(size);
if (header.Path == path)
if (header.Path.Equals(path, StringComparison.InvariantCultureIgnoreCase))
{
length = size;
startPos = psvStream.Position;

View File

@ -5,7 +5,7 @@ using System.Security.Cryptography;
namespace Vita.PsvImgTools
{
class PSVIMGStream : Stream
public class PSVIMGStream : Stream
{
private Stream baseStream;
private MemoryStream blockStream;
@ -217,11 +217,9 @@ namespace Vita.PsvImgTools
public override void Close()
{
blockStream.Close();
blockStream.Dispose();
baseStream.Close();
baseStream.Dispose();
Dispose();
base.Close();
}
private void update()
{