make Chovy-Sign-CLI and GUI version run on linux

This commit is contained in:
Li 2023-06-09 21:06:44 +12:00
parent 5aa34528ea
commit c15e345b30
18 changed files with 284 additions and 84 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_LastSelectedProfileId>C:\Users\Li\Documents\git\Chovy-Sign-v2\ChovySign-CLI\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
<_LastSelectedProfileId>C:\Users\Li\Documents\git\Chovy-Sign-v2\ChovySign-CLI\Properties\PublishProfiles\Win64.pubxml</_LastSelectedProfileId>
</PropertyGroup>
</Project>

View File

@ -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<string> parameters = new List<string>();
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());

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<History>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;</History>
<LastFailureDetails />
</PropertyGroup>
</Project>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>bin\Release\Linux</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net6.0</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
<PublishReadyToRun>true</PublishReadyToRun>
<PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
</Project>

View File

@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>bin\Release\</PublishDir>
<PublishDir>bin\Release\Windows</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net6.0</TargetFramework>

View File

@ -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());

View File

@ -1,3 +1,4 @@
using Avalonia;
using Avalonia.Controls;
namespace ChovySign_GUI

View File

@ -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<byte[]?> doLoad(BrowseButton imgFile, int width, int height)

View File

@ -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");

View File

@ -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 + "\"";

View File

@ -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<int, CueStream>();
@ -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);
}
}

View File

@ -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<byte> 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;

View File

@ -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()

View File

@ -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<string, byte[]?> DataFiles = new Dictionary<string, byte[]?>();
@ -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)

View File

@ -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));

View File

@ -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);

View File

@ -19,6 +19,9 @@ namespace LibChovy
Type = ChovyTypes.POPS;
discList = new List<PSInfo>();
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

View File

@ -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())
{