From c15e345b3047970f60ecb66d2c1e11db44a6e688 Mon Sep 17 00:00:00 2001
From: Li
Date: Fri, 9 Jun 2023 21:06:44 +1200
Subject: [PATCH] make Chovy-Sign-CLI and GUI version run on linux
---
ChovySign-CLI/ChovySign-CLI.csproj.user | 2 +-
ChovySign-CLI/Program.cs | 115 ++++++++++++++----
.../PublishProfiles/FolderProfile.pubxml.user | 10 --
.../Properties/PublishProfiles/Linux64.pubxml | 19 +++
.../{FolderProfile.pubxml => Win64.pubxml} | 2 +-
ChovySign-GUI/Global/ProgressStatus.axaml.cs | 13 +-
ChovySign-GUI/MainWindow.axaml.cs | 1 +
ChovySign-GUI/Ps1/GameInfoSelector.axaml.cs | 7 +-
ChovySign-GUI/Psp/PspTab.axaml.cs | 2 +-
GameBuilder/Atrac3/Atrac3ToolEncoder.cs | 19 +++
GameBuilder/Cue/CueReader.cs | 30 +++--
GameBuilder/Pops/PopsImg.cs | 41 +++++--
GameBuilder/Psp/NpUmdImg.cs | 4 +-
GameBuilder/Psp/UmdInfo.cs | 29 +++--
LibChovy/Art/Downloader.cs | 2 +-
LibChovy/ChovySign.cs | 11 ++
LibChovy/PopsParameters.cs | 7 ++
Vita/ContentManager/SettingsReader.cs | 54 ++++++--
18 files changed, 284 insertions(+), 84 deletions(-)
delete mode 100644 ChovySign-CLI/Properties/PublishProfiles/FolderProfile.pubxml.user
create mode 100644 ChovySign-CLI/Properties/PublishProfiles/Linux64.pubxml
rename ChovySign-CLI/Properties/PublishProfiles/{FolderProfile.pubxml => Win64.pubxml} (90%)
diff --git a/ChovySign-CLI/ChovySign-CLI.csproj.user b/ChovySign-CLI/ChovySign-CLI.csproj.user
index ea87748..dea5502 100644
--- a/ChovySign-CLI/ChovySign-CLI.csproj.user
+++ b/ChovySign-CLI/ChovySign-CLI.csproj.user
@@ -1,6 +1,6 @@
- <_LastSelectedProfileId>C:\Users\Li\Documents\git\Chovy-Sign-v2\ChovySign-CLI\Properties\PublishProfiles\FolderProfile.pubxml
+ <_LastSelectedProfileId>C:\Users\Li\Documents\git\Chovy-Sign-v2\ChovySign-CLI\Properties\PublishProfiles\Win64.pubxml
\ No newline at end of file
diff --git a/ChovySign-CLI/Program.cs b/ChovySign-CLI/Program.cs
index c77fa1c..23e5bf6 100644
--- a/ChovySign-CLI/Program.cs
+++ b/ChovySign-CLI/Program.cs
@@ -4,6 +4,8 @@ using GameBuilder.Psp;
using LibChovy;
using LibChovy.VersionKey;
using System.Text;
+using Vita.ContentManager;
+using PspCrypto;
namespace ChovySign_CLI
{
@@ -11,19 +13,29 @@ namespace ChovySign_CLI
{
private static ArgumentParsingMode mode = ArgumentParsingMode.ARG;
private static List parameters = new List();
- private static string[] discs;
+ private static string[] discs = new string[] { };
private static bool pspCompress = false;
- private static bool devKit = false;
private static string? popsDiscName;
- private static string? popsIcon0File;
- private static string? popsPic0File;
+ private static byte[]? popsIcon0File;
+ private static byte[]? popsPic0File;
private static PbpMode? pbpMode = null;
private static NpDrmRif? rifFile = null;
private static NpDrmInfo? drmInfo = null;
+ // cma
+ private static bool devKit = false;
+ private static bool packagePsvImg = true;
+ private static string? outputFolder = null;
+
+ // --vkey-gen
private static byte[]? actDat = null;
private static byte[]? idps = null;
private static string? rifFolder = null;
+
+ // --pops-eboot-sign
+ private static byte[]? ebootElf = null;
+ private static byte[]? configBin = null;
+
enum PbpMode
{
PSP = 0,
@@ -33,15 +45,23 @@ namespace ChovySign_CLI
}
enum ArgumentParsingMode
{
- ARG = 0,
- POPS_DISC = 1,
- PSP_UMD = 2,
- VERSIONKEY = 3,
- VERSIONKEY_EXTRACT = 4,
- VERSIONKEY_GENERATOR = 5,
- POPS_INFO = 6,
- KEYS_TXT_GEN = 7,
- RIF = 8
+ ARG,
+ POPS_DISC,
+ PSP_UMD,
+
+ VERSIONKEY,
+ VERSIONKEY_EXTRACT,
+ VERSIONKEY_GENERATOR,
+
+ CMA_DEVKIT,
+ CMA_OUTPUT_FOLDER,
+ CMA_PACKAGE_PSVIMG,
+
+ POPS_INFO,
+ POPS_EBOOT,
+
+ KEYS_TXT_GEN,
+ RIF
}
public static int Error(string errorMsg, int ret)
{
@@ -102,13 +122,13 @@ namespace ChovySign_CLI
switch (mode)
{
case ArgumentParsingMode.POPS_DISC:
- if (parameters.Count > 5) return Error("--pops: no more than 5 disc images allowed in a single game (sony's rules, not mine)", 5);
- if (parameters.Count < 1) return Error("--pops: at least 1 disc image file is required.", 5);
+ if (parameters.Count > 5) return Error("--pops: no more than 5 disc images allowed in a single game (sony's rules, not mine)", 4);
+ if (parameters.Count < 1) return Error("--pops: at least 1 disc image file is required.", 4);
discs = parameters.ToArray();
break;
case ArgumentParsingMode.PSP_UMD:
- if (parameters.Count < 1) return Error("--psp: a path to a disc image is required", 5);
- if (parameters.Count > 2) return Error("--psp: no more than 2 arguments. ("+parameters.Count+" given)", 5);
+ if (parameters.Count < 1) return Error("--psp: a path to a disc image is required", 4);
+ if (parameters.Count > 2) return Error("--psp: no more than 2 arguments. ("+parameters.Count+" given)", 4);
discs = new string[1];
discs[0] = parameters[0];
@@ -134,10 +154,10 @@ namespace ChovySign_CLI
if (parameters.Count < 2) return Error("--pops-info takes at least 1 arguments ("+parameters.Count+" given)", 4);
if (parameters.Count > 3) return Error("--pops-info takes no more than 3 arguments("+parameters.Count+" given)", 4);
popsDiscName = parameters[0];
- if (parameters.Count > 1)
- popsIcon0File = parameters[1];
- if (parameters.Count > 2)
- popsPic0File = parameters[2];
+ if (parameters.Count > 1 && File.Exists(parameters[1]))
+ popsIcon0File = File.ReadAllBytes(parameters[1]);
+ if (parameters.Count > 2 && File.Exists(parameters[2]))
+ popsPic0File = File.ReadAllBytes(parameters[2]);
break;
case ArgumentParsingMode.KEYS_TXT_GEN:
if (parameters.Count != 3) return Error("--keys-txt-gen takes 3 arguments, (" + parameters.Count + " given)", 4);
@@ -145,6 +165,23 @@ namespace ChovySign_CLI
idps = StringToByteArray(parameters[1]);
rifFolder = parameters[2];
break;
+ case ArgumentParsingMode.POPS_EBOOT:
+ if (parameters.Count < 1) return Error("--pops-eboot-sign expects at most 1 arguments", 4);
+ if (!File.Exists(parameters[0])) return Error("--pops-eboot-sign: file not found", 4);
+ ebootElf = File.ReadAllBytes(parameters[0]);
+
+ if (parameters.Count >= 2 && File.Exists(parameters[1]))
+ configBin = File.ReadAllBytes(parameters[1]);
+ else
+ configBin = GameBuilder.Resources.DATAPSPSDCFG;
+
+ break;
+ case ArgumentParsingMode.CMA_OUTPUT_FOLDER:
+ if (parameters.Count < 1) return Error("--output-folder expects 1 output", 4);
+ if (!Directory.Exists(parameters[0])) return Error("--output-folder: directory not found", 4);
+
+ SettingsReader.BackupsFolder = parameters[0];
+ break;
case ArgumentParsingMode.RIF:
if (parameters.Count != 1) return Error("--rif expects only 1 argument,", 4);
rifFile = new NpDrmRif(File.ReadAllBytes(parameters[0]));
@@ -163,12 +200,20 @@ namespace ChovySign_CLI
Console.WriteLine("Chovy-Sign v2 (CLI)");
Console.WriteLine("--pops [disc1.cue] [disc2.cue] [disc3.cue] ... (up to 5)");
Console.WriteLine("--pops-info [game title] [icon0.png] (optional) [pic1.png] (optional)");
+ Console.WriteLine("--pops-eboot [eboot.elf] [config.bin] (optional)");
+
Console.WriteLine("--psp [umd.iso] [compress; true/false] (optional)");
+
Console.WriteLine("--rif [GAME.RIF]");
+
Console.WriteLine("--devkit (Use 000000000000 account id)");
+ Console.WriteLine("--no-psvimg (Disable creating a .psvimg file)");
+ Console.WriteLine("--output-folder [output_folder]");
+
Console.WriteLine("--vkey [versionkey] [contentid] [key_index]");
Console.WriteLine("--vkey-extract [eboot.pbp]");
Console.WriteLine("--vkey-gen [act.dat] [license.rif] [console_id] [key_index]");
+
Console.WriteLine("--keys-txt-gen [act.dat] [console_id] [psp_license_folder]");
}
@@ -236,6 +281,17 @@ namespace ChovySign_CLI
return Error("rif is already set", 3);
break;
+ case "--pops-eboot":
+ mode = ArgumentParsingMode.POPS_EBOOT;
+ break;
+ case "--output-folder":
+ mode = ArgumentParsingMode.CMA_OUTPUT_FOLDER;
+ break;
+
+ case "--no-psvimg":
+ packagePsvImg = false;
+ break;
+
case "--devkit":
devKit = true;
break;
@@ -248,6 +304,7 @@ namespace ChovySign_CLI
case ArgumentParsingMode.VERSIONKEY_EXTRACT:
case ArgumentParsingMode.PSP_UMD:
case ArgumentParsingMode.POPS_DISC:
+ case ArgumentParsingMode.POPS_EBOOT:
case ArgumentParsingMode.POPS_INFO:
case ArgumentParsingMode.RIF:
default:
@@ -267,14 +324,14 @@ namespace ChovySign_CLI
if (pbpMode is null) return Error("no pbp mode was set, exiting", 7);
if (pbpMode == PbpMode.PSP && drmInfo.KeyIndex != 2)
- return Error("KeyType is "+drmInfo.KeyIndex+", but PBP mode is PSP, you cant do that .. please use a type 1 versionkey.", 8);
+ return Error("KeyType is "+drmInfo.KeyIndex+", but PBP mode is PSP, you cant do that .. please use a type 2 versionkey.", 8);
if (pbpMode == PbpMode.POPS && drmInfo.KeyIndex != 1)
return Error("KeyType is " + drmInfo.KeyIndex + ", but PBP mode is POPS, you cant do that .. please use a type 1 versionkey.", 8);
if (rifFile is null)
return Error("Rif is not set, use --rif to specify base game RIF", 8);
- //if (pbpMode == PbpMode.POPS && (popsDiscName is null || popsIcon0File is null)) return Error("pbp mode is POPS, but you have not specified a disc title or icon file using --pops-info.", 9);
+
ChovySign csign = new ChovySign();
csign.RegisterCallback(onProgress);
if (pbpMode == PbpMode.POPS)
@@ -287,11 +344,17 @@ namespace ChovySign_CLI
if(popsDiscName is not null)
popsParameters.Name = popsDiscName;
- if(File.Exists(popsIcon0File))
- popsParameters.Icon0 = File.ReadAllBytes(popsIcon0File);
+ if(popsIcon0File is not null)
+ popsParameters.Icon0 = popsIcon0File;
+
+ popsParameters.CreatePsvImg = packagePsvImg;
popsParameters.Account.Devkit = devKit;
+ // Allow for custom eboot.elf and configs
+ popsParameters.ConfigBinOverride = configBin;
+ popsParameters.EbootElfOverride = ebootElf;
+
csign.Go(popsParameters);
}
@@ -299,6 +362,8 @@ namespace ChovySign_CLI
{
PspParameters pspParameters = new PspParameters(drmInfo, rifFile);
pspParameters.Account.Devkit = devKit;
+ pspParameters.CreatePsvImg = packagePsvImg;
+
pspParameters.Compress = pspCompress;
pspParameters.Umd = new UmdInfo(discs.First());
diff --git a/ChovySign-CLI/Properties/PublishProfiles/FolderProfile.pubxml.user b/ChovySign-CLI/Properties/PublishProfiles/FolderProfile.pubxml.user
deleted file mode 100644
index b3e5516..0000000
--- a/ChovySign-CLI/Properties/PublishProfiles/FolderProfile.pubxml.user
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
- True|2023-05-01T17:56:05.9738806Z;True|2023-04-26T15:20:05.7988009+12:00;True|2023-04-24T08:18:55.4774877+12:00;True|2023-04-20T08:33:00.3404616+12:00;False|2023-04-20T08:29:02.1306599+12:00;True|2023-04-19T21:53:45.1116925+12:00;True|2023-04-19T20:46:20.2756012+12:00;True|2023-04-19T19:58:40.3825010+12:00;True|2023-04-18T00:00:51.4131559+12:00;True|2023-04-17T09:56:35.5065135+12:00;True|2023-04-17T09:22:54.8607008+12:00;True|2023-04-17T08:27:16.5281469+12:00;True|2023-04-17T08:22:02.0531219+12:00;
-
-
-
\ No newline at end of file
diff --git a/ChovySign-CLI/Properties/PublishProfiles/Linux64.pubxml b/ChovySign-CLI/Properties/PublishProfiles/Linux64.pubxml
new file mode 100644
index 0000000..862ba73
--- /dev/null
+++ b/ChovySign-CLI/Properties/PublishProfiles/Linux64.pubxml
@@ -0,0 +1,19 @@
+
+
+
+
+ Release
+ Any CPU
+ bin\Release\Linux
+ FileSystem
+ <_TargetId>Folder
+ net6.0
+ linux-x64
+ true
+ true
+ true
+ true
+
+
\ No newline at end of file
diff --git a/ChovySign-CLI/Properties/PublishProfiles/FolderProfile.pubxml b/ChovySign-CLI/Properties/PublishProfiles/Win64.pubxml
similarity index 90%
rename from ChovySign-CLI/Properties/PublishProfiles/FolderProfile.pubxml
rename to ChovySign-CLI/Properties/PublishProfiles/Win64.pubxml
index d1d5c25..fc063c7 100644
--- a/ChovySign-CLI/Properties/PublishProfiles/FolderProfile.pubxml
+++ b/ChovySign-CLI/Properties/PublishProfiles/Win64.pubxml
@@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
Release
Any CPU
- bin\Release\
+ bin\Release\Windows
FileSystem
<_TargetId>Folder
net6.0
diff --git a/ChovySign-GUI/Global/ProgressStatus.axaml.cs b/ChovySign-GUI/Global/ProgressStatus.axaml.cs
index bc175a2..2633203 100644
--- a/ChovySign-GUI/Global/ProgressStatus.axaml.cs
+++ b/ChovySign-GUI/Global/ProgressStatus.axaml.cs
@@ -42,12 +42,21 @@ namespace ChovySign_GUI.Global
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); });
+ await Task.Run(() => {
+ try
+ {
+ chovySign.Go(Parameters);
+ }
+ catch (Exception e)
+ {
+ Dispatcher.UIThread.Post(() => { _ = MessageBox.Show(currentWindow, "Error building: " + e.Message + "\n\nSTACKTRACE: " + e.StackTrace, "ERROR", MessageBoxButtons.Ok); });
+ }
+ });
OnFinished(new EventArgs());
diff --git a/ChovySign-GUI/MainWindow.axaml.cs b/ChovySign-GUI/MainWindow.axaml.cs
index c5dcc0d..c8cc7b5 100644
--- a/ChovySign-GUI/MainWindow.axaml.cs
+++ b/ChovySign-GUI/MainWindow.axaml.cs
@@ -1,3 +1,4 @@
+using Avalonia;
using Avalonia.Controls;
namespace ChovySign_GUI
diff --git a/ChovySign-GUI/Ps1/GameInfoSelector.axaml.cs b/ChovySign-GUI/Ps1/GameInfoSelector.axaml.cs
index 9ad59c2..a1cf6c0 100644
--- a/ChovySign-GUI/Ps1/GameInfoSelector.axaml.cs
+++ b/ChovySign-GUI/Ps1/GameInfoSelector.axaml.cs
@@ -103,7 +103,12 @@ namespace ChovySign_GUI.Ps1
loadIcon(newCover);
iconCache = newCover;
}
- catch (Exception) { }
+ catch (Exception e) {
+ Window? currentWindow = this.VisualRoot as Window;
+ if (currentWindow is not Window) throw new Exception("could not find current window");
+
+ await MessageBox.Show(currentWindow, "unable to read cue sheet: " + Path.GetFileName(cueFile) + "\n" + e.Message + "\n\nSTACKTRACE: " + e.StackTrace, "cannot load cue sheet", MessageBox.MessageBoxButtons.Ok);
+ }
}
private async Task doLoad(BrowseButton imgFile, int width, int height)
diff --git a/ChovySign-GUI/Psp/PspTab.axaml.cs b/ChovySign-GUI/Psp/PspTab.axaml.cs
index 530a393..3a6c9cf 100644
--- a/ChovySign-GUI/Psp/PspTab.axaml.cs
+++ b/ChovySign-GUI/Psp/PspTab.axaml.cs
@@ -38,7 +38,7 @@ namespace ChovySign_GUI.Psp
{
keySelector.IsEnabled = true;
isoSelector.IsEnabled = true;
- SettingsTab.Settings.IsEnabled = false;
+ SettingsTab.Settings.IsEnabled = true;
Window? currentWindow = this.VisualRoot as Window;
if (currentWindow is not Window) throw new Exception("could not find current window");
diff --git a/GameBuilder/Atrac3/Atrac3ToolEncoder.cs b/GameBuilder/Atrac3/Atrac3ToolEncoder.cs
index 421def3..e37d250 100644
--- a/GameBuilder/Atrac3/Atrac3ToolEncoder.cs
+++ b/GameBuilder/Atrac3/Atrac3ToolEncoder.cs
@@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
+using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Channels;
using System.Threading.Tasks;
@@ -12,6 +13,9 @@ namespace GameBuilder.Atrac3
{
public class Atrac3ToolEncoder : IAtracEncoderBase
{
+ [DllImport("libc")]
+ private static extern int setenv(string name, string value, bool overwrite);
+
private static Random rng = new Random();
private static string TOOLS_DIRECTORY = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "tools");
@@ -19,6 +23,7 @@ namespace GameBuilder.Atrac3
private static string AT3TOOL_LINUX = Path.Combine(TOOLS_DIRECTORY, "at3tool.elf");
private static string TEMP_DIRECTORY = Path.Combine(Path.GetTempPath(), "at3tool_tmp");
+ private static string LD_LIBRARY_PATH = "LD_LIBRARY_PATH";
// random name so that can generate multiple at once if wanted ..
private string TEMP_WAV;
@@ -45,10 +50,24 @@ namespace GameBuilder.Atrac3
}
}
+ private string setupLibaryPath()
+ {
+ string? libaryPath = Environment.GetEnvironmentVariable(LD_LIBRARY_PATH);
+ if (libaryPath is null) libaryPath = TOOLS_DIRECTORY;
+ else libaryPath += ";" + TOOLS_DIRECTORY;
+
+ Environment.SetEnvironmentVariable(libaryPath, libaryPath);
+ setenv(LD_LIBRARY_PATH, libaryPath, true);
+
+ return libaryPath;
+ }
private void runAtrac3Tool()
{
using(Process proc = new Process())
{
+ if (OperatingSystem.IsLinux())
+ proc.StartInfo.Environment.Add(LD_LIBRARY_PATH, setupLibaryPath());
+
proc.StartInfo.FileName = AT3TOOL_LOCATION;
proc.StartInfo.Arguments = "-br 132 -e \"" + TEMP_WAV + "\" \"" + TEMP_AT3 + "\"";
diff --git a/GameBuilder/Cue/CueReader.cs b/GameBuilder/Cue/CueReader.cs
index f94e41f..6f5e1cf 100644
--- a/GameBuilder/Cue/CueReader.cs
+++ b/GameBuilder/Cue/CueReader.cs
@@ -300,6 +300,19 @@ namespace GameBuilder.Cue
openTracks.Clear();
}
+ private string getFilename(string str)
+ {
+ if (!str.Contains(' ')) throw new Exception("cue specifies no bin file.");
+ if (!str.Contains('"')) return str.Split(' ')[1];
+
+ int start = str.IndexOf('"');
+ str = str.Substring(start + 1);
+
+
+ int end = str.IndexOf('"');
+ str = str.Substring(0, end);
+ return str;
+ }
public CueReader(string cueFile)
{
openTracks = new Dictionary();
@@ -310,10 +323,11 @@ namespace GameBuilder.Cue
CueTrack? curTrack = null;
for (string? cueData = cueReader.ReadLine();
- cueData != null;
+ cueData is not null;
cueData = cueReader.ReadLine())
{
- string[] cueLn = cueData.Trim().Replace("\r", "").Replace("\n", "").Split(' ');
+ cueData = cueData.Trim().Replace("\r", "").Replace("\n", "");
+ string[] cueLn = cueData.Split(' ');
if (cueLn[0] == "INDEX")
{
@@ -350,17 +364,17 @@ namespace GameBuilder.Cue
if (curTrack != null) setTrackNumber(curTrack.TrackNo, ref curTrack);
// parse out filename..
- string[] cueFnameParts = new string[cueLn.Length - 2];
- Array.ConstrainedCopy(cueLn, 1, cueFnameParts, 0, cueFnameParts.Length);
- string cueFname = String.Join(' ', cueFnameParts);
-
- // open file ..
- string binFileName = cueFname.Substring(1, cueFname.Length - 2);
+ string binFileName = getFilename(cueData);
string? folderContainingCue = Path.GetDirectoryName(cueFile);
if (folderContainingCue != null)
binFileName = Path.Combine(folderContainingCue, binFileName);
+ if(!File.Exists(binFileName))
+ binFileName = Path.ChangeExtension(cueFile, ".bin");
+
+ if (!File.Exists(binFileName)) throw new FileNotFoundException("unable to find bin file.");
+
curTrack = new CueTrack(binFileName);
}
}
diff --git a/GameBuilder/Pops/PopsImg.cs b/GameBuilder/Pops/PopsImg.cs
index 806338c..de30472 100644
--- a/GameBuilder/Pops/PopsImg.cs
+++ b/GameBuilder/Pops/PopsImg.cs
@@ -24,6 +24,9 @@ namespace GameBuilder.Pops
this.createSimpleDat();
this.SimplePgd = CreatePgd(simple.ToArray());
+ this.EbootElf = Resources.DATAPSPSD;
+ this.ConfigBin = Resources.DATAPSPSDCFG;
+ this.PatchEboot = true;
}
internal void createSimpleDat()
{
@@ -54,28 +57,42 @@ namespace GameBuilder.Pops
public override byte[] GenerateDataPsp()
{
Span loaderEnc = new byte[0x9B13];
+
+ //byte[] dataPspElf = Resources.DATAPSPSD;
- byte[] dataPspElf = Resources.DATAPSPSD;
+ if (this.PatchEboot)
+ {
+ // calculate size low and high part ..
+ uint szLow = Convert.ToUInt32(Psar.Length) >> 16;
+ uint szHigh = Convert.ToUInt32(Psar.Length) & 0xFFFF;
- // calculate size low and high part ..
- uint szLow = Convert.ToUInt32(Psar.Length) >> 16;
- uint szHigh = Convert.ToUInt32(Psar.Length) & 0xFFFF;
+ // convert to big endain bytes
+ byte[] lowBits = BitConverter.GetBytes(Convert.ToUInt16(szLow)).ToArray();
+ byte[] highBits = BitConverter.GetBytes(Convert.ToUInt16(szHigh)).ToArray();
- // convert to big endain bytes
- byte[] lowBits = BitConverter.GetBytes(Convert.ToUInt16(szLow)).ToArray();
- byte[] highBits = BitConverter.GetBytes(Convert.ToUInt16(szHigh)).ToArray();
+ // overwrite data.psar size check ..
+ Array.ConstrainedCopy(lowBits, 0, this.EbootElf, 0x68C, 0x2);
+ Array.ConstrainedCopy(highBits, 0, this.EbootElf, 0x694, 0x2);
+ }
- // overwrite data.psar size check ..
- Array.ConstrainedCopy(lowBits, 0, dataPspElf, 0x68C, 0x2);
- Array.ConstrainedCopy(highBits, 0, dataPspElf, 0x694, 0x2);
-
- SceMesgLed.Encrypt(loaderEnc, dataPspElf, 0x0DAA06F0, SceExecFileDecryptMode.DECRYPT_MODE_POPS_EXEC, DrmInfo.VersionKey, DrmInfo.ContentId, Resources.DATAPSPSDCFG);
+ SceMesgLed.Encrypt(
+ loaderEnc,
+ this.EbootElf,
+ 0x0DAA06F0,
+ SceExecFileDecryptMode.DECRYPT_MODE_POPS_EXEC,
+ DrmInfo.VersionKey,
+ DrmInfo.ContentId,
+ this.ConfigBin);
return loaderEnc.ToArray();
}
private MemoryStream simple;
private StreamUtil simpleUtil;
+ public byte[] EbootElf;
+ public byte[] ConfigBin;
+ public bool PatchEboot;
+
public byte[] StartDat;
public byte[] SimplePgd;
diff --git a/GameBuilder/Psp/NpUmdImg.cs b/GameBuilder/Psp/NpUmdImg.cs
index 725866f..1d78315 100644
--- a/GameBuilder/Psp/NpUmdImg.cs
+++ b/GameBuilder/Psp/NpUmdImg.cs
@@ -43,8 +43,8 @@ namespace GameBuilder.Psp
public void PatchSfo()
{
Sfo sfoKeys = Sfo.ReadSfo(umdImage.DataFiles["PARAM.SFO"]);
- if ((sfoKeys["CATEGORY"] as String) == "UG") // "UMD Game"
- sfoKeys["CATEGORY"] = "EG"; // set it to "Eboot Game"
+ //if ((sfoKeys["CATEGORY"] as String) == "UG") // "UMD Game"
+ sfoKeys["CATEGORY"] = "EG"; // set it to "Eboot Game"
umdImage.DataFiles["PARAM.SFO"] = sfoKeys.WriteSfo();
}
private void createNpHdr()
diff --git a/GameBuilder/Psp/UmdInfo.cs b/GameBuilder/Psp/UmdInfo.cs
index 2962b0b..fe79227 100644
--- a/GameBuilder/Psp/UmdInfo.cs
+++ b/GameBuilder/Psp/UmdInfo.cs
@@ -12,12 +12,12 @@ namespace GameBuilder.Psp
{
private string[] filesList = new string[]
{
- "PSP_GAME\\ICON0.PNG",
- "PSP_GAME\\ICON1.PMF",
- "PSP_GAME\\PARAM.SFO",
- "PSP_GAME\\PIC0.PNG",
- "PSP_GAME\\PIC1.PNG",
- "PSP_GAME\\SND0.AT3"
+ Path.Combine("PSP_GAME","ICON0.PNG"),
+ Path.Combine("PSP_GAME","ICON1.PMF"),
+ Path.Combine("PSP_GAME","PARAM.SFO"),
+ Path.Combine("PSP_GAME","PIC0.PNG"),
+ Path.Combine("PSP_GAME","PIC1.PNG"),
+ Path.Combine("PSP_GAME","SND0.AT3")
};
public Dictionary DataFiles = new Dictionary();
@@ -27,12 +27,12 @@ namespace GameBuilder.Psp
this.IsoStream = File.OpenRead(isoFile);
using (CDReader cdReader = new CDReader(this.IsoStream, true, true))
{
- foreach (string file in filesList)
+ foreach (string file in this.filesList)
{
string fname = Path.GetFileName(file).ToUpperInvariant();
- if (cdReader.FileExists(file))
+ if (cdReader.FileExists(file.Replace('/', '\\')))
{
- using (SparseStream s = cdReader.OpenFile(file, FileMode.Open))
+ using (SparseStream s = cdReader.OpenFile(file.Replace('/', '\\'), FileMode.Open))
{
byte[] data = new byte[s.Length];
@@ -48,11 +48,14 @@ namespace GameBuilder.Psp
}
}
-
- if (DataFiles["PARAM.SFO"] is null) throw new Exception("ISO contains no PARAM.SFO file, so this is not a valid PSP game.");
+ byte[]? paramFile = DataFiles["PARAM.SFO"];
+ if (paramFile is null) throw new Exception("ISO contains no PARAM.SFO file, so this is not a valid PSP game.");
- Sfo sfo = Sfo.ReadSfo(DataFiles["PARAM.SFO"]);
- this.DiscId = sfo["DISC_ID"] as String;
+ Sfo sfo = Sfo.ReadSfo(paramFile);
+ string? discId = sfo["DISC_ID"] as String;
+ if (discId is null) throw new Exception("PARAM.SFO does not contain \"DISC_ID\"");
+
+ this.DiscId = discId;
// check minis
if (sfo["ATTRIBUTE"] is UInt32)
diff --git a/LibChovy/Art/Downloader.cs b/LibChovy/Art/Downloader.cs
index 2102fe1..4f60d1c 100644
--- a/LibChovy/Art/Downloader.cs
+++ b/LibChovy/Art/Downloader.cs
@@ -30,7 +30,7 @@ namespace LibChovy.Art
using (Image psnBorder = Image.Load(Resources.ICON0))
{
- coverImage.Mutate(x => x.Crop(new Rectangle(80, 0, coverImage.Width - 80, coverImage.Height)));
+ //coverImage.Mutate(x => x.Crop(new Rectangle(80, 0, coverImage.Width - 80, coverImage.Height)));
coverImage.Mutate(x => x.Resize(58, 58));
psnBorder.Mutate(x => x.DrawImage(coverImage, new Point(13, 11), 1.0f));
diff --git a/LibChovy/ChovySign.cs b/LibChovy/ChovySign.cs
index 8ee2526..2e09249 100644
--- a/LibChovy/ChovySign.cs
+++ b/LibChovy/ChovySign.cs
@@ -62,6 +62,17 @@ namespace LibChovy
else
img = new PsIsoImg(parameters.DrmInfo, parameters.FirstDisc);
+ // apply eboot elf overrides
+ if(parameters.EbootElfOverride is not null)
+ {
+ img.EbootElf = parameters.EbootElfOverride;
+ img.PatchEboot = false;
+ }
+ if (parameters.ConfigBinOverride is not null)
+ {
+ img.ConfigBin = parameters.ConfigBinOverride;
+ }
+
using (PbpBuilder pbpBuilder = new PbpBuilder(sfo, parameters.Icon0, null, parameters.Pic0, parameters.Pic1, null, img, 0))
{
pbpBuilder.RegisterCallback(onProgress);
diff --git a/LibChovy/PopsParameters.cs b/LibChovy/PopsParameters.cs
index 7fb4fe7..da09211 100644
--- a/LibChovy/PopsParameters.cs
+++ b/LibChovy/PopsParameters.cs
@@ -19,6 +19,9 @@ namespace LibChovy
Type = ChovyTypes.POPS;
discList = new List();
+ EbootElfOverride = null;
+ ConfigBinOverride = null;
+
discIdOverride = null;
nameOverride = null;
libCryptMethod = LibCryptMethod.METHOD_MAGIC_WORD;
@@ -32,6 +35,10 @@ namespace LibChovy
private byte[]? pic1;
private byte[]? icon0;
+
+ public byte[]? EbootElfOverride;
+ public byte[]? ConfigBinOverride;
+
public PSInfo FirstDisc
{
get
diff --git a/Vita/ContentManager/SettingsReader.cs b/Vita/ContentManager/SettingsReader.cs
index 7742f2c..f0490df 100644
--- a/Vita/ContentManager/SettingsReader.cs
+++ b/Vita/ContentManager/SettingsReader.cs
@@ -75,7 +75,50 @@ namespace Vita.ContentManager
private static string getDefaultCmaPSVitaFolder()
{
- return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "PS Vita");
+ return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "PS Vita");
+ }
+
+ private static string getQcmaConfFile()
+ {
+ if (OperatingSystem.IsLinux())
+ return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "codestation", "qcma.conf");
+ else if (OperatingSystem.IsMacOS())
+ return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Preferences", "com.codestation.qcma.plist");
+ else
+ throw new PlatformNotSupportedException("cannot open qcma config as i dont know where it is.");
+ }
+ private static string? getQcmaConfigSetting(string file, string key)
+ {
+ if (!File.Exists(file)) return null;
+
+ if (OperatingSystem.IsLinux())
+ {
+ using (TextReader confFile = File.OpenText(file))
+ {
+ for (string? ln = confFile.ReadLine();
+ ln is not null;
+ ln = confFile.ReadLine())
+ {
+ ln = ln.Trim();
+ if (ln.StartsWith("[")) continue;
+
+ string[] kvp = ln.Split('=');
+ if (kvp.Length < 2) continue;
+
+ string settingKey = kvp[0].Trim();
+ string settingValue = kvp[1].Trim();
+
+
+ if (settingKey == key)
+ return settingValue;
+ }
+ }
+ }
+ else if (OperatingSystem.IsMacOS())
+ {
+ throw new PlatformNotSupportedException("TODO: Implement reading bplist file from mac os");
+ }
+ return null;
}
private static string? getRegistryKey(string registryPath, string keyName)
@@ -116,15 +159,12 @@ namespace Vita.ContentManager
{
if (OperatingSystem.IsWindows())
{
- using(RegistryKey? qcmaKey = Registry.CurrentUser.OpenSubKey(@"Software\codestation\qcma"))
- {
- return getRegistryKey(@"Software\codestation\qcma", "appsPath");
- }
+ return getRegistryKey(@"Software\codestation\qcma", "appsPath");
}
else if (OperatingSystem.IsLinux())
{
- string qcmaConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "codestation", "qcma.conf");
- // TODO: read file
+ string qcmaConf = getQcmaConfFile();
+ return getQcmaConfigSetting(qcmaConf, "appsPath");
}
else if (OperatingSystem.IsMacOS())
{