diff --git a/UnionPatcher.Cli/Program.cs b/UnionPatcher.Cli/Program.cs index 85ece50..934dd33 100644 --- a/UnionPatcher.Cli/Program.cs +++ b/UnionPatcher.Cli/Program.cs @@ -2,53 +2,53 @@ using System.Diagnostics; using System.IO; -namespace LBPUnion.UnionPatcher.Cli { - public static class Program { - public const string Version = "1.0"; +namespace LBPUnion.UnionPatcher.Cli; - private static string fileName; +public static class Program { + public const string Version = "1.0"; - public static string FileName { - get { - if(fileName != null) return fileName; + private static string fileName; - return fileName = Path.GetFileName(Process.GetCurrentProcess().MainModule?.FileName); - } - } + public static string FileName { + get { + if(fileName != null) return fileName; - public static void Main(string[] args) { - if(args.Length < 3) { - PrintHelp(); - return; - } - - ElfFile eboot = new(new FileInfo(args[0])); - - if(!eboot.IsValid) { - Console.WriteLine($"{eboot.Name} is not a valid ELF file (magic number mismatch)"); - Console.WriteLine("The EBOOT must be decrypted before using this tool"); - return; - } - - if(eboot.Is64Bit == null) { - Console.WriteLine($"{eboot.Name} does not target a valid system"); - return; - } - - if(string.IsNullOrWhiteSpace(eboot.Architecture)) { - Console.WriteLine($"{eboot.Name} does not target a valid architecture (PowerPC or ARM)"); - return; - } - - Console.WriteLine($"{eboot.Name} targets {eboot.Architecture}"); - - Patcher.PatchFile(args[0], args[1], args[2]); - Console.WriteLine($"Successfully patched Server URL to {args[1]}."); - } - - public static void PrintHelp() { - Console.WriteLine($"UnionPatcher {Version}"); - Console.WriteLine($" Usage: {FileName} "); + return fileName = Path.GetFileName(Process.GetCurrentProcess().MainModule?.FileName); } } + + public static void Main(string[] args) { + if(args.Length < 3) { + PrintHelp(); + return; + } + + ElfFile eboot = new(new FileInfo(args[0])); + + if(!eboot.IsValid) { + Console.WriteLine($"{eboot.Name} is not a valid ELF file (magic number mismatch)"); + Console.WriteLine("The EBOOT must be decrypted before using this tool"); + return; + } + + if(eboot.Is64Bit == null) { + Console.WriteLine($"{eboot.Name} does not target a valid system"); + return; + } + + if(string.IsNullOrWhiteSpace(eboot.Architecture)) { + Console.WriteLine($"{eboot.Name} does not target a valid architecture (PowerPC or ARM)"); + return; + } + + Console.WriteLine($"{eboot.Name} targets {eboot.Architecture}"); + + Patcher.PatchFile(args[0], args[1], args[2]); + Console.WriteLine($"Successfully patched Server URL to {args[1]}."); + } + + public static void PrintHelp() { + Console.WriteLine($"UnionPatcher {Version}"); + Console.WriteLine($" Usage: {FileName} "); + } } \ No newline at end of file diff --git a/UnionPatcher.Gui.Linux/Program.cs b/UnionPatcher.Gui.Linux/Program.cs index a3ca1aa..36b3f70 100644 --- a/UnionPatcher.Gui.Linux/Program.cs +++ b/UnionPatcher.Gui.Linux/Program.cs @@ -1,7 +1,7 @@ -namespace LBPUnion.UnionPatcher.Gui.Linux { - public static class Program { - public static void Main() { - Gui.Show(); - } +namespace LBPUnion.UnionPatcher.Gui.Linux; + +public static class Program { + public static void Main() { + Gui.Show(); } } \ No newline at end of file diff --git a/UnionPatcher.Gui.MacOS/Program.cs b/UnionPatcher.Gui.MacOS/Program.cs index e20eb37..11af14f 100644 --- a/UnionPatcher.Gui.MacOS/Program.cs +++ b/UnionPatcher.Gui.MacOS/Program.cs @@ -1,7 +1,7 @@ -namespace LBPUnion.UnionPatcher.Gui.MacOS { - public static class Program { - public static void Main() { - Gui.Show(); - } +namespace LBPUnion.UnionPatcher.Gui.MacOS; + +public static class Program { + public static void Main() { + Gui.Show(); } } \ No newline at end of file diff --git a/UnionPatcher.Gui.Windows/Program.cs b/UnionPatcher.Gui.Windows/Program.cs index 3cd096c..3d4650a 100644 --- a/UnionPatcher.Gui.Windows/Program.cs +++ b/UnionPatcher.Gui.Windows/Program.cs @@ -1,10 +1,10 @@ using System; -namespace LBPUnion.UnionPatcher.Gui.Windows { - public static class Program { - [STAThread] - public static void Main() { - Gui.Show(); - } +namespace LBPUnion.UnionPatcher.Gui.Windows; + +public static class Program { + [STAThread] + public static void Main() { + Gui.Show(); } } \ No newline at end of file diff --git a/UnionPatcher.Gui/EasterEgg.cs b/UnionPatcher.Gui/EasterEgg.cs index ce9a960..852b3f6 100644 --- a/UnionPatcher.Gui/EasterEgg.cs +++ b/UnionPatcher.Gui/EasterEgg.cs @@ -1,16 +1,16 @@ using System; -namespace LBPUnion.UnionPatcher.Gui { - public static class EasterEgg { - private static bool? restitch = null; +namespace LBPUnion.UnionPatcher.Gui; - public static bool Restitch { - get { - if(restitch == null) { - return (bool)(restitch = new Random().Next(1, 10_000) == 1); - } - return (bool)restitch; +public static class EasterEgg { + private static bool? restitch = null; + + public static bool Restitch { + get { + if(restitch == null) { + return (bool)(restitch = new Random().Next(1, 10_000) == 1); } + return (bool)restitch; } } } \ No newline at end of file diff --git a/UnionPatcher.Gui/Gui.cs b/UnionPatcher.Gui/Gui.cs index a5b1bba..e09968d 100644 --- a/UnionPatcher.Gui/Gui.cs +++ b/UnionPatcher.Gui/Gui.cs @@ -1,9 +1,9 @@ using Eto.Forms; -namespace LBPUnion.UnionPatcher.Gui { - public static class Gui { - public static void Show() { - new Application().Run(new MainForm()); - } +namespace LBPUnion.UnionPatcher.Gui; + +public static class Gui { + public static void Show() { + new Application().Run(new MainForm()); } } \ No newline at end of file diff --git a/UnionPatcher.Gui/MainForm.cs b/UnionPatcher.Gui/MainForm.cs index b47df7e..568660d 100644 --- a/UnionPatcher.Gui/MainForm.cs +++ b/UnionPatcher.Gui/MainForm.cs @@ -5,161 +5,161 @@ using Eto; using Eto.Drawing; using Eto.Forms; -namespace LBPUnion.UnionPatcher.Gui { - public class MainForm : Form { - #region UI - private readonly FilePicker filePicker; - private readonly TextBox serverUrl; - private readonly FilePicker outputFileName; - public Dialog CreateOkDialog(string title, string errorMessage) { - DynamicLayout layout = new(); - Button button; +namespace LBPUnion.UnionPatcher.Gui; - layout.Spacing = new Size(5, 5); - layout.MinimumSize = new Size(350, 100); +public class MainForm : Form { + #region UI + private readonly FilePicker filePicker; + private readonly TextBox serverUrl; + private readonly FilePicker outputFileName; + public Dialog CreateOkDialog(string title, string errorMessage) { + DynamicLayout layout = new(); + Button button; - layout.BeginHorizontal(); - layout.Add(new Label { - Text = errorMessage, - }); + layout.Spacing = new Size(5, 5); + layout.MinimumSize = new Size(350, 100); - layout.BeginHorizontal(); - layout.BeginVertical(); - layout.Add(null); - layout.Add(button = new Button { - Text = "OK", - }); + layout.BeginHorizontal(); + layout.Add(new Label { + Text = errorMessage, + }); - layout.EndVertical(); - layout.EndHorizontal(); - layout.EndHorizontal(); + layout.BeginHorizontal(); + layout.BeginVertical(); + layout.Add(null); + layout.Add(button = new Button { + Text = "OK", + }); - Dialog dialog = new() { - Content = layout, - Padding = new Padding(10, 10, 10, 10), - Title = title, - }; + layout.EndVertical(); + layout.EndHorizontal(); + layout.EndHorizontal(); - button.Click += delegate { - dialog.Close(); - }; + Dialog dialog = new() { + Content = layout, + Padding = new Padding(10, 10, 10, 10), + Title = title, + }; - return dialog; - } + button.Click += delegate { + dialog.Close(); + }; - public Control CreatePatchButton(int tabIndex = 0) { - Button control = new() { - Text = EasterEgg.Restitch ? "Restitch!" : "Patch!", - TabIndex = tabIndex, - }; - - control.Click += Patch; - - return control; - } - - public Control CreateHelpButton(int tabIndex = 0) { - Button control = new() { - Text = "Help", - TabIndex = tabIndex, - }; - - control.Click += delegate { - Process process = new(); - - process.StartInfo.UseShellExecute = true; - process.StartInfo.FileName = "https://www.lbpunion.com"; - process.Start(); - }; - - return control; - } - - public MainForm() { - this.Title = EasterEgg.Restitch ? "Union Restitcher" : "Union Patcher"; - this.ClientSize = new Size(500, -1); - this.Content = new TableLayout { - Spacing = new Size(5,5), - Padding = new Padding(10, 10, 10, 10), - Rows = { - new TableRow( - new TableCell(new Label { Text = "EBOOT.elf: ", VerticalAlignment = VerticalAlignment.Center }), - new TableCell(this.filePicker = new FilePicker { TabIndex = 0 }) - ), - new TableRow( - new TableCell(new Label { Text = "Server URL: ", VerticalAlignment = VerticalAlignment.Center }), - new TableCell(this.serverUrl = new TextBox { TabIndex = 1 }) - ), - new TableRow( - new TableCell(new Label { Text = "Output filename: ", VerticalAlignment = VerticalAlignment.Center }), - new TableCell(this.outputFileName = new FilePicker { TabIndex = 2, FileAction = FileAction.SaveFile }) - ), - new TableRow( - new TableCell(this.CreateHelpButton(4)), - new TableCell(this.CreatePatchButton(3)) - ), - }, - }; - } - #endregion - private void Patch(object sender, EventArgs e) { - this.Patch(); - } - - private void Patch() { - if(string.IsNullOrWhiteSpace(this.filePicker.FilePath)) { - this.CreateOkDialog("Form Error", "No file specified!").ShowModal(); - return; - } - - if(string.IsNullOrWhiteSpace(this.serverUrl.Text)) { - this.CreateOkDialog("Form Error", "No server URL specified!").ShowModal(); - return; - } - - if(string.IsNullOrWhiteSpace(this.outputFileName.FilePath)) { - this.CreateOkDialog("Form Error", "No output file specified!").ShowModal(); - return; - } - - if(this.filePicker.FilePath == this.outputFileName.FilePath) { - this.CreateOkDialog("Form Error", "Input and output filename are the same! Please save the patched file with a different name so you have a backup of your the original EBOOT.ELF.").ShowModal(); - return; - } - - if(!Uri.TryCreate(this.serverUrl.Text, UriKind.Absolute, out _)) { - this.CreateOkDialog("Form Error", "Server URL is invalid! Please enter a valid URL.").ShowModal(); - return; - } - - // Validate EBOOT after validating form; more expensive - - ElfFile eboot = new(this.filePicker.FilePath); - - if(eboot.IsValid == false) { - this.CreateOkDialog("EBOOT Error", $"{eboot.Name} is not a valid ELF file (magic number mismatch)\n" + "The EBOOT must be decrypted before using this tool").ShowModal(); - return; - } - - if(eboot.Is64Bit == null) { - this.CreateOkDialog("EBOOT Error", $"{eboot.Name} does not target a valid system").ShowModal(); - return; - } - - if(string.IsNullOrWhiteSpace(eboot.Architecture)) { - this.CreateOkDialog("EBOOT Error", $"{eboot.Name} does not target a valid architecture (PowerPC or ARM)").ShowModal(); - return; - } - - try { - Patcher.PatchFile(this.filePicker.FilePath, this.serverUrl.Text, this.outputFileName.FilePath); - } - catch(Exception e) { - this.CreateOkDialog("Error occurred while patching", "An error occured while patching:\n" + e).ShowModal(); - return; - } - - this.CreateOkDialog("Success!", "The Server URL has been patched to " + this.serverUrl.Text).ShowModal(); - } + return dialog; } -} + + public Control CreatePatchButton(int tabIndex = 0) { + Button control = new() { + Text = EasterEgg.Restitch ? "Restitch!" : "Patch!", + TabIndex = tabIndex, + }; + + control.Click += Patch; + + return control; + } + + public Control CreateHelpButton(int tabIndex = 0) { + Button control = new() { + Text = "Help", + TabIndex = tabIndex, + }; + + control.Click += delegate { + Process process = new(); + + process.StartInfo.UseShellExecute = true; + process.StartInfo.FileName = "https://www.lbpunion.com"; + process.Start(); + }; + + return control; + } + + public MainForm() { + this.Title = EasterEgg.Restitch ? "Union Restitcher" : "Union Patcher"; + this.ClientSize = new Size(500, -1); + this.Content = new TableLayout { + Spacing = new Size(5,5), + Padding = new Padding(10, 10, 10, 10), + Rows = { + new TableRow( + new TableCell(new Label { Text = "EBOOT.elf: ", VerticalAlignment = VerticalAlignment.Center }), + new TableCell(this.filePicker = new FilePicker { TabIndex = 0 }) + ), + new TableRow( + new TableCell(new Label { Text = "Server URL: ", VerticalAlignment = VerticalAlignment.Center }), + new TableCell(this.serverUrl = new TextBox { TabIndex = 1 }) + ), + new TableRow( + new TableCell(new Label { Text = "Output filename: ", VerticalAlignment = VerticalAlignment.Center }), + new TableCell(this.outputFileName = new FilePicker { TabIndex = 2, FileAction = FileAction.SaveFile }) + ), + new TableRow( + new TableCell(this.CreateHelpButton(4)), + new TableCell(this.CreatePatchButton(3)) + ), + }, + }; + } + #endregion + private void Patch(object sender, EventArgs e) { + this.Patch(); + } + + private void Patch() { + if(string.IsNullOrWhiteSpace(this.filePicker.FilePath)) { + this.CreateOkDialog("Form Error", "No file specified!").ShowModal(); + return; + } + + if(string.IsNullOrWhiteSpace(this.serverUrl.Text)) { + this.CreateOkDialog("Form Error", "No server URL specified!").ShowModal(); + return; + } + + if(string.IsNullOrWhiteSpace(this.outputFileName.FilePath)) { + this.CreateOkDialog("Form Error", "No output file specified!").ShowModal(); + return; + } + + if(this.filePicker.FilePath == this.outputFileName.FilePath) { + this.CreateOkDialog("Form Error", "Input and output filename are the same! Please save the patched file with a different name so you have a backup of your the original EBOOT.ELF.").ShowModal(); + return; + } + + if(!Uri.TryCreate(this.serverUrl.Text, UriKind.Absolute, out _)) { + this.CreateOkDialog("Form Error", "Server URL is invalid! Please enter a valid URL.").ShowModal(); + return; + } + + // Validate EBOOT after validating form; more expensive + + ElfFile eboot = new(this.filePicker.FilePath); + + if(eboot.IsValid == false) { + this.CreateOkDialog("EBOOT Error", $"{eboot.Name} is not a valid ELF file (magic number mismatch)\n" + "The EBOOT must be decrypted before using this tool").ShowModal(); + return; + } + + if(eboot.Is64Bit == null) { + this.CreateOkDialog("EBOOT Error", $"{eboot.Name} does not target a valid system").ShowModal(); + return; + } + + if(string.IsNullOrWhiteSpace(eboot.Architecture)) { + this.CreateOkDialog("EBOOT Error", $"{eboot.Name} does not target a valid architecture (PowerPC or ARM)").ShowModal(); + return; + } + + try { + Patcher.PatchFile(this.filePicker.FilePath, this.serverUrl.Text, this.outputFileName.FilePath); + } + catch(Exception e) { + this.CreateOkDialog("Error occurred while patching", "An error occured while patching:\n" + e).ShowModal(); + return; + } + + this.CreateOkDialog("Success!", "The Server URL has been patched to " + this.serverUrl.Text).ShowModal(); + } +} \ No newline at end of file diff --git a/UnionPatcher/ElfFile.cs b/UnionPatcher/ElfFile.cs index f8b5fd8..03d5268 100644 --- a/UnionPatcher/ElfFile.cs +++ b/UnionPatcher/ElfFile.cs @@ -8,78 +8,78 @@ Linux ELF header refspec: https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eh Wikipedia entry on ELF: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format */ -namespace LBPUnion.UnionPatcher { - public class ElfFile { - internal const int MinimumSize = 52; +namespace LBPUnion.UnionPatcher; + +public class ElfFile { + internal const int MinimumSize = 52; - private enum WordSize : byte { - ThirtyTwoBits = 0x01, - SixtyFourBits = 0x02, - } - - private enum Endianness : byte { - Little = 0x01, - Big = 0x02, - } - - private enum InstructionSetArchitecture : UInt16 { - PowerPC = 0x15, //64-bit PowerPC (PS3) - ARM = 0x28, //32-bit ARM (Vita) - } - - public string Name { get; } = "Binary Blob"; - - public bool IsValid { get; } = false; - public bool? Is64Bit { get; } = null; - public bool? IsBigEndian { get; } = null; - public string Architecture { get; } = null; - - public byte[] Contents { get; } = null; - - public ElfFile(byte[] fileContents) { - if(fileContents.Length < MinimumSize) - return; - - IsValid = fileContents[..0x04].SequenceEqual(new byte[] { - 0x7F, - (byte)'E', - (byte)'L', - (byte)'F', - }); - - if(!IsValid) return; - - byte identClassValue = fileContents[0x04]; - byte identDataValue = fileContents[0x05]; - - if(identClassValue == (byte)WordSize.ThirtyTwoBits || identClassValue == (byte)WordSize.SixtyFourBits) - Is64Bit = identClassValue == (byte)WordSize.SixtyFourBits; - - if(identDataValue == (byte)Endianness.Little || identDataValue == (byte)Endianness.Big) - IsBigEndian = identDataValue == (byte)Endianness.Big; - - Architecture = GetFileArchitecture(fileContents, IsBigEndian == true); - - Contents = fileContents; - } - - public ElfFile(FileInfo file) : this(File.ReadAllBytes(file.FullName)) { - Name = file.Name; - } - - public ElfFile(string fileName) : this(new FileInfo(fileName)) {} - - private string GetFileArchitecture(byte[] elfHeader, bool isBigEndian) { - byte[] architectureBytes = elfHeader[0x12..0x14]; - UInt16 fileArch = (isBigEndian) ? - BinaryPrimitives.ReadUInt16BigEndian(architectureBytes) : - BinaryPrimitives.ReadUInt16LittleEndian(architectureBytes); - - foreach(InstructionSetArchitecture arch in Enum.GetValues(typeof(InstructionSetArchitecture))) { - if(fileArch == (UInt16)arch) - return arch.ToString(); - } - return null; - } + private enum WordSize : byte { + ThirtyTwoBits = 0x01, + SixtyFourBits = 0x02, } -} + + private enum Endianness : byte { + Little = 0x01, + Big = 0x02, + } + + private enum InstructionSetArchitecture : UInt16 { + PowerPC = 0x15, //64-bit PowerPC (PS3) + ARM = 0x28, //32-bit ARM (Vita) + } + + public string Name { get; } = "Binary Blob"; + + public bool IsValid { get; } = false; + public bool? Is64Bit { get; } = null; + public bool? IsBigEndian { get; } = null; + public string Architecture { get; } = null; + + public byte[] Contents { get; } = null; + + public ElfFile(byte[] fileContents) { + if(fileContents.Length < MinimumSize) + return; + + IsValid = fileContents[..0x04].SequenceEqual(new byte[] { + 0x7F, + (byte)'E', + (byte)'L', + (byte)'F', + }); + + if(!IsValid) return; + + byte identClassValue = fileContents[0x04]; + byte identDataValue = fileContents[0x05]; + + if(identClassValue == (byte)WordSize.ThirtyTwoBits || identClassValue == (byte)WordSize.SixtyFourBits) + Is64Bit = identClassValue == (byte)WordSize.SixtyFourBits; + + if(identDataValue == (byte)Endianness.Little || identDataValue == (byte)Endianness.Big) + IsBigEndian = identDataValue == (byte)Endianness.Big; + + Architecture = GetFileArchitecture(fileContents, IsBigEndian == true); + + Contents = fileContents; + } + + public ElfFile(FileInfo file) : this(File.ReadAllBytes(file.FullName)) { + Name = file.Name; + } + + public ElfFile(string fileName) : this(new FileInfo(fileName)) {} + + private string GetFileArchitecture(byte[] elfHeader, bool isBigEndian) { + byte[] architectureBytes = elfHeader[0x12..0x14]; + UInt16 fileArch = (isBigEndian) ? + BinaryPrimitives.ReadUInt16BigEndian(architectureBytes) : + BinaryPrimitives.ReadUInt16LittleEndian(architectureBytes); + + foreach(InstructionSetArchitecture arch in Enum.GetValues(typeof(InstructionSetArchitecture))) { + if(fileArch == (UInt16)arch) + return arch.ToString(); + } + return null; + } +} \ No newline at end of file diff --git a/UnionPatcher/Patcher.cs b/UnionPatcher/Patcher.cs index 71092ee..17e3bcb 100644 --- a/UnionPatcher/Patcher.cs +++ b/UnionPatcher/Patcher.cs @@ -2,104 +2,104 @@ using System; using System.IO; using System.Text; -namespace LBPUnion.UnionPatcher { - public static class Patcher { - private static readonly string[] toBePatched = { - // Normal LittleBigPlanet gameserver URLs - "https://littlebigplanetps3.online.scee.com:10061/LITTLEBIGPLANETPS3_XML", - "http://littlebigplanetps3.online.scee.com:10060/LITTLEBIGPLANETPS3_XML", - // LittleBigPlanet 3 Presence URLs - "http://live.littlebigplanetps3.online.scee.com:10060/LITTLEBIGPLANETPS3_XML", - "http://presence.littlebigplanetps3.online.scee.com:10060/LITTLEBIGPLANETPS3_XML", - #region Spinoff URLs - // LittleBigPlanet PSP URLs - "http://lbppsp.online.scee.com:10060/LITTLEBIGPLANETPSP_XML", - "https://lbppsp.online.scee.com:10061/LITTLEBIGPLANETPSP_XML", - // LittleBigPlanet Vita URLs - "http://lbpvita.online.scee.com:10060/LITTLEBIGPLANETPS3_XML", - "https://lbpvita.online.scee.com:10061/LITTLEBIGPLANETPS3_XML", - #endregion - #region Beta URLS - // LittleBigPlanet 2 Beta URLs - "http://lbp2ps3-beta.online.scee.com:10060/LITTLEBIGPLANETPS3_XML", - "https://lbp2ps3-beta.online.scee.com:10061/LITTLEBIGPLANETPS3_XML", - // LittleBigPlanet (3?) Beta URLs - "http://littlebigplanetps3-beta.online.scee.com:10060/LITTLEBIGPLANETPS3_XML", - "https://littlebigplanetps3-beta.online.scee.com:10061/LITTLEBIGPLANETPS3_XML", - // LittleBigPlanet Vita Beta URLs - "http://lbpvita-beta.online.scee.com:10060/LITTLEBIGPLANETPS3_XML", - "https://lbpvita-beta.online.scee.com:10061/LITTLEBIGPLANETPS3_XML", - #endregion - }; +namespace LBPUnion.UnionPatcher; - public static void PatchFile(string fileName, Uri serverUrl, string outputFileName) { - PatchFile(fileName, serverUrl.ToString(), outputFileName); - } +public static class Patcher { + private static readonly string[] toBePatched = { + // Normal LittleBigPlanet gameserver URLs + "https://littlebigplanetps3.online.scee.com:10061/LITTLEBIGPLANETPS3_XML", + "http://littlebigplanetps3.online.scee.com:10060/LITTLEBIGPLANETPS3_XML", + // LittleBigPlanet 3 Presence URLs + "http://live.littlebigplanetps3.online.scee.com:10060/LITTLEBIGPLANETPS3_XML", + "http://presence.littlebigplanetps3.online.scee.com:10060/LITTLEBIGPLANETPS3_XML", + #region Spinoff URLs + // LittleBigPlanet PSP URLs + "http://lbppsp.online.scee.com:10060/LITTLEBIGPLANETPSP_XML", + "https://lbppsp.online.scee.com:10061/LITTLEBIGPLANETPSP_XML", + // LittleBigPlanet Vita URLs + "http://lbpvita.online.scee.com:10060/LITTLEBIGPLANETPS3_XML", + "https://lbpvita.online.scee.com:10061/LITTLEBIGPLANETPS3_XML", + #endregion + #region Beta URLS + // LittleBigPlanet 2 Beta URLs + "http://lbp2ps3-beta.online.scee.com:10060/LITTLEBIGPLANETPS3_XML", + "https://lbp2ps3-beta.online.scee.com:10061/LITTLEBIGPLANETPS3_XML", + // LittleBigPlanet (3?) Beta URLs + "http://littlebigplanetps3-beta.online.scee.com:10060/LITTLEBIGPLANETPS3_XML", + "https://littlebigplanetps3-beta.online.scee.com:10061/LITTLEBIGPLANETPS3_XML", + // LittleBigPlanet Vita Beta URLs + "http://lbpvita-beta.online.scee.com:10060/LITTLEBIGPLANETPS3_XML", + "https://lbpvita-beta.online.scee.com:10061/LITTLEBIGPLANETPS3_XML", + #endregion + }; - public static void PatchFile(string fileName, string serverUrl, string outputFileName) { - File.WriteAllBytes(outputFileName, PatchData(File.ReadAllBytes(fileName), serverUrl)); - } - - public static byte[] PatchData(byte[] data, Uri serverUrl) { - return PatchData(data, serverUrl.ToString()); - } - - public static byte[] PatchData(byte[] data, string serverUrl) { - #region Validation - if(serverUrl.EndsWith('/')) { - throw new ArgumentException("URL must not contain a trailing slash!"); - } - - // Attempt to create URI to see if it's valid - if(!Uri.TryCreate(serverUrl, UriKind.RelativeOrAbsolute, out _)) { - throw new Exception("URL must be valid."); - } - - if(serverUrl.Length > data.Length) { - throw new ArgumentException("URL cannot be bigger than the file to patch."); - } - #endregion - - string dataAsString = Encoding.ASCII.GetString(data); - - using MemoryStream ms = new(data); - using BinaryWriter writer = new(ms); - - // Using writer.Write(string) writes the length as a byte beforehand - // This is problematic because LBP (being written in C/C++) uses null-terminated strings, - // as opposed to length-text written strings as C# likes to serialize. - byte[] serverUrlAsBytes = Encoding.ASCII.GetBytes(serverUrl); - - bool wroteUrl = false; - foreach(string url in toBePatched) { - if(serverUrl.Length > url.Length) { - throw new ArgumentOutOfRangeException(nameof(serverUrl), $"Server URL ({serverUrl.Length} characters long) is above maximum length {url.Length}"); - } - - int offset = dataAsString.IndexOf(url, StringComparison.Ordinal); - if(offset < 1) continue; - - writer.BaseStream.Position = offset; - for(int i = 0; i < url.Length; i++) { - writer.Write((byte)0x00); // Zero out data - } - - writer.BaseStream.Position = offset; // Reset position to beginning - writer.Write(serverUrlAsBytes); - - wroteUrl = true; - } - - if(!wroteUrl) { - throw new Exception("No patchable URLs were detected in the " + - "provided file. Please make sure you are patching " + - "the correct file."); - } - - writer.Flush(); - writer.Close(); - - return data; - } + public static void PatchFile(string fileName, Uri serverUrl, string outputFileName) { + PatchFile(fileName, serverUrl.ToString(), outputFileName); } -} + + public static void PatchFile(string fileName, string serverUrl, string outputFileName) { + File.WriteAllBytes(outputFileName, PatchData(File.ReadAllBytes(fileName), serverUrl)); + } + + public static byte[] PatchData(byte[] data, Uri serverUrl) { + return PatchData(data, serverUrl.ToString()); + } + + public static byte[] PatchData(byte[] data, string serverUrl) { + #region Validation + if(serverUrl.EndsWith('/')) { + throw new ArgumentException("URL must not contain a trailing slash!"); + } + + // Attempt to create URI to see if it's valid + if(!Uri.TryCreate(serverUrl, UriKind.RelativeOrAbsolute, out _)) { + throw new Exception("URL must be valid."); + } + + if(serverUrl.Length > data.Length) { + throw new ArgumentException("URL cannot be bigger than the file to patch."); + } + #endregion + + string dataAsString = Encoding.ASCII.GetString(data); + + using MemoryStream ms = new(data); + using BinaryWriter writer = new(ms); + + // Using writer.Write(string) writes the length as a byte beforehand + // This is problematic because LBP (being written in C/C++) uses null-terminated strings, + // as opposed to length-text written strings as C# likes to serialize. + byte[] serverUrlAsBytes = Encoding.ASCII.GetBytes(serverUrl); + + bool wroteUrl = false; + foreach(string url in toBePatched) { + if(serverUrl.Length > url.Length) { + throw new ArgumentOutOfRangeException(nameof(serverUrl), $"Server URL ({serverUrl.Length} characters long) is above maximum length {url.Length}"); + } + + int offset = dataAsString.IndexOf(url, StringComparison.Ordinal); + if(offset < 1) continue; + + writer.BaseStream.Position = offset; + for(int i = 0; i < url.Length; i++) { + writer.Write((byte)0x00); // Zero out data + } + + writer.BaseStream.Position = offset; // Reset position to beginning + writer.Write(serverUrlAsBytes); + + wroteUrl = true; + } + + if(!wroteUrl) { + throw new Exception("No patchable URLs were detected in the " + + "provided file. Please make sure you are patching " + + "the correct file."); + } + + writer.Flush(); + writer.Close(); + + return data; + } +} \ No newline at end of file