From ff33cd32549c1dd72a24a813d6d146c3b6665a51 Mon Sep 17 00:00:00 2001 From: Michael Malloy Date: Sat, 6 Feb 2021 21:19:03 -0600 Subject: [PATCH] Continue Formatting/Recommenting --- CommonKey.cs | 36 +- CommonKeyType.cs | 14 - ContentIndices.cs | 22 +- HbcTransmitter.cs | 662 +++++++++++-------- Headers.cs | 1330 ++++++++++++++++++++++----------------- HexView.cs | 578 +++++++++-------- IosPatcher.cs | 573 +++++++++-------- LowerTitleID.cs | 18 - Protocol.cs | 15 - TMD.cs | 8 +- Ticket.cs | 11 +- WAD.cs | 45 +- WAD_Header.cs | 68 -- libWiiSharp.csproj | 6 - libWiiSharp.csproj.user | 6 + zlibWrapper.cs | 46 -- 16 files changed, 1903 insertions(+), 1535 deletions(-) delete mode 100644 CommonKeyType.cs delete mode 100644 LowerTitleID.cs delete mode 100644 Protocol.cs delete mode 100644 WAD_Header.cs create mode 100644 libWiiSharp.csproj.user delete mode 100644 zlibWrapper.cs diff --git a/CommonKey.cs b/CommonKey.cs index ad04749..573f34b 100644 --- a/CommonKey.cs +++ b/CommonKey.cs @@ -1,18 +1,30 @@ -// Decompiled with JetBrains decompiler -// Type: libWiiSharp.CommonKey -// Assembly: libWiiSharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=null -// MVID: FBF36F3D-B5D6-481F-B5F5-1BD3C19E13B2 -// Assembly location: C:\Users\theso\Downloads\NCPatcher\pack\libWiiSharp.dll +/* This file is part of libWiiSharp + * Copyright (C) 2009 Leathl + * Copyright (C) 2020 Github Contributors + * + * libWiiSharp is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libWiiSharp is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ namespace libWiiSharp { - public class CommonKey - { - private static string standardKey = "ebe42a225e8593e448d9c5457381aaf7"; - private static string koreanKey = "63b82bb4f4614e2e13f2fefbba4c9b7e"; + public class CommonKey + { + private static string standardKey = "ebe42a225e8593e448d9c5457381aaf7"; + private static string koreanKey = "63b82bb4f4614e2e13f2fefbba4c9b7e"; - public static byte[] GetStandardKey() => Shared.HexStringToByteArray(CommonKey.standardKey); + public static byte[] GetStandardKey() => Shared.HexStringToByteArray(CommonKey.standardKey); - public static byte[] GetKoreanKey() => Shared.HexStringToByteArray(CommonKey.koreanKey); - } + public static byte[] GetKoreanKey() => Shared.HexStringToByteArray(CommonKey.koreanKey); + } } diff --git a/CommonKeyType.cs b/CommonKeyType.cs deleted file mode 100644 index b5d75c2..0000000 --- a/CommonKeyType.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Decompiled with JetBrains decompiler -// Type: libWiiSharp.CommonKeyType -// Assembly: libWiiSharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=null -// MVID: FBF36F3D-B5D6-481F-B5F5-1BD3C19E13B2 -// Assembly location: C:\Users\theso\Downloads\NCPatcher\pack\libWiiSharp.dll - -namespace libWiiSharp -{ - public enum CommonKeyType : byte - { - Standard, - Korean, - } -} diff --git a/ContentIndices.cs b/ContentIndices.cs index 57d3075..4750e57 100644 --- a/ContentIndices.cs +++ b/ContentIndices.cs @@ -1,8 +1,20 @@ -// Decompiled with JetBrains decompiler -// Type: libWiiSharp.ContentIndices -// Assembly: libWiiSharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=null -// MVID: FBF36F3D-B5D6-481F-B5F5-1BD3C19E13B2 -// Assembly location: C:\Users\theso\Downloads\NCPatcher\pack\libWiiSharp.dll +/* This file is part of libWiiSharp + * Copyright (C) 2009 Leathl + * Copyright (C) 2020 Github Contributors + * + * libWiiSharp is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libWiiSharp is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ using System; diff --git a/HbcTransmitter.cs b/HbcTransmitter.cs index 3460f9f..5a634b9 100644 --- a/HbcTransmitter.cs +++ b/HbcTransmitter.cs @@ -1,301 +1,415 @@ -// Decompiled with JetBrains decompiler -// Type: libWiiSharp.HbcTransmitter -// Assembly: libWiiSharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=null -// MVID: FBF36F3D-B5D6-481F-B5F5-1BD3C19E13B2 -// Assembly location: C:\Users\theso\Downloads\NCPatcher\pack\libWiiSharp.dll +/* This file is part of libWiiSharp + * Copyright (C) 2009 Leathl + * Copyright (C) 2020 Github Contributors + * + * libWiiSharp is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libWiiSharp is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ using System; using System.ComponentModel; using System.IO; using System.Net.Sockets; +using System.Runtime.InteropServices; namespace libWiiSharp { - public class HbcTransmitter : IDisposable - { - private int blocksize = 4096; - private int wiiloadMayor; - private int wiiloadMinor = 5; - private bool compress; - private string ipAddress; - private int port = 4299; - private string lastErrorMessage = string.Empty; - private Protocol protocol; - private TcpClient tcpClient; - private NetworkStream nwStream; - private string lastError = string.Empty; - private int transmittedLength; - private int compressionRatio; - private bool isDisposed; - - public int Blocksize + public enum Protocol { - get => this.blocksize; - set => this.blocksize = value; + /// + /// Will preconfigure all settings for HBC to 1.0.5 (HAXX). + /// + HAXX = 0, + /// + /// Will preconfigure all settings for HBC from 1.0.5 (JODI). + /// + JODI = 1, + /// + /// Remember to define your custom settings. + /// + Custom = 2, } - public int WiiloadVersionMayor + /// + /// The HbcTransmitter can easily transmit files to the Homebrew Channel. + /// In order to use compression, you need zlib1.dll in the application directory. + /// + public class HbcTransmitter : IDisposable { - get => this.wiiloadMayor; - set => this.wiiloadMayor = value; - } + private int blocksize = 4096; + private int wiiloadMayor; + private int wiiloadMinor = 5; + private bool compress; + private string ipAddress; + private int port = 4299; + private string lastErrorMessage = string.Empty; + private Protocol protocol; + private TcpClient tcpClient; + private NetworkStream nwStream; + private string lastError = string.Empty; + private int transmittedLength; + private int compressionRatio; + private bool isDisposed; - public int WiiloadVersionMinor - { - get => this.wiiloadMinor; - set => this.wiiloadMinor = value; - } - - public bool Compress - { - get => this.compress; - set - { - if (this.protocol == Protocol.HAXX) - return; - this.compress = value; - } - } - - public string IpAddress - { - get => this.ipAddress; - set => this.ipAddress = value; - } - - public int Port - { - get => this.port; - set => this.port = value; - } - - public int TransmittedLength => this.transmittedLength; - - public int CompressionRatio => this.compressionRatio; - - public string LastError => this.lastError; - - public event EventHandler Progress; - - public event EventHandler Debug; - - public HbcTransmitter(Protocol protocol, string ipAddress) - { - this.protocol = protocol; - this.ipAddress = ipAddress; - this.wiiloadMinor = protocol == Protocol.HAXX ? 4 : 5; - this.compress = protocol == Protocol.JODI; - } - - ~HbcTransmitter() => this.Dispose(false); - - public void Dispose() - { - this.Dispose(true); - GC.SuppressFinalize((object) this); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing && !this.isDisposed) - { - this.ipAddress = (string) null; - this.lastErrorMessage = (string) null; - this.lastError = (string) null; - if (this.nwStream != null) + /// + /// The size of the buffer that is used to transmit the data. + /// Default is 4 * 1024. If you're facing problems (freezes while transmitting), try a higher size. + /// + public int Blocksize { - this.nwStream.Close(); - this.nwStream = (NetworkStream) null; + get => this.blocksize; + set => this.blocksize = value; } - if (this.tcpClient != null) + + /// + /// The mayor version of wiiload. You might need to change it for upcoming releases of the HBC. + /// + public int WiiloadVersionMayor { - this.tcpClient.Close(); - this.tcpClient = (TcpClient) null; + get => this.wiiloadMayor; + set => this.wiiloadMayor = value; } - } - this.isDisposed = true; + + /// + /// The minor version of wiiload. You might need to change it for upcoming releases of the HBC. + /// + public int WiiloadVersionMinor + { + get => this.wiiloadMinor; + set => this.wiiloadMinor = value; + } + + /// + /// If true, the data will be compressed before being transmitted. NOT available for Protocol.HAXX! + /// Also, compression will only work if zlib1.dll is in the application folder. + /// + public bool Compress + { + get => this.compress; + set + { + if (this.protocol == Protocol.HAXX) + return; + this.compress = value; + } + } + + /// + /// The IP address of the Wii. + /// + public string IpAddress + { + get => this.ipAddress; + set => this.ipAddress = value; + } + + /// The port used for the transmission. + /// You don't need to touch this unless the port changes in future releases of the HBC. + /// + public int Port + { + get => this.port; + set => this.port = value; + } + + /// + /// After a successfully completed transmission, this value holds the number of transmitted bytes. + /// + public int TransmittedLength => this.transmittedLength; + + /// + /// After a successfully completed transmission, this value holds the compression ratio. + /// Will be 0 if the data wasn't compressed. + /// + public int CompressionRatio => this.compressionRatio; + + /// + /// Holds the last occured error message. + /// + public string LastError => this.lastError; + + public HbcTransmitter(Protocol protocol, string ipAddress) + { + this.protocol = protocol; + this.ipAddress = ipAddress; + this.wiiloadMinor = protocol == Protocol.HAXX ? 4 : 5; + this.compress = protocol == Protocol.JODI; + } + + #region IDisposable Members + + ~HbcTransmitter() => this.Dispose(false); + + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize((object) this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing && !this.isDisposed) + { + this.ipAddress = (string) null; + this.lastErrorMessage = (string) null; + this.lastError = (string) null; + if (this.nwStream != null) + { + this.nwStream.Close(); + this.nwStream = (NetworkStream) null; + } + if (this.tcpClient != null) + { + this.tcpClient.Close(); + this.tcpClient = (TcpClient) null; + } + } + this.isDisposed = true; + } + #endregion + + #region Public Functions + public bool TransmitFile(string pathToFile) => this.transmit(Path.GetFileName(pathToFile), File.ReadAllBytes(pathToFile)); + + public bool TransmitFile(string fileName, byte[] fileData) => this.transmit(fileName, fileData); + #endregion + + #region Private Functions + private bool transmit(string fileName, byte[] fileData) + { + this.fireDebug("Transmitting {0} to {1}:{2}...", (object) fileName, (object) this.ipAddress, (object) this.port); + if (!Environment.OSVersion.ToString().ToLower().Contains("windows")) + this.compress = false; + if (fileName.ToLower().EndsWith(".zip")) + this.compress = false; + this.tcpClient = new TcpClient(); + byte[] buffer1 = new byte[4]; + this.fireDebug(" Connecting..."); + try + { + this.tcpClient.Connect(this.ipAddress, 4299); + } + catch (Exception ex) + { + this.fireDebug(" -> Connection Failed:\n" + ex.Message); + this.lastError = "Connection Failed:\n" + ex.Message; + this.tcpClient.Close(); + return false; + } + this.nwStream = this.tcpClient.GetStream(); + this.fireDebug(" Sending Magic..."); + buffer1[0] = (byte) 72; + buffer1[1] = (byte) 65; + buffer1[2] = (byte) 88; + buffer1[3] = (byte) 88; + try + { + this.nwStream.Write(buffer1, 0, 4); + } + catch (Exception ex) + { + this.fireDebug(" -> Error sending Magic:\n" + ex.Message); + this.lastError = "Error sending Magic:\n" + ex.Message; + this.nwStream.Close(); + this.tcpClient.Close(); + return false; + } + this.fireDebug(" Sending Version Info..."); + buffer1[0] = (byte) this.wiiloadMayor; + buffer1[1] = (byte) this.wiiloadMinor; + buffer1[2] = (byte) (fileName.Length + 2 >> 8 & (int) byte.MaxValue); + buffer1[3] = (byte) (fileName.Length + 2 & (int) byte.MaxValue); + try + { + this.nwStream.Write(buffer1, 0, 4); + } + catch (Exception ex) + { + this.fireDebug(" -> Error sending Version Info:\n" + ex.Message); + this.lastError = "Error sending Version Info:\n" + ex.Message; + this.nwStream.Close(); + this.tcpClient.Close(); + return false; + } + byte[] buffer2; + if (this.compress) + { + this.fireDebug(" Compressing File..."); + try + { + buffer2 = zlibWrapper.Compress(fileData); + } + catch + { + this.fireDebug(" -> Compression failed, continuing without compression..."); + this.compress = false; + buffer2 = fileData; + fileData = new byte[0]; + } + } + else + { + buffer2 = fileData; + fileData = new byte[0]; + } + this.fireDebug(" Sending Filesize..."); + buffer1[0] = (byte) (buffer2.Length >> 24 & (int) byte.MaxValue); + buffer1[1] = (byte) (buffer2.Length >> 16 & (int) byte.MaxValue); + buffer1[2] = (byte) (buffer2.Length >> 8 & (int) byte.MaxValue); + buffer1[3] = (byte) (buffer2.Length & (int) byte.MaxValue); + try + { + this.nwStream.Write(buffer1, 0, 4); + } + catch (Exception ex) + { + this.fireDebug(" -> Error sending Filesize:\n" + ex.Message); + this.lastError = "Error sending Filesize:\n" + ex.Message; + this.nwStream.Close(); + this.tcpClient.Close(); + return false; + } + if (this.protocol != Protocol.HAXX) + { + buffer1[0] = (byte) (fileData.Length >> 24 & (int) byte.MaxValue); + buffer1[1] = (byte) (fileData.Length >> 16 & (int) byte.MaxValue); + buffer1[2] = (byte) (fileData.Length >> 8 & (int) byte.MaxValue); + buffer1[3] = (byte) (fileData.Length & (int) byte.MaxValue); + try + { + this.nwStream.Write(buffer1, 0, 4); + } + catch (Exception ex) + { + this.fireDebug(" -> Error sending Filesize:\n" + ex.Message); + this.lastError = "Error sending Filesize:\n" + ex.Message; + this.nwStream.Close(); + this.tcpClient.Close(); + return false; + } + } + this.fireDebug(" Sending File..."); + int offset = 0; + int num1 = 0; + int num2 = buffer2.Length / this.Blocksize; + int num3 = buffer2.Length % this.Blocksize; + try + { + do + { + this.fireProgress(++num1 * 100 / num2); + this.nwStream.Write(buffer2, offset, this.Blocksize); + offset += this.Blocksize; + } + while (num1 < num2); + if (num3 > 0) + this.nwStream.Write(buffer2, offset, buffer2.Length - offset); + } + catch (Exception ex) + { + this.fireDebug(" -> Error sending File:\n" + ex.Message); + this.lastError = "Error sending File:\n" + ex.Message; + this.nwStream.Close(); + this.tcpClient.Close(); + return false; + } + this.fireDebug(" Sending Arguments..."); + byte[] buffer3 = new byte[fileName.Length + 2]; + for (int index = 0; index < fileName.Length; ++index) + buffer3[index] = (byte) fileName.ToCharArray()[index]; + try + { + this.nwStream.Write(buffer3, 0, buffer3.Length); + } + catch (Exception ex) + { + this.fireDebug(" -> Error sending Arguments:\n" + ex.Message); + this.lastError = "Error sending Arguments:\n" + ex.Message; + this.nwStream.Close(); + this.tcpClient.Close(); + return false; + } + this.nwStream.Close(); + this.tcpClient.Close(); + this.transmittedLength = buffer2.Length; + this.compressionRatio = !this.compress || fileData.Length == 0 ? 0 : buffer2.Length * 100 / fileData.Length; + this.fireDebug("Transmitting {0} to {1}:{2} Finished...", (object) fileName, (object) this.ipAddress, (object) this.port); + return true; + } + #endregion + + #region Events + /// + /// Fires the Progress of various operations + /// + public event EventHandler Progress; + + /// + /// Fires debugging messages. You may write them into a log file or log textbox. + /// + public event EventHandler Debug; + + private void fireDebug(string debugMessage, params object[] args) + { + EventHandler debug = this.Debug; + if (debug == null) + return; + debug(new object(), new MessageEventArgs(string.Format(debugMessage, args))); + } + + private void fireProgress(int progressPercentage) + { + EventHandler progress = this.Progress; + if (progress == null) + return; + progress(new object(), new ProgressChangedEventArgs(progressPercentage, (object) string.Empty)); + } + #endregion } - public bool TransmitFile(string pathToFile) => this.transmit(Path.GetFileName(pathToFile), File.ReadAllBytes(pathToFile)); - - public bool TransmitFile(string fileName, byte[] fileData) => this.transmit(fileName, fileData); - - private bool transmit(string fileName, byte[] fileData) + internal class zlibWrapper { - this.fireDebug("Transmitting {0} to {1}:{2}...", (object) fileName, (object) this.ipAddress, (object) this.port); - if (!Environment.OSVersion.ToString().ToLower().Contains("windows")) - this.compress = false; - if (fileName.ToLower().EndsWith(".zip")) - this.compress = false; - this.tcpClient = new TcpClient(); - byte[] buffer1 = new byte[4]; - this.fireDebug(" Connecting..."); - try - { - this.tcpClient.Connect(this.ipAddress, 4299); - } - catch (Exception ex) - { - this.fireDebug(" -> Connection Failed:\n" + ex.Message); - this.lastError = "Connection Failed:\n" + ex.Message; - this.tcpClient.Close(); - return false; - } - this.nwStream = this.tcpClient.GetStream(); - this.fireDebug(" Sending Magic..."); - buffer1[0] = (byte) 72; - buffer1[1] = (byte) 65; - buffer1[2] = (byte) 88; - buffer1[3] = (byte) 88; - try - { - this.nwStream.Write(buffer1, 0, 4); - } - catch (Exception ex) - { - this.fireDebug(" -> Error sending Magic:\n" + ex.Message); - this.lastError = "Error sending Magic:\n" + ex.Message; - this.nwStream.Close(); - this.tcpClient.Close(); - return false; - } - this.fireDebug(" Sending Version Info..."); - buffer1[0] = (byte) this.wiiloadMayor; - buffer1[1] = (byte) this.wiiloadMinor; - buffer1[2] = (byte) (fileName.Length + 2 >> 8 & (int) byte.MaxValue); - buffer1[3] = (byte) (fileName.Length + 2 & (int) byte.MaxValue); - try - { - this.nwStream.Write(buffer1, 0, 4); - } - catch (Exception ex) - { - this.fireDebug(" -> Error sending Version Info:\n" + ex.Message); - this.lastError = "Error sending Version Info:\n" + ex.Message; - this.nwStream.Close(); - this.tcpClient.Close(); - return false; - } - byte[] buffer2; - if (this.compress) - { - this.fireDebug(" Compressing File..."); - try + [DllImport("zlib1.dll")] + private static extern zlibWrapper.ZLibError compress2( + byte[] dest, + ref int destLength, + byte[] source, + int sourceLength, + int level); + + public static byte[] Compress(byte[] inFile) { - buffer2 = zlibWrapper.Compress(fileData); + byte[] array = new byte[inFile.Length + 64]; + int destLength = -1; + zlibWrapper.ZLibError zlibError = zlibWrapper.compress2(array, ref destLength, inFile, inFile.Length, 6); + if (zlibError != zlibWrapper.ZLibError.Z_OK || destLength <= -1 || destLength >= inFile.Length) + throw new Exception("An error occured while compressing! Code: " + zlibError.ToString()); + Array.Resize(ref array, destLength); + return array; } - catch + + public enum ZLibError { - this.fireDebug(" -> Compression failed, continuing without compression..."); - this.compress = false; - buffer2 = fileData; - fileData = new byte[0]; + Z_VERSION_ERROR = -6, // 0xFFFFFFFA + Z_BUF_ERROR = -5, // 0xFFFFFFFB + Z_MEM_ERROR = -4, // 0xFFFFFFFC + Z_DATA_ERROR = -3, // 0xFFFFFFFD + Z_STREAM_ERROR = -2, // 0xFFFFFFFE + Z_ERRNO = -1, // 0xFFFFFFFF + Z_OK = 0, + Z_STREAM_END = 1, + Z_NEED_DICT = 2, } - } - else - { - buffer2 = fileData; - fileData = new byte[0]; - } - this.fireDebug(" Sending Filesize..."); - buffer1[0] = (byte) (buffer2.Length >> 24 & (int) byte.MaxValue); - buffer1[1] = (byte) (buffer2.Length >> 16 & (int) byte.MaxValue); - buffer1[2] = (byte) (buffer2.Length >> 8 & (int) byte.MaxValue); - buffer1[3] = (byte) (buffer2.Length & (int) byte.MaxValue); - try - { - this.nwStream.Write(buffer1, 0, 4); - } - catch (Exception ex) - { - this.fireDebug(" -> Error sending Filesize:\n" + ex.Message); - this.lastError = "Error sending Filesize:\n" + ex.Message; - this.nwStream.Close(); - this.tcpClient.Close(); - return false; - } - if (this.protocol != Protocol.HAXX) - { - buffer1[0] = (byte) (fileData.Length >> 24 & (int) byte.MaxValue); - buffer1[1] = (byte) (fileData.Length >> 16 & (int) byte.MaxValue); - buffer1[2] = (byte) (fileData.Length >> 8 & (int) byte.MaxValue); - buffer1[3] = (byte) (fileData.Length & (int) byte.MaxValue); - try - { - this.nwStream.Write(buffer1, 0, 4); - } - catch (Exception ex) - { - this.fireDebug(" -> Error sending Filesize:\n" + ex.Message); - this.lastError = "Error sending Filesize:\n" + ex.Message; - this.nwStream.Close(); - this.tcpClient.Close(); - return false; - } - } - this.fireDebug(" Sending File..."); - int offset = 0; - int num1 = 0; - int num2 = buffer2.Length / this.Blocksize; - int num3 = buffer2.Length % this.Blocksize; - try - { - do - { - this.fireProgress(++num1 * 100 / num2); - this.nwStream.Write(buffer2, offset, this.Blocksize); - offset += this.Blocksize; - } - while (num1 < num2); - if (num3 > 0) - this.nwStream.Write(buffer2, offset, buffer2.Length - offset); - } - catch (Exception ex) - { - this.fireDebug(" -> Error sending File:\n" + ex.Message); - this.lastError = "Error sending File:\n" + ex.Message; - this.nwStream.Close(); - this.tcpClient.Close(); - return false; - } - this.fireDebug(" Sending Arguments..."); - byte[] buffer3 = new byte[fileName.Length + 2]; - for (int index = 0; index < fileName.Length; ++index) - buffer3[index] = (byte) fileName.ToCharArray()[index]; - try - { - this.nwStream.Write(buffer3, 0, buffer3.Length); - } - catch (Exception ex) - { - this.fireDebug(" -> Error sending Arguments:\n" + ex.Message); - this.lastError = "Error sending Arguments:\n" + ex.Message; - this.nwStream.Close(); - this.tcpClient.Close(); - return false; - } - this.nwStream.Close(); - this.tcpClient.Close(); - this.transmittedLength = buffer2.Length; - this.compressionRatio = !this.compress || fileData.Length == 0 ? 0 : buffer2.Length * 100 / fileData.Length; - this.fireDebug("Transmitting {0} to {1}:{2} Finished...", (object) fileName, (object) this.ipAddress, (object) this.port); - return true; } - private void fireDebug(string debugMessage, params object[] args) - { - EventHandler debug = this.Debug; - if (debug == null) - return; - debug(new object(), new MessageEventArgs(string.Format(debugMessage, args))); - } - - private void fireProgress(int progressPercentage) - { - EventHandler progress = this.Progress; - if (progress == null) - return; - progress(new object(), new ProgressChangedEventArgs(progressPercentage, (object) string.Empty)); - } - } } diff --git a/Headers.cs b/Headers.cs index 8018362..361d07c 100644 --- a/Headers.cs +++ b/Headers.cs @@ -1,8 +1,20 @@ -// Decompiled with JetBrains decompiler -// Type: libWiiSharp.Headers -// Assembly: libWiiSharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=null -// MVID: FBF36F3D-B5D6-481F-B5F5-1BD3C19E13B2 -// Assembly location: C:\Users\theso\Downloads\NCPatcher\pack\libWiiSharp.dll +/* This file is part of libWiiSharp + * Copyright (C) 2009 Leathl + * Copyright (C) 2020 Github Contributors + * + * libWiiSharp is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libWiiSharp is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ using System; using System.IO; @@ -10,581 +22,773 @@ using System.Security.Cryptography; namespace libWiiSharp { - public class Headers - { - private static uint imd5Magic = 1229800501; - private static uint imetMagic = 1229800788; - - public static Headers.HeaderType DetectHeader(string pathToFile) => Headers.DetectHeader(File.ReadAllBytes(pathToFile)); - - public static Headers.HeaderType DetectHeader(byte[] file) + public class Headers { - if (file.Length > 68 && (int) Shared.Swap(BitConverter.ToUInt32(file, 64)) == (int) Headers.imetMagic) - return Headers.HeaderType.ShortIMET; - if (file.Length > 132 && (int) Shared.Swap(BitConverter.ToUInt32(file, 128)) == (int) Headers.imetMagic) - return Headers.HeaderType.IMET; - return file.Length > 4 && (int) Shared.Swap(BitConverter.ToUInt32(file, 0)) == (int) Headers.imd5Magic ? Headers.HeaderType.IMD5 : Headers.HeaderType.None; - } + private static uint imd5Magic = 1229800501; + private static uint imetMagic = 1229800788; - public static Headers.HeaderType DetectHeader(Stream file) - { - byte[] buffer = new byte[4]; - if (file.Length > 68L) - { - file.Seek(64L, SeekOrigin.Begin); - file.Read(buffer, 0, buffer.Length); - if ((int) Shared.Swap(BitConverter.ToUInt32(buffer, 0)) == (int) Headers.imetMagic) - return Headers.HeaderType.ShortIMET; - } - if (file.Length > 132L) - { - file.Seek(128L, SeekOrigin.Begin); - file.Read(buffer, 0, buffer.Length); - if ((int) Shared.Swap(BitConverter.ToUInt32(buffer, 0)) == (int) Headers.imetMagic) - return Headers.HeaderType.IMET; - } - if (file.Length > 4L) - { - file.Seek(0L, SeekOrigin.Begin); - file.Read(buffer, 0, buffer.Length); - if ((int) Shared.Swap(BitConverter.ToUInt32(buffer, 0)) == (int) Headers.imd5Magic) - return Headers.HeaderType.IMD5; - } - return Headers.HeaderType.None; - } - - public enum HeaderType - { - None = 0, - IMD5 = 32, // 0x00000020 - ShortIMET = 1536, // 0x00000600 - IMET = 1600, // 0x00000640 - } - - public class IMET - { - private bool hashesMatch = true; - private bool isShortImet; - private byte[] additionalPadding = new byte[64]; - private byte[] padding = new byte[64]; - private uint imetMagic = 1229800788; - private uint sizeOfHeader = 1536; - private uint unknown = 3; - private uint iconSize; - private uint bannerSize; - private uint soundSize; - private uint flags; - private byte[] japaneseTitle = new byte[84]; - private byte[] englishTitle = new byte[84]; - private byte[] germanTitle = new byte[84]; - private byte[] frenchTitle = new byte[84]; - private byte[] spanishTitle = new byte[84]; - private byte[] italianTitle = new byte[84]; - private byte[] dutchTitle = new byte[84]; - private byte[] unknownTitle1 = new byte[84]; - private byte[] unknownTitle2 = new byte[84]; - private byte[] koreanTitle = new byte[84]; - private byte[] padding2 = new byte[588]; - private byte[] hash = new byte[16]; - - public bool IsShortIMET - { - get => this.isShortImet; - set => this.isShortImet = value; - } - - public uint IconSize - { - get => this.iconSize; - set => this.iconSize = value; - } - - public uint BannerSize - { - get => this.bannerSize; - set => this.bannerSize = value; - } - - public uint SoundSize - { - get => this.soundSize; - set => this.soundSize = value; - } - - public string JapaneseTitle - { - get => this.returnTitleAsString(this.japaneseTitle); - set => this.setTitleFromString(value, 0); - } - - public string EnglishTitle - { - get => this.returnTitleAsString(this.englishTitle); - set => this.setTitleFromString(value, 1); - } - - public string GermanTitle - { - get => this.returnTitleAsString(this.germanTitle); - set => this.setTitleFromString(value, 2); - } - - public string FrenchTitle - { - get => this.returnTitleAsString(this.frenchTitle); - set => this.setTitleFromString(value, 3); - } - - public string SpanishTitle - { - get => this.returnTitleAsString(this.spanishTitle); - set => this.setTitleFromString(value, 4); - } - - public string ItalianTitle - { - get => this.returnTitleAsString(this.italianTitle); - set => this.setTitleFromString(value, 5); - } - - public string DutchTitle - { - get => this.returnTitleAsString(this.dutchTitle); - set => this.setTitleFromString(value, 6); - } - - public string KoreanTitle - { - get => this.returnTitleAsString(this.koreanTitle); - set => this.setTitleFromString(value, 7); - } - - public string[] AllTitles => new string[8] - { - this.JapaneseTitle, - this.EnglishTitle, - this.GermanTitle, - this.FrenchTitle, - this.SpanishTitle, - this.ItalianTitle, - this.DutchTitle, - this.KoreanTitle - }; - - public bool HashesMatch => this.hashesMatch; - - public static Headers.IMET Load(string pathToFile) => Headers.IMET.Load(File.ReadAllBytes(pathToFile)); - - public static Headers.IMET Load(byte[] fileOrHeader) - { - Headers.HeaderType headerType = Headers.DetectHeader(fileOrHeader); - switch (headerType) + /// + /// Convert HeaderType to int to get it's Length. + /// + public enum HeaderType { - case Headers.HeaderType.ShortIMET: - case Headers.HeaderType.IMET: - Headers.IMET imet = new Headers.IMET(); - if (headerType == Headers.HeaderType.ShortIMET) - imet.isShortImet = true; - MemoryStream memoryStream = new MemoryStream(fileOrHeader); - try + None = 0, + /// + /// Used in banner.bin / icon.bin + /// + IMD5 = 32, + /// + /// Used in opening.bnr + /// + ShortIMET = 1536, + /// + /// Used in 00000000.app + /// + IMET = 1600, + } + + #region Public Functions + /// + /// Checks a file for Headers. + /// + /// + /// + public static Headers.HeaderType DetectHeader(string pathToFile) => Headers.DetectHeader(File.ReadAllBytes(pathToFile)); + + /// + /// Checks the byte array for Headers. + /// + /// + /// + public static Headers.HeaderType DetectHeader(byte[] file) + { + if (file.Length > 68 && (int) Shared.Swap(BitConverter.ToUInt32(file, 64)) == (int) Headers.imetMagic) + return Headers.HeaderType.ShortIMET; + if (file.Length > 132 && (int) Shared.Swap(BitConverter.ToUInt32(file, 128)) == (int) Headers.imetMagic) + return Headers.HeaderType.IMET; + return file.Length > 4 && (int) Shared.Swap(BitConverter.ToUInt32(file, 0)) == (int) Headers.imd5Magic ? Headers.HeaderType.IMD5 : Headers.HeaderType.None; + } + + /// + /// Checks the stream for Headers. + /// + /// + /// + public static Headers.HeaderType DetectHeader(Stream file) + { + byte[] buffer = new byte[4]; + if (file.Length > 68L) { - imet.parseHeader((Stream) memoryStream); + file.Seek(64L, SeekOrigin.Begin); + file.Read(buffer, 0, buffer.Length); + if ((int) Shared.Swap(BitConverter.ToUInt32(buffer, 0)) == (int) Headers.imetMagic) + return Headers.HeaderType.ShortIMET; } - catch + if (file.Length > 132L) { - memoryStream.Dispose(); - throw; + file.Seek(128L, SeekOrigin.Begin); + file.Read(buffer, 0, buffer.Length); + if ((int) Shared.Swap(BitConverter.ToUInt32(buffer, 0)) == (int) Headers.imetMagic) + return Headers.HeaderType.IMET; } - memoryStream.Dispose(); - return imet; - default: - throw new Exception("No IMET Header found!"); + if (file.Length > 4L) + { + file.Seek(0L, SeekOrigin.Begin); + file.Read(buffer, 0, buffer.Length); + if ((int) Shared.Swap(BitConverter.ToUInt32(buffer, 0)) == (int) Headers.imd5Magic) + return Headers.HeaderType.IMD5; + } + return Headers.HeaderType.None; } - } + #endregion - public static Headers.IMET Load(Stream fileOrHeader) - { - Headers.HeaderType headerType = Headers.DetectHeader(fileOrHeader); - switch (headerType) + public class IMET { - case Headers.HeaderType.ShortIMET: - case Headers.HeaderType.IMET: - Headers.IMET imet = new Headers.IMET(); - if (headerType == Headers.HeaderType.ShortIMET) - imet.isShortImet = true; - imet.parseHeader(fileOrHeader); - return imet; - default: - throw new Exception("No IMET Header found!"); + private bool hashesMatch = true; + private bool isShortImet; + private byte[] additionalPadding = new byte[64]; + private byte[] padding = new byte[64]; + private uint imetMagic = 1229800788; + private uint sizeOfHeader = 1536; + private uint unknown = 3; + private uint iconSize; + private uint bannerSize; + private uint soundSize; + private uint flags; + private byte[] japaneseTitle = new byte[84]; + private byte[] englishTitle = new byte[84]; + private byte[] germanTitle = new byte[84]; + private byte[] frenchTitle = new byte[84]; + private byte[] spanishTitle = new byte[84]; + private byte[] italianTitle = new byte[84]; + private byte[] dutchTitle = new byte[84]; + private byte[] unknownTitle1 = new byte[84]; + private byte[] unknownTitle2 = new byte[84]; + private byte[] koreanTitle = new byte[84]; + private byte[] padding2 = new byte[588]; + private byte[] hash = new byte[16]; + + /// + /// Short IMET has a padding of 64 bytes at the beginning while Long IMET has 128. + /// + public bool IsShortIMET + { + get => this.isShortImet; + set => this.isShortImet = value; + } + + /// + /// The size of uncompressed icon.bin + /// + public uint IconSize + { + get => this.iconSize; + set => this.iconSize = value; + } + + /// + /// The size of uncompressed banner.bin + /// + public uint BannerSize + { + get => this.bannerSize; + set => this.bannerSize = value; + } + + /// + /// The size of uncompressed sound.bin + /// + public uint SoundSize + { + get => this.soundSize; + set => this.soundSize = value; + } + + /// + /// The Japanese Title. + /// + public string JapaneseTitle + { + get => this.returnTitleAsString(this.japaneseTitle); + set => this.setTitleFromString(value, 0); + } + + /// + /// The English Title. + /// + public string EnglishTitle + { + get => this.returnTitleAsString(this.englishTitle); + set => this.setTitleFromString(value, 1); + } + + /// + /// The German Title. + /// + public string GermanTitle + { + get => this.returnTitleAsString(this.germanTitle); + set => this.setTitleFromString(value, 2); + } + + /// + /// The French Title. + /// + public string FrenchTitle + { + get => this.returnTitleAsString(this.frenchTitle); + set => this.setTitleFromString(value, 3); + } + + /// + /// The Spanish Title. + /// + public string SpanishTitle + { + get => this.returnTitleAsString(this.spanishTitle); + set => this.setTitleFromString(value, 4); + } + + /// + /// The Italian Title. + /// + public string ItalianTitle + { + get => this.returnTitleAsString(this.italianTitle); + set => this.setTitleFromString(value, 5); + } + + /// + /// The Dutch Title. + /// + public string DutchTitle + { + get => this.returnTitleAsString(this.dutchTitle); + set => this.setTitleFromString(value, 6); + } + + /// + /// The Korean Title. + /// + public string KoreanTitle + { + get => this.returnTitleAsString(this.koreanTitle); + set => this.setTitleFromString(value, 7); + } + + /// + /// All Titles as a string array. + /// + public string[] AllTitles => new string[8] + { + this.JapaneseTitle, + this.EnglishTitle, + this.GermanTitle, + this.FrenchTitle, + this.SpanishTitle, + this.ItalianTitle, + this.DutchTitle, + this.KoreanTitle + }; + + /// + /// When parsing an IMET header, this value will turn false if the hash stored in the header doesn't match the headers hash. + /// + public bool HashesMatch => this.hashesMatch; + + #region Public Functions + /// + /// Loads the IMET Header of a file. + /// + /// + /// + public static Headers.IMET Load(string pathToFile) => Headers.IMET.Load(File.ReadAllBytes(pathToFile)); + + /// + /// Loads the IMET Header of a byte array. + /// + /// + /// + public static Headers.IMET Load(byte[] fileOrHeader) + { + Headers.HeaderType headerType = Headers.DetectHeader(fileOrHeader); + switch (headerType) + { + case Headers.HeaderType.ShortIMET: + case Headers.HeaderType.IMET: + Headers.IMET imet = new Headers.IMET(); + if (headerType == Headers.HeaderType.ShortIMET) + imet.isShortImet = true; + MemoryStream memoryStream = new MemoryStream(fileOrHeader); + try + { + imet.parseHeader((Stream) memoryStream); + } + catch + { + memoryStream.Dispose(); + throw; + } + memoryStream.Dispose(); + return imet; + default: + throw new Exception("No IMET Header found!"); + } + } + + /// + /// Loads the IMET Header of a stream. + /// + /// + /// + public static Headers.IMET Load(Stream fileOrHeader) + { + Headers.HeaderType headerType = Headers.DetectHeader(fileOrHeader); + switch (headerType) + { + case Headers.HeaderType.ShortIMET: + case Headers.HeaderType.IMET: + Headers.IMET imet = new Headers.IMET(); + if (headerType == Headers.HeaderType.ShortIMET) + imet.isShortImet = true; + imet.parseHeader(fileOrHeader); + return imet; + default: + throw new Exception("No IMET Header found!"); + } + } + + /// + /// Creates a new IMET Header. + /// + /// + /// + /// + /// + /// + /// + public static Headers.IMET Create( + bool isShortImet, + int iconSize, + int bannerSize, + int soundSize, + params string[] titles) + { + Headers.IMET imet = new Headers.IMET(); + imet.isShortImet = isShortImet; + for (int titleIndex = 0; titleIndex < titles.Length; ++titleIndex) + imet.setTitleFromString(titles[titleIndex], titleIndex); + for (int length = titles.Length; length < 8; ++length) + imet.setTitleFromString(titles.Length > 1 ? titles[1] : titles[0], length); + imet.iconSize = (uint) iconSize; + imet.bannerSize = (uint) bannerSize; + imet.soundSize = (uint) soundSize; + return imet; + } + + /// + /// Removes the IMET Header of a file. + /// + /// + public static void RemoveHeader(string pathToFile) + { + byte[] bytes = Headers.IMET.RemoveHeader(File.ReadAllBytes(pathToFile)); + File.Delete(pathToFile); + File.WriteAllBytes(pathToFile, bytes); + } + + /// + /// Removes the IMET Header of a byte array. + /// + /// + /// + public static byte[] RemoveHeader(byte[] file) + { + Headers.HeaderType headerType = Headers.DetectHeader(file); + switch (headerType) + { + case Headers.HeaderType.ShortIMET: + case Headers.HeaderType.IMET: + byte[] numArray = new byte[(int) (file.Length - headerType)]; + Array.Copy((Array) file, (int) headerType, (Array) numArray, 0, numArray.Length); + return numArray; + default: + throw new Exception("No IMET Header found!"); + } + } + + /// + /// Sets all title to the given string. + /// + /// + public void SetAllTitles(string newTitle) + { + for (int titleIndex = 0; titleIndex < 10; ++titleIndex) + this.setTitleFromString(newTitle, titleIndex); + } + + /// + /// Returns the Header as a memory stream. + /// + /// + public MemoryStream ToMemoryStream() + { + MemoryStream memoryStream = new MemoryStream(); + try + { + this.writeToStream((Stream) memoryStream); + return memoryStream; + } + catch + { + memoryStream.Dispose(); + throw; + } + } + + /// + /// Returns the Header as a byte array. + /// + /// + public byte[] ToByteArray() => this.ToMemoryStream().ToArray(); + + /// + /// Writes the Header to the given stream. + /// + /// + public void Write(Stream writeStream) => this.writeToStream(writeStream); + + /// + /// Changes the Titles. + /// + /// + public void ChangeTitles(params string[] newTitles) + { + for (int titleIndex = 0; titleIndex < newTitles.Length; ++titleIndex) + this.setTitleFromString(newTitles[titleIndex], titleIndex); + for (int length = newTitles.Length; length < 8; ++length) + this.setTitleFromString(newTitles.Length > 1 ? newTitles[1] : newTitles[0], length); + } + + /// + /// Returns a string array with the Titles. + /// + /// + public string[] GetTitles() => new string[8] + { + this.JapaneseTitle, + this.EnglishTitle, + this.GermanTitle, + this.FrenchTitle, + this.SpanishTitle, + this.ItalianTitle, + this.DutchTitle, + this.KoreanTitle + }; + #endregion + + #region Private Functions + private void writeToStream(Stream writeStream) + { + writeStream.Seek(0L, SeekOrigin.Begin); + if (!this.isShortImet) + writeStream.Write(this.additionalPadding, 0, this.additionalPadding.Length); + writeStream.Write(this.padding, 0, this.padding.Length); + writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.imetMagic)), 0, 4); + writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.sizeOfHeader)), 0, 4); + writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.unknown)), 0, 4); + writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.iconSize)), 0, 4); + writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.bannerSize)), 0, 4); + writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.soundSize)), 0, 4); + writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.flags)), 0, 4); + writeStream.Write(this.japaneseTitle, 0, this.japaneseTitle.Length); + writeStream.Write(this.englishTitle, 0, this.englishTitle.Length); + writeStream.Write(this.germanTitle, 0, this.germanTitle.Length); + writeStream.Write(this.frenchTitle, 0, this.frenchTitle.Length); + writeStream.Write(this.spanishTitle, 0, this.spanishTitle.Length); + writeStream.Write(this.italianTitle, 0, this.italianTitle.Length); + writeStream.Write(this.dutchTitle, 0, this.dutchTitle.Length); + writeStream.Write(this.unknownTitle1, 0, this.unknownTitle1.Length); + writeStream.Write(this.unknownTitle2, 0, this.unknownTitle2.Length); + writeStream.Write(this.koreanTitle, 0, this.koreanTitle.Length); + writeStream.Write(this.padding2, 0, this.padding2.Length); + int position = (int) writeStream.Position; + this.hash = new byte[16]; + writeStream.Write(this.hash, 0, this.hash.Length); + byte[] numArray = new byte[writeStream.Position]; + writeStream.Seek(0L, SeekOrigin.Begin); + writeStream.Read(numArray, 0, numArray.Length); + this.computeHash(numArray, !this.isShortImet ? 64 : 0); + writeStream.Seek((long) position, SeekOrigin.Begin); + writeStream.Write(this.hash, 0, this.hash.Length); + } + + private void computeHash(byte[] headerBytes, int hashPos) + { + MD5 md5 = MD5.Create(); + this.hash = md5.ComputeHash(headerBytes, hashPos, 1536); + md5.Clear(); + } + + private void parseHeader(Stream headerStream) + { + headerStream.Seek(0L, SeekOrigin.Begin); + byte[] buffer1 = new byte[4]; + if (!this.isShortImet) + headerStream.Read(this.additionalPadding, 0, this.additionalPadding.Length); + headerStream.Read(this.padding, 0, this.padding.Length); + headerStream.Read(buffer1, 0, 4); + if ((int) Shared.Swap(BitConverter.ToUInt32(buffer1, 0)) != (int) this.imetMagic) + throw new Exception("Invalid Magic!"); + headerStream.Read(buffer1, 0, 4); + if ((int) Shared.Swap(BitConverter.ToUInt32(buffer1, 0)) != (int) this.sizeOfHeader) + throw new Exception("Invalid Header Size!"); + headerStream.Read(buffer1, 0, 4); + this.unknown = Shared.Swap(BitConverter.ToUInt32(buffer1, 0)); + headerStream.Read(buffer1, 0, 4); + this.iconSize = Shared.Swap(BitConverter.ToUInt32(buffer1, 0)); + headerStream.Read(buffer1, 0, 4); + this.bannerSize = Shared.Swap(BitConverter.ToUInt32(buffer1, 0)); + headerStream.Read(buffer1, 0, 4); + this.soundSize = Shared.Swap(BitConverter.ToUInt32(buffer1, 0)); + headerStream.Read(buffer1, 0, 4); + this.flags = Shared.Swap(BitConverter.ToUInt32(buffer1, 0)); + headerStream.Read(this.japaneseTitle, 0, this.japaneseTitle.Length); + headerStream.Read(this.englishTitle, 0, this.englishTitle.Length); + headerStream.Read(this.germanTitle, 0, this.germanTitle.Length); + headerStream.Read(this.frenchTitle, 0, this.frenchTitle.Length); + headerStream.Read(this.spanishTitle, 0, this.spanishTitle.Length); + headerStream.Read(this.italianTitle, 0, this.italianTitle.Length); + headerStream.Read(this.dutchTitle, 0, this.dutchTitle.Length); + headerStream.Read(this.unknownTitle1, 0, this.unknownTitle1.Length); + headerStream.Read(this.unknownTitle2, 0, this.unknownTitle2.Length); + headerStream.Read(this.koreanTitle, 0, this.koreanTitle.Length); + headerStream.Read(this.padding2, 0, this.padding2.Length); + headerStream.Read(this.hash, 0, this.hash.Length); + headerStream.Seek(-16L, SeekOrigin.Current); + headerStream.Write(new byte[16], 0, 16); + byte[] buffer2 = new byte[headerStream.Length]; + headerStream.Seek(0L, SeekOrigin.Begin); + headerStream.Read(buffer2, 0, buffer2.Length); + MD5 md5 = MD5.Create(); + byte[] hash = md5.ComputeHash(buffer2, !this.isShortImet ? 64 : 0, 1536); + md5.Clear(); + this.hashesMatch = Shared.CompareByteArrays(hash, this.hash); + } + + private string returnTitleAsString(byte[] title) + { + string empty = string.Empty; + for (int index = 0; index < 84; index += 2) + { + char ch = BitConverter.ToChar(new byte[2] + { + title[index + 1], + title[index] + }, 0); + if (ch != char.MinValue) + empty += ch.ToString(); + } + return empty; + } + + private void setTitleFromString(string title, int titleIndex) + { + byte[] numArray = new byte[84]; + for (int index = 0; index < title.Length; ++index) + { + byte[] bytes = BitConverter.GetBytes(title[index]); + numArray[index * 2 + 1] = bytes[0]; + numArray[index * 2] = bytes[1]; + } + switch (titleIndex) + { + case 0: + this.japaneseTitle = numArray; + break; + case 1: + this.englishTitle = numArray; + break; + case 2: + this.germanTitle = numArray; + break; + case 3: + this.frenchTitle = numArray; + break; + case 4: + this.spanishTitle = numArray; + break; + case 5: + this.italianTitle = numArray; + break; + case 6: + this.dutchTitle = numArray; + break; + case 7: + this.koreanTitle = numArray; + break; + } + } + #endregion } - } - public static Headers.IMET Create( - bool isShortImet, - int iconSize, - int bannerSize, - int soundSize, - params string[] titles) - { - Headers.IMET imet = new Headers.IMET(); - imet.isShortImet = isShortImet; - for (int titleIndex = 0; titleIndex < titles.Length; ++titleIndex) - imet.setTitleFromString(titles[titleIndex], titleIndex); - for (int length = titles.Length; length < 8; ++length) - imet.setTitleFromString(titles.Length > 1 ? titles[1] : titles[0], length); - imet.iconSize = (uint) iconSize; - imet.bannerSize = (uint) bannerSize; - imet.soundSize = (uint) soundSize; - return imet; - } - - public static void RemoveHeader(string pathToFile) - { - byte[] bytes = Headers.IMET.RemoveHeader(File.ReadAllBytes(pathToFile)); - File.Delete(pathToFile); - File.WriteAllBytes(pathToFile, bytes); - } - - public static byte[] RemoveHeader(byte[] file) - { - Headers.HeaderType headerType = Headers.DetectHeader(file); - switch (headerType) + public class IMD5 { - case Headers.HeaderType.ShortIMET: - case Headers.HeaderType.IMET: - byte[] numArray = new byte[(int) (file.Length - headerType)]; - Array.Copy((Array) file, (int) headerType, (Array) numArray, 0, numArray.Length); - return numArray; - default: - throw new Exception("No IMET Header found!"); - } - } + private uint imd5Magic = 1229800501; + private uint fileSize; + private byte[] padding = new byte[8]; + private byte[] hash = new byte[16]; - public void SetAllTitles(string newTitle) - { - for (int titleIndex = 0; titleIndex < 10; ++titleIndex) - this.setTitleFromString(newTitle, titleIndex); - } + /// + /// The size of the file without the IMD5 Header. + /// + public uint FileSize => this.fileSize; - public MemoryStream ToMemoryStream() - { - MemoryStream memoryStream = new MemoryStream(); - try + /// + /// The hash of the file without the IMD5 Header. + /// + public byte[] Hash => this.hash; + + private IMD5() { - this.writeToStream((Stream) memoryStream); - return memoryStream; } - catch - { - memoryStream.Dispose(); - throw; + + #region Public Functions + /// + /// Loads the IMD5 Header of a file. + /// + /// + /// + public static Headers.IMD5 Load(string pathToFile) => Headers.IMD5.Load(File.ReadAllBytes(pathToFile)); + + /// + /// Loads the IMD5 Header of a byte array. + /// + /// + /// + public static Headers.IMD5 Load(byte[] fileOrHeader) + { + if (Headers.DetectHeader(fileOrHeader) != Headers.HeaderType.IMD5) + throw new Exception("No IMD5 Header found!"); + Headers.IMD5 imD5 = new Headers.IMD5(); + MemoryStream memoryStream = new MemoryStream(fileOrHeader); + try + { + imD5.parseHeader((Stream) memoryStream); + } + catch + { + memoryStream.Dispose(); + throw; + } + memoryStream.Dispose(); + return imD5; + } + + /// + /// Loads the IMD5 Header of a stream. + /// + /// + /// + public static Headers.IMD5 Load(Stream fileOrHeader) + { + if (Headers.DetectHeader(fileOrHeader) != Headers.HeaderType.IMD5) + throw new Exception("No IMD5 Header found!"); + Headers.IMD5 imD5 = new Headers.IMD5(); + imD5.parseHeader(fileOrHeader); + return imD5; + } + + /// + /// Creates a new IMD5 Header. + /// + /// + /// + public static Headers.IMD5 Create(byte[] file) + { + Headers.IMD5 imD5 = new Headers.IMD5(); + imD5.fileSize = (uint) file.Length; + imD5.computeHash(file); + return imD5; + } + + /// + /// Adds an IMD5 Header to a file. + /// + /// + public static void AddHeader(string pathToFile) + { + byte[] buffer = Headers.IMD5.AddHeader(File.ReadAllBytes(pathToFile)); + File.Delete(pathToFile); + using (FileStream fileStream = new FileStream(pathToFile, FileMode.Create)) + fileStream.Write(buffer, 0, buffer.Length); + } + + /// + /// Adds an IMD5 Header to a byte array. + /// + /// + /// + public static byte[] AddHeader(byte[] file) + { + Headers.IMD5 imD5 = Headers.IMD5.Create(file); + MemoryStream memoryStream1 = new MemoryStream(); + MemoryStream memoryStream2 = memoryStream1; + imD5.writeToStream((Stream) memoryStream2); + memoryStream1.Write(file, 0, file.Length); + byte[] array = memoryStream1.ToArray(); + memoryStream1.Dispose(); + return array; + } + + /// + /// Removes the IMD5 Header of a file. + /// + /// + public static void RemoveHeader(string pathToFile) + { + byte[] buffer = Headers.IMD5.RemoveHeader(File.ReadAllBytes(pathToFile)); + File.Delete(pathToFile); + using (FileStream fileStream = new FileStream(pathToFile, FileMode.Create)) + fileStream.Write(buffer, 0, buffer.Length); + } + + /// + /// Removes the IMD5 Header of a byte array. + /// + /// + /// + public static byte[] RemoveHeader(byte[] file) + { + MemoryStream memoryStream = new MemoryStream(); + memoryStream.Write(file, 32, file.Length - 32); + byte[] array = memoryStream.ToArray(); + memoryStream.Dispose(); + return array; + } + + /// + /// Returns the IMD5 Header as a memory stream. + /// + /// + public MemoryStream ToMemoryStream() + { + MemoryStream memoryStream = new MemoryStream(); + try + { + this.writeToStream((Stream) memoryStream); + return memoryStream; + } + catch + { + memoryStream.Dispose(); + throw; + } + } + + /// + /// Returns the IMD5 Header as a byte array. + /// + /// + public byte[] ToByteArray() => this.ToMemoryStream().ToArray(); + + /// + /// Writes the IMD5 Header to the given stream. + /// + /// + public void Write(Stream writeStream) => this.writeToStream(writeStream); + #endregion + + #region Private Functions + private void writeToStream(Stream writeStream) + { + writeStream.Seek(0L, SeekOrigin.Begin); + writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.imd5Magic)), 0, 4); + writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.fileSize)), 0, 4); + writeStream.Write(this.padding, 0, this.padding.Length); + writeStream.Write(this.hash, 0, this.hash.Length); + } + + private void computeHash(byte[] bytesToHash) + { + MD5 md5 = MD5.Create(); + this.hash = md5.ComputeHash(bytesToHash); + md5.Clear(); + } + + private void parseHeader(Stream headerStream) + { + headerStream.Seek(0L, SeekOrigin.Begin); + byte[] buffer = new byte[4]; + headerStream.Read(buffer, 0, 4); + if ((int) Shared.Swap(BitConverter.ToUInt32(buffer, 0)) != (int) this.imd5Magic) + throw new Exception("Invalid Magic!"); + headerStream.Read(buffer, 0, 4); + this.fileSize = Shared.Swap(BitConverter.ToUInt32(buffer, 0)); + headerStream.Read(this.padding, 0, this.padding.Length); + headerStream.Read(this.hash, 0, this.hash.Length); + } + #endregion } - } - - public byte[] ToByteArray() => this.ToMemoryStream().ToArray(); - - public void Write(Stream writeStream) => this.writeToStream(writeStream); - - public void ChangeTitles(params string[] newTitles) - { - for (int titleIndex = 0; titleIndex < newTitles.Length; ++titleIndex) - this.setTitleFromString(newTitles[titleIndex], titleIndex); - for (int length = newTitles.Length; length < 8; ++length) - this.setTitleFromString(newTitles.Length > 1 ? newTitles[1] : newTitles[0], length); - } - - public string[] GetTitles() => new string[8] - { - this.JapaneseTitle, - this.EnglishTitle, - this.GermanTitle, - this.FrenchTitle, - this.SpanishTitle, - this.ItalianTitle, - this.DutchTitle, - this.KoreanTitle - }; - - private void writeToStream(Stream writeStream) - { - writeStream.Seek(0L, SeekOrigin.Begin); - if (!this.isShortImet) - writeStream.Write(this.additionalPadding, 0, this.additionalPadding.Length); - writeStream.Write(this.padding, 0, this.padding.Length); - writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.imetMagic)), 0, 4); - writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.sizeOfHeader)), 0, 4); - writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.unknown)), 0, 4); - writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.iconSize)), 0, 4); - writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.bannerSize)), 0, 4); - writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.soundSize)), 0, 4); - writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.flags)), 0, 4); - writeStream.Write(this.japaneseTitle, 0, this.japaneseTitle.Length); - writeStream.Write(this.englishTitle, 0, this.englishTitle.Length); - writeStream.Write(this.germanTitle, 0, this.germanTitle.Length); - writeStream.Write(this.frenchTitle, 0, this.frenchTitle.Length); - writeStream.Write(this.spanishTitle, 0, this.spanishTitle.Length); - writeStream.Write(this.italianTitle, 0, this.italianTitle.Length); - writeStream.Write(this.dutchTitle, 0, this.dutchTitle.Length); - writeStream.Write(this.unknownTitle1, 0, this.unknownTitle1.Length); - writeStream.Write(this.unknownTitle2, 0, this.unknownTitle2.Length); - writeStream.Write(this.koreanTitle, 0, this.koreanTitle.Length); - writeStream.Write(this.padding2, 0, this.padding2.Length); - int position = (int) writeStream.Position; - this.hash = new byte[16]; - writeStream.Write(this.hash, 0, this.hash.Length); - byte[] numArray = new byte[writeStream.Position]; - writeStream.Seek(0L, SeekOrigin.Begin); - writeStream.Read(numArray, 0, numArray.Length); - this.computeHash(numArray, !this.isShortImet ? 64 : 0); - writeStream.Seek((long) position, SeekOrigin.Begin); - writeStream.Write(this.hash, 0, this.hash.Length); - } - - private void computeHash(byte[] headerBytes, int hashPos) - { - MD5 md5 = MD5.Create(); - this.hash = md5.ComputeHash(headerBytes, hashPos, 1536); - md5.Clear(); - } - - private void parseHeader(Stream headerStream) - { - headerStream.Seek(0L, SeekOrigin.Begin); - byte[] buffer1 = new byte[4]; - if (!this.isShortImet) - headerStream.Read(this.additionalPadding, 0, this.additionalPadding.Length); - headerStream.Read(this.padding, 0, this.padding.Length); - headerStream.Read(buffer1, 0, 4); - if ((int) Shared.Swap(BitConverter.ToUInt32(buffer1, 0)) != (int) this.imetMagic) - throw new Exception("Invalid Magic!"); - headerStream.Read(buffer1, 0, 4); - if ((int) Shared.Swap(BitConverter.ToUInt32(buffer1, 0)) != (int) this.sizeOfHeader) - throw new Exception("Invalid Header Size!"); - headerStream.Read(buffer1, 0, 4); - this.unknown = Shared.Swap(BitConverter.ToUInt32(buffer1, 0)); - headerStream.Read(buffer1, 0, 4); - this.iconSize = Shared.Swap(BitConverter.ToUInt32(buffer1, 0)); - headerStream.Read(buffer1, 0, 4); - this.bannerSize = Shared.Swap(BitConverter.ToUInt32(buffer1, 0)); - headerStream.Read(buffer1, 0, 4); - this.soundSize = Shared.Swap(BitConverter.ToUInt32(buffer1, 0)); - headerStream.Read(buffer1, 0, 4); - this.flags = Shared.Swap(BitConverter.ToUInt32(buffer1, 0)); - headerStream.Read(this.japaneseTitle, 0, this.japaneseTitle.Length); - headerStream.Read(this.englishTitle, 0, this.englishTitle.Length); - headerStream.Read(this.germanTitle, 0, this.germanTitle.Length); - headerStream.Read(this.frenchTitle, 0, this.frenchTitle.Length); - headerStream.Read(this.spanishTitle, 0, this.spanishTitle.Length); - headerStream.Read(this.italianTitle, 0, this.italianTitle.Length); - headerStream.Read(this.dutchTitle, 0, this.dutchTitle.Length); - headerStream.Read(this.unknownTitle1, 0, this.unknownTitle1.Length); - headerStream.Read(this.unknownTitle2, 0, this.unknownTitle2.Length); - headerStream.Read(this.koreanTitle, 0, this.koreanTitle.Length); - headerStream.Read(this.padding2, 0, this.padding2.Length); - headerStream.Read(this.hash, 0, this.hash.Length); - headerStream.Seek(-16L, SeekOrigin.Current); - headerStream.Write(new byte[16], 0, 16); - byte[] buffer2 = new byte[headerStream.Length]; - headerStream.Seek(0L, SeekOrigin.Begin); - headerStream.Read(buffer2, 0, buffer2.Length); - MD5 md5 = MD5.Create(); - byte[] hash = md5.ComputeHash(buffer2, !this.isShortImet ? 64 : 0, 1536); - md5.Clear(); - this.hashesMatch = Shared.CompareByteArrays(hash, this.hash); - } - - private string returnTitleAsString(byte[] title) - { - string empty = string.Empty; - for (int index = 0; index < 84; index += 2) - { - char ch = BitConverter.ToChar(new byte[2] - { - title[index + 1], - title[index] - }, 0); - if (ch != char.MinValue) - empty += ch.ToString(); - } - return empty; - } - - private void setTitleFromString(string title, int titleIndex) - { - byte[] numArray = new byte[84]; - for (int index = 0; index < title.Length; ++index) - { - byte[] bytes = BitConverter.GetBytes(title[index]); - numArray[index * 2 + 1] = bytes[0]; - numArray[index * 2] = bytes[1]; - } - switch (titleIndex) - { - case 0: - this.japaneseTitle = numArray; - break; - case 1: - this.englishTitle = numArray; - break; - case 2: - this.germanTitle = numArray; - break; - case 3: - this.frenchTitle = numArray; - break; - case 4: - this.spanishTitle = numArray; - break; - case 5: - this.italianTitle = numArray; - break; - case 6: - this.dutchTitle = numArray; - break; - case 7: - this.koreanTitle = numArray; - break; - } - } } - - public class IMD5 - { - private uint imd5Magic = 1229800501; - private uint fileSize; - private byte[] padding = new byte[8]; - private byte[] hash = new byte[16]; - - public uint FileSize => this.fileSize; - - public byte[] Hash => this.hash; - - private IMD5() - { - } - - public static Headers.IMD5 Load(string pathToFile) => Headers.IMD5.Load(File.ReadAllBytes(pathToFile)); - - public static Headers.IMD5 Load(byte[] fileOrHeader) - { - if (Headers.DetectHeader(fileOrHeader) != Headers.HeaderType.IMD5) - throw new Exception("No IMD5 Header found!"); - Headers.IMD5 imD5 = new Headers.IMD5(); - MemoryStream memoryStream = new MemoryStream(fileOrHeader); - try - { - imD5.parseHeader((Stream) memoryStream); - } - catch - { - memoryStream.Dispose(); - throw; - } - memoryStream.Dispose(); - return imD5; - } - - public static Headers.IMD5 Load(Stream fileOrHeader) - { - if (Headers.DetectHeader(fileOrHeader) != Headers.HeaderType.IMD5) - throw new Exception("No IMD5 Header found!"); - Headers.IMD5 imD5 = new Headers.IMD5(); - imD5.parseHeader(fileOrHeader); - return imD5; - } - - public static Headers.IMD5 Create(byte[] file) - { - Headers.IMD5 imD5 = new Headers.IMD5(); - imD5.fileSize = (uint) file.Length; - imD5.computeHash(file); - return imD5; - } - - public static void AddHeader(string pathToFile) - { - byte[] buffer = Headers.IMD5.AddHeader(File.ReadAllBytes(pathToFile)); - File.Delete(pathToFile); - using (FileStream fileStream = new FileStream(pathToFile, FileMode.Create)) - fileStream.Write(buffer, 0, buffer.Length); - } - - public static byte[] AddHeader(byte[] file) - { - Headers.IMD5 imD5 = Headers.IMD5.Create(file); - MemoryStream memoryStream1 = new MemoryStream(); - MemoryStream memoryStream2 = memoryStream1; - imD5.writeToStream((Stream) memoryStream2); - memoryStream1.Write(file, 0, file.Length); - byte[] array = memoryStream1.ToArray(); - memoryStream1.Dispose(); - return array; - } - - public static void RemoveHeader(string pathToFile) - { - byte[] buffer = Headers.IMD5.RemoveHeader(File.ReadAllBytes(pathToFile)); - File.Delete(pathToFile); - using (FileStream fileStream = new FileStream(pathToFile, FileMode.Create)) - fileStream.Write(buffer, 0, buffer.Length); - } - - public static byte[] RemoveHeader(byte[] file) - { - MemoryStream memoryStream = new MemoryStream(); - memoryStream.Write(file, 32, file.Length - 32); - byte[] array = memoryStream.ToArray(); - memoryStream.Dispose(); - return array; - } - - public MemoryStream ToMemoryStream() - { - MemoryStream memoryStream = new MemoryStream(); - try - { - this.writeToStream((Stream) memoryStream); - return memoryStream; - } - catch - { - memoryStream.Dispose(); - throw; - } - } - - public byte[] ToByteArray() => this.ToMemoryStream().ToArray(); - - public void Write(Stream writeStream) => this.writeToStream(writeStream); - - private void writeToStream(Stream writeStream) - { - writeStream.Seek(0L, SeekOrigin.Begin); - writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.imd5Magic)), 0, 4); - writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.fileSize)), 0, 4); - writeStream.Write(this.padding, 0, this.padding.Length); - writeStream.Write(this.hash, 0, this.hash.Length); - } - - private void computeHash(byte[] bytesToHash) - { - MD5 md5 = MD5.Create(); - this.hash = md5.ComputeHash(bytesToHash); - md5.Clear(); - } - - private void parseHeader(Stream headerStream) - { - headerStream.Seek(0L, SeekOrigin.Begin); - byte[] buffer = new byte[4]; - headerStream.Read(buffer, 0, 4); - if ((int) Shared.Swap(BitConverter.ToUInt32(buffer, 0)) != (int) this.imd5Magic) - throw new Exception("Invalid Magic!"); - headerStream.Read(buffer, 0, 4); - this.fileSize = Shared.Swap(BitConverter.ToUInt32(buffer, 0)); - headerStream.Read(this.padding, 0, this.padding.Length); - headerStream.Read(this.hash, 0, this.hash.Length); - } - } - } } diff --git a/HexView.cs b/HexView.cs index 232cbb1..864765d 100644 --- a/HexView.cs +++ b/HexView.cs @@ -1,8 +1,20 @@ -// Decompiled with JetBrains decompiler -// Type: libWiiSharp.HexView -// Assembly: libWiiSharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=null -// MVID: FBF36F3D-B5D6-481F-B5F5-1BD3C19E13B2 -// Assembly location: C:\Users\theso\Downloads\NCPatcher\pack\libWiiSharp.dll +/* This file is part of libWiiSharp + * Copyright (C) 2009 Leathl + * Copyright (C) 2020 Github Contributors + * + * libWiiSharp is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libWiiSharp is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ using System; using System.Collections.Generic; @@ -12,249 +24,319 @@ using System.Windows.Forms; namespace libWiiSharp { - public static class HexView - { - private static string savedValue; - - public static void DumpToListView(byte[] data, ListView listView) => HexView.dumpToListView(data, listView); - - public static void DumpToDataGridView(byte[] data, DataGridView dataGridView) => HexView.dumpToDataGridView(data, dataGridView); - - public static byte[] DumpFromDataGridView(DataGridView dataGridView) => HexView.dumpFromDataGridView(dataGridView); - - public static void DumpToRichTextBox(byte[] data, RichTextBox richTextBox) + /// + /// A static class that provides functions to dump a byte array to view it like in a hex-editor. + /// In combination with a DataGridView, it's even able to act like a hex-editor. + /// Big files (25kB ++) will take quite a long time, so don't use this for big files. + /// + public static class HexView { - richTextBox.Clear(); - richTextBox.Font = new Font("Courier New", 9f); - richTextBox.ReadOnly = true; - richTextBox.Text = HexView.DumpAsString(data); + private static string savedValue; + + #region Public Functions + /// + /// Displays the byte array like a hex editor in a ListView. + /// Columns will be created, estimated width is ~685 px. + /// Big files (25kB ++) will take quite a long time, so don't use this for big files. + /// + /// + /// + public static void DumpToListView(byte[] data, ListView listView) => HexView.dumpToListView(data, listView); + + /// + /// Displays the byte array like a hex editor in a DataGridView. + /// Columns will be created, estimated width is ~685 px. + /// Big files (25kB ++) will take quite a long time, so don't use this for big files. + /// + /// + /// + public static void DumpToDataGridView(byte[] data, DataGridView dataGridView) => HexView.dumpToDataGridView(data, dataGridView); + + /// + /// Dumps a DataGridView back to a byte array. + /// The DataGridView must have the right format. + /// Big files (25kB ++) will take quite a long time, so don't use this for big files. + /// + /// + /// + public static byte[] DumpFromDataGridView(DataGridView dataGridView) => HexView.dumpFromDataGridView(dataGridView); + + /// + /// Displays the byte array like a hex editor in a RichTextBox. + /// Big files (25kB ++) will take quite a long time, so don't use this for big files. + /// + /// + /// + public static void DumpToRichTextBox(byte[] data, RichTextBox richTextBox) + { + richTextBox.Clear(); + richTextBox.Font = new Font("Courier New", 9f); + richTextBox.ReadOnly = true; + richTextBox.Text = HexView.DumpAsString(data); + } + + /// + /// Displays the byte array like a hex editor in a TextBox. + /// Big files (25kB ++) will take quite a long time, so don't use this for big files. + /// + /// + /// + public static void DumpToTextBox(byte[] data, TextBox textBox) + { + textBox.Multiline = true; + textBox.Font = new Font("Courier New", 9f); + textBox.ReadOnly = true; + textBox.Text = HexView.DumpAsString(data).Replace("\n", "\r\n"); + } + + /// + /// Displays the byte array like a hex editor as a string array. + /// Be sure to use "Courier New" as a font, so every char has the same width. + /// Big files (25kB ++) will take quite a long time, so don't use this for big files. + /// + /// + /// + public static string[] DumpAsStringArray(byte[] data) => HexView.dumpAsStringArray(data); + + /// + /// Displays the byte array like a hex editor as a string. + /// Be sure to use "Courier New" as a font, so every char has the same width. + /// Big files (25kB ++) will take quite a long time, so don't use this for big files. + /// + /// + /// + public static string DumpAsString(byte[] data) => string.Join("\n", HexView.dumpAsStringArray(data)); + + /// + /// Link your DataGridView's CellEndEdit event with this function. + /// The dump and byte values will be synchronized. + /// Don't forget to also link the CellBeginEdit event. + /// + /// + /// + public static void DataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e) + { + try + { + DataGridView dataGridView = sender as DataGridView; + if (dataGridView.Columns[e.ColumnIndex].HeaderText.ToLower() == "dump") + { + string str = (string) dataGridView.Rows[e.RowIndex].Cells[17].Value; + if (!(str != HexView.savedValue)) + return; + if (str.Length != 16) + throw new Exception(); + for (int index = 0; index < 16; ++index) + { + if ((int) HexView.toAscii(byte.Parse((string) dataGridView.Rows[e.RowIndex].Cells[index + 1].Value, NumberStyles.HexNumber)) != (int) str[index]) + dataGridView.Rows[e.RowIndex].Cells[index + 1].Value = (object) HexView.fromAscii(str[index]).ToString("x2"); + } + } + else + { + if (((string) dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value).Length == 1) + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = (object) ("0" + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value?.ToString()); + int startIndex = int.Parse(dataGridView.Columns[e.ColumnIndex].HeaderText, NumberStyles.HexNumber); + string str = ((string) dataGridView.Rows[e.RowIndex].Cells[17].Value).Remove(startIndex, 1).Insert(startIndex, HexView.toAscii(byte.Parse((string) dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value, NumberStyles.HexNumber)).ToString()); + dataGridView.Rows[e.RowIndex].Cells[17].Value = (object) str; + if (((string) dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value).Length <= 2) + return; + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = (object) ((string) dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value).Remove(0, ((string) dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value).Length - 2); + } + } + catch + { + ((DataGridView) sender).Rows[e.RowIndex].Cells[e.ColumnIndex].Value = (object) HexView.savedValue; + } + } + + /// + /// Link your DataGridView's CellBeginEdit event with this function. + /// The dump and byte values will be synchronized. + /// Don't forget to also link the CellEndEdit event. + /// + /// + /// + public static void DataGridView_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) => HexView.savedValue = (string) ((DataGridView) sender).Rows[e.RowIndex].Cells[e.ColumnIndex].Value; + #endregion + + #region Private Functions + private static string[] dumpAsStringArray(byte[] data) + { + List stringList = new List(); + string empty = string.Empty; + int num; + char ascii; + for (num = 0; (double) (data.Length - num) / 16.0 >= 1.0; num += 16) + { + string str1 = string.Empty + num.ToString("x8") + " "; + string str2 = string.Empty; + for (int index = 0; index < 16; ++index) + { + str1 = str1 + data[num + index].ToString("x2") + " "; + string str3 = str2; + ascii = HexView.toAscii(data[num + index]); + string str4 = ascii.ToString(); + str2 = str3 + str4; + } + string str5 = str1 + " " + str2; + stringList.Add(str5); + } + if (data.Length > num) + { + string str1 = string.Empty + num.ToString("x8") + " "; + string str2 = string.Empty; + for (int index = 0; index < 16; ++index) + { + if (index < data.Length - num) + { + str1 = str1 + data[num + index].ToString("x2") + " "; + string str3 = str2; + ascii = HexView.toAscii(data[num + index]); + string str4 = ascii.ToString(); + str2 = str3 + str4; + } + else + str1 += " "; + } + string str5 = str1 + " " + str2; + stringList.Add(str5); + } + return stringList.ToArray(); + } + + private static byte[] dumpFromDataGridView(DataGridView dataGridView) + { + try + { + List byteList = new List(); + for (int index1 = 0; !string.IsNullOrEmpty((string) dataGridView.Rows[index1].Cells[1].Value); ++index1) + { + for (int index2 = 0; index2 < 16; ++index2) + { + if (!string.IsNullOrEmpty((string) dataGridView.Rows[index1].Cells[index2 + 1].Value)) + byteList.Add(byte.Parse((string) dataGridView.Rows[index1].Cells[index2 + 1].Value, NumberStyles.HexNumber)); + } + if (index1 == dataGridView.Rows.Count - 1) + break; + } + return byteList.ToArray(); + } + catch + { + throw new Exception("An error occured. The DataGridView might have the wrong format!"); + } + } + + private static void dumpToDataGridView(byte[] data, DataGridView dataGridView) + { + dataGridView.Columns.Clear(); + dataGridView.Rows.Clear(); + dataGridView.Font = new Font("Courier New", 9f); + dataGridView.Columns.Add(new DataGridViewColumn() + { + HeaderText = "Offset", + Width = 80, + CellTemplate = (DataGridViewCell) new DataGridViewTextBoxCell() + }); + for (int index = 0; index < 16; ++index) + dataGridView.Columns.Add(new DataGridViewColumn() + { + HeaderText = index.ToString("x1"), + Width = 30, + CellTemplate = (DataGridViewCell) new DataGridViewTextBoxCell() + }); + dataGridView.Columns.Add(new DataGridViewColumn() + { + HeaderText = "Dump", + Width = 125, + CellTemplate = (DataGridViewCell) new DataGridViewTextBoxCell() + }); + int num; + for (num = 0; (double) (data.Length - num) / 16.0 >= 1.0; num += 16) + { + DataGridViewRow dataGridViewRow = new DataGridViewRow(); + int index1 = dataGridViewRow.Cells.Add((DataGridViewCell) new DataGridViewTextBoxCell()); + dataGridViewRow.Cells[index1].Value = (object) num.ToString("x8"); + dataGridViewRow.Cells[index1].ReadOnly = true; + string empty = string.Empty; + for (int index2 = 0; index2 < 16; ++index2) + { + int index3 = dataGridViewRow.Cells.Add((DataGridViewCell) new DataGridViewTextBoxCell()); + dataGridViewRow.Cells[index3].Value = (object) data[num + index2].ToString("x2"); + empty += HexView.toAscii(data[num + index2]).ToString(); + } + int index4 = dataGridViewRow.Cells.Add((DataGridViewCell) new DataGridViewTextBoxCell()); + dataGridViewRow.Cells[index4].Value = (object) empty; + dataGridView.Rows.Add(dataGridViewRow); + } + if (data.Length <= num) + return; + DataGridViewRow dataGridViewRow1 = new DataGridViewRow(); + int index5 = dataGridViewRow1.Cells.Add((DataGridViewCell) new DataGridViewTextBoxCell()); + dataGridViewRow1.Cells[index5].Value = (object) num.ToString("x8"); + dataGridViewRow1.Cells[index5].ReadOnly = true; + string empty1 = string.Empty; + for (int index1 = 0; index1 < 16; ++index1) + { + if (index1 < data.Length - num) + { + int index2 = dataGridViewRow1.Cells.Add((DataGridViewCell) new DataGridViewTextBoxCell()); + dataGridViewRow1.Cells[index2].Value = (object) data[num + index1].ToString("x2"); + empty1 += HexView.toAscii(data[num + index1]).ToString(); + } + else + dataGridViewRow1.Cells.Add((DataGridViewCell) new DataGridViewTextBoxCell()); + } + int index6 = dataGridViewRow1.Cells.Add((DataGridViewCell) new DataGridViewTextBoxCell()); + dataGridViewRow1.Cells[index6].Value = (object) empty1; + dataGridView.Rows.Add(dataGridViewRow1); + } + + private static void dumpToListView(byte[] data, ListView listView) + { + listView.Columns.Clear(); + listView.Items.Clear(); + listView.View = View.Details; + listView.Font = new Font("Courier New", 9f); + listView.Columns.Add("Offset", "Offset", 80, HorizontalAlignment.Left, string.Empty); + for (int index = 0; index < 16; ++index) + listView.Columns.Add(index.ToString("x1"), index.ToString("x1"), 30, HorizontalAlignment.Left, string.Empty); + listView.Columns.Add("Dump", "Dump", 125, HorizontalAlignment.Left, string.Empty); + int num; + for (num = 0; (double) (data.Length - num) / 16.0 >= 1.0; num += 16) + { + ListViewItem listViewItem = new ListViewItem(num.ToString("x8")); + string empty = string.Empty; + for (int index = 0; index < 16; ++index) + { + listViewItem.SubItems.Add(data[num + index].ToString("x2")); + empty += HexView.toAscii(data[num + index]).ToString(); + } + listViewItem.SubItems.Add(empty); + listView.Items.Add(listViewItem); + } + if (data.Length <= num) + return; + ListViewItem listViewItem1 = new ListViewItem(num.ToString("x8")); + string empty1 = string.Empty; + for (int index = 0; index < 16; ++index) + { + if (index < data.Length - num) + { + listViewItem1.SubItems.Add(data[num + index].ToString("x2")); + empty1 += HexView.toAscii(data[num + index]).ToString(); + } + else + listViewItem1.SubItems.Add(string.Empty); + } + listViewItem1.SubItems.Add(empty1); + listView.Items.Add(listViewItem1); + } + + private static char toAscii(byte value) => value >= (byte) 32 && value <= (byte) 126 ? (char) value : '.'; + + private static byte fromAscii(char value) => (byte) value; + #endregion } - - public static void DumpToTextBox(byte[] data, TextBox textBox) - { - textBox.Multiline = true; - textBox.Font = new Font("Courier New", 9f); - textBox.ReadOnly = true; - textBox.Text = HexView.DumpAsString(data).Replace("\n", "\r\n"); - } - - public static string[] DumpAsStringArray(byte[] data) => HexView.dumpAsStringArray(data); - - public static string DumpAsString(byte[] data) => string.Join("\n", HexView.dumpAsStringArray(data)); - - public static void DataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e) - { - try - { - DataGridView dataGridView = sender as DataGridView; - if (dataGridView.Columns[e.ColumnIndex].HeaderText.ToLower() == "dump") - { - string str = (string) dataGridView.Rows[e.RowIndex].Cells[17].Value; - if (!(str != HexView.savedValue)) - return; - if (str.Length != 16) - throw new Exception(); - for (int index = 0; index < 16; ++index) - { - if ((int) HexView.toAscii(byte.Parse((string) dataGridView.Rows[e.RowIndex].Cells[index + 1].Value, NumberStyles.HexNumber)) != (int) str[index]) - dataGridView.Rows[e.RowIndex].Cells[index + 1].Value = (object) HexView.fromAscii(str[index]).ToString("x2"); - } - } - else - { - if (((string) dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value).Length == 1) - dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = (object) ("0" + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value?.ToString()); - int startIndex = int.Parse(dataGridView.Columns[e.ColumnIndex].HeaderText, NumberStyles.HexNumber); - string str = ((string) dataGridView.Rows[e.RowIndex].Cells[17].Value).Remove(startIndex, 1).Insert(startIndex, HexView.toAscii(byte.Parse((string) dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value, NumberStyles.HexNumber)).ToString()); - dataGridView.Rows[e.RowIndex].Cells[17].Value = (object) str; - if (((string) dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value).Length <= 2) - return; - dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = (object) ((string) dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value).Remove(0, ((string) dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value).Length - 2); - } - } - catch - { - ((DataGridView) sender).Rows[e.RowIndex].Cells[e.ColumnIndex].Value = (object) HexView.savedValue; - } - } - - public static void DataGridView_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) => HexView.savedValue = (string) ((DataGridView) sender).Rows[e.RowIndex].Cells[e.ColumnIndex].Value; - - private static string[] dumpAsStringArray(byte[] data) - { - List stringList = new List(); - string empty = string.Empty; - int num; - char ascii; - for (num = 0; (double) (data.Length - num) / 16.0 >= 1.0; num += 16) - { - string str1 = string.Empty + num.ToString("x8") + " "; - string str2 = string.Empty; - for (int index = 0; index < 16; ++index) - { - str1 = str1 + data[num + index].ToString("x2") + " "; - string str3 = str2; - ascii = HexView.toAscii(data[num + index]); - string str4 = ascii.ToString(); - str2 = str3 + str4; - } - string str5 = str1 + " " + str2; - stringList.Add(str5); - } - if (data.Length > num) - { - string str1 = string.Empty + num.ToString("x8") + " "; - string str2 = string.Empty; - for (int index = 0; index < 16; ++index) - { - if (index < data.Length - num) - { - str1 = str1 + data[num + index].ToString("x2") + " "; - string str3 = str2; - ascii = HexView.toAscii(data[num + index]); - string str4 = ascii.ToString(); - str2 = str3 + str4; - } - else - str1 += " "; - } - string str5 = str1 + " " + str2; - stringList.Add(str5); - } - return stringList.ToArray(); - } - - private static byte[] dumpFromDataGridView(DataGridView dataGridView) - { - try - { - List byteList = new List(); - for (int index1 = 0; !string.IsNullOrEmpty((string) dataGridView.Rows[index1].Cells[1].Value); ++index1) - { - for (int index2 = 0; index2 < 16; ++index2) - { - if (!string.IsNullOrEmpty((string) dataGridView.Rows[index1].Cells[index2 + 1].Value)) - byteList.Add(byte.Parse((string) dataGridView.Rows[index1].Cells[index2 + 1].Value, NumberStyles.HexNumber)); - } - if (index1 == dataGridView.Rows.Count - 1) - break; - } - return byteList.ToArray(); - } - catch - { - throw new Exception("An error occured. The DataGridView might have the wrong format!"); - } - } - - private static void dumpToDataGridView(byte[] data, DataGridView dataGridView) - { - dataGridView.Columns.Clear(); - dataGridView.Rows.Clear(); - dataGridView.Font = new Font("Courier New", 9f); - dataGridView.Columns.Add(new DataGridViewColumn() - { - HeaderText = "Offset", - Width = 80, - CellTemplate = (DataGridViewCell) new DataGridViewTextBoxCell() - }); - for (int index = 0; index < 16; ++index) - dataGridView.Columns.Add(new DataGridViewColumn() - { - HeaderText = index.ToString("x1"), - Width = 30, - CellTemplate = (DataGridViewCell) new DataGridViewTextBoxCell() - }); - dataGridView.Columns.Add(new DataGridViewColumn() - { - HeaderText = "Dump", - Width = 125, - CellTemplate = (DataGridViewCell) new DataGridViewTextBoxCell() - }); - int num; - for (num = 0; (double) (data.Length - num) / 16.0 >= 1.0; num += 16) - { - DataGridViewRow dataGridViewRow = new DataGridViewRow(); - int index1 = dataGridViewRow.Cells.Add((DataGridViewCell) new DataGridViewTextBoxCell()); - dataGridViewRow.Cells[index1].Value = (object) num.ToString("x8"); - dataGridViewRow.Cells[index1].ReadOnly = true; - string empty = string.Empty; - for (int index2 = 0; index2 < 16; ++index2) - { - int index3 = dataGridViewRow.Cells.Add((DataGridViewCell) new DataGridViewTextBoxCell()); - dataGridViewRow.Cells[index3].Value = (object) data[num + index2].ToString("x2"); - empty += HexView.toAscii(data[num + index2]).ToString(); - } - int index4 = dataGridViewRow.Cells.Add((DataGridViewCell) new DataGridViewTextBoxCell()); - dataGridViewRow.Cells[index4].Value = (object) empty; - dataGridView.Rows.Add(dataGridViewRow); - } - if (data.Length <= num) - return; - DataGridViewRow dataGridViewRow1 = new DataGridViewRow(); - int index5 = dataGridViewRow1.Cells.Add((DataGridViewCell) new DataGridViewTextBoxCell()); - dataGridViewRow1.Cells[index5].Value = (object) num.ToString("x8"); - dataGridViewRow1.Cells[index5].ReadOnly = true; - string empty1 = string.Empty; - for (int index1 = 0; index1 < 16; ++index1) - { - if (index1 < data.Length - num) - { - int index2 = dataGridViewRow1.Cells.Add((DataGridViewCell) new DataGridViewTextBoxCell()); - dataGridViewRow1.Cells[index2].Value = (object) data[num + index1].ToString("x2"); - empty1 += HexView.toAscii(data[num + index1]).ToString(); - } - else - dataGridViewRow1.Cells.Add((DataGridViewCell) new DataGridViewTextBoxCell()); - } - int index6 = dataGridViewRow1.Cells.Add((DataGridViewCell) new DataGridViewTextBoxCell()); - dataGridViewRow1.Cells[index6].Value = (object) empty1; - dataGridView.Rows.Add(dataGridViewRow1); - } - - private static void dumpToListView(byte[] data, ListView listView) - { - listView.Columns.Clear(); - listView.Items.Clear(); - listView.View = View.Details; - listView.Font = new Font("Courier New", 9f); - listView.Columns.Add("Offset", "Offset", 80, HorizontalAlignment.Left, string.Empty); - for (int index = 0; index < 16; ++index) - listView.Columns.Add(index.ToString("x1"), index.ToString("x1"), 30, HorizontalAlignment.Left, string.Empty); - listView.Columns.Add("Dump", "Dump", 125, HorizontalAlignment.Left, string.Empty); - int num; - for (num = 0; (double) (data.Length - num) / 16.0 >= 1.0; num += 16) - { - ListViewItem listViewItem = new ListViewItem(num.ToString("x8")); - string empty = string.Empty; - for (int index = 0; index < 16; ++index) - { - listViewItem.SubItems.Add(data[num + index].ToString("x2")); - empty += HexView.toAscii(data[num + index]).ToString(); - } - listViewItem.SubItems.Add(empty); - listView.Items.Add(listViewItem); - } - if (data.Length <= num) - return; - ListViewItem listViewItem1 = new ListViewItem(num.ToString("x8")); - string empty1 = string.Empty; - for (int index = 0; index < 16; ++index) - { - if (index < data.Length - num) - { - listViewItem1.SubItems.Add(data[num + index].ToString("x2")); - empty1 += HexView.toAscii(data[num + index]).ToString(); - } - else - listViewItem1.SubItems.Add(string.Empty); - } - listViewItem1.SubItems.Add(empty1); - listView.Items.Add(listViewItem1); - } - - private static char toAscii(byte value) => value >= (byte) 32 && value <= (byte) 126 ? (char) value : '.'; - - private static byte fromAscii(char value) => (byte) value; - } } diff --git a/IosPatcher.cs b/IosPatcher.cs index 82dd0e3..82c5d4d 100644 --- a/IosPatcher.cs +++ b/IosPatcher.cs @@ -1,8 +1,20 @@ -// Decompiled with JetBrains decompiler -// Type: libWiiSharp.IosPatcher -// Assembly: libWiiSharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=null -// MVID: FBF36F3D-B5D6-481F-B5F5-1BD3C19E13B2 -// Assembly location: C:\Users\theso\Downloads\NCPatcher\pack\libWiiSharp.dll +/* This file is part of libWiiSharp + * Copyright (C) 2009 Leathl + * Copyright (C) 2020 Github Contributors + * + * libWiiSharp is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libWiiSharp is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ using System; using System.ComponentModel; @@ -10,277 +22,314 @@ using System.Text; namespace libWiiSharp { - public class IosPatcher - { - private WAD wadFile; - private int esIndex = -1; - - public event EventHandler Progress; - - public event EventHandler Debug; - - public void LoadIOS(ref WAD iosWad) + /// + /// An IOS patcher which can patch fakesigning, es_identify and nand permissions. + /// + public class IosPatcher { - this.wadFile = iosWad; - this.getEsIndex(); - } + private WAD wadFile; + private int esIndex = -1; - public int PatchFakeSigning() => this.esIndex < 0 ? -1 : this.patchFakeSigning(ref this.wadFile.Contents[this.esIndex]); - - public int PatchEsIdentify() => this.esIndex < 0 ? -1 : this.patchEsIdentify(ref this.wadFile.Contents[this.esIndex]); - - public int PatchNandPermissions() => this.esIndex < 0 ? -1 : this.patchNandPermissions(ref this.wadFile.Contents[this.esIndex]); - - public int PatchVP() => this.esIndex < 0 ? -1 : this.patchVP(ref this.wadFile.Contents[this.esIndex]); - - public int PatchAll() => this.esIndex < 0 ? -1 : this.patchAll(ref this.wadFile.Contents[this.esIndex]); - - public int PatchFakeSigning(ref byte[] esModule) => this.patchFakeSigning(ref esModule); - - public int PatchEsIdentify(ref byte[] esModule) => this.patchEsIdentify(ref esModule); - - public int PatchNandPermissions(ref byte[] esModule) => this.patchNandPermissions(ref esModule); - - public int PatchVP(ref byte[] esModule) => this.patchVP(ref esModule); - - public int PatchAll(ref byte[] esModule) => this.patchAll(ref esModule); - - private int patchFakeSigning(ref byte[] esModule) - { - this.fireDebug("Patching Fakesigning..."); - int num = 0; - byte[] second1 = new byte[4] - { - (byte) 32, - (byte) 7, - (byte) 35, - (byte) 162 - }; - byte[] second2 = new byte[4] - { - (byte) 32, - (byte) 7, - (byte) 75, - (byte) 11 - }; - for (int firstIndex = 0; firstIndex < esModule.Length - 4; ++firstIndex) - { - this.fireProgress((firstIndex + 1) * 100 / esModule.Length); - if (Shared.CompareByteArrays(esModule, firstIndex, second1, 0, 4) || Shared.CompareByteArrays(esModule, firstIndex, second2, 0, 4)) + #region Public Functions + /// + /// Loads an IOS wad to patch the es module. + /// + /// + public void LoadIOS(ref WAD iosWad) { - this.fireDebug(" Patching at Offset: 0x{0}", (object) firstIndex.ToString("x8").ToUpper()); - esModule[firstIndex + 1] = (byte) 0; - firstIndex += 4; - ++num; + this.wadFile = iosWad; + this.getEsIndex(); } - } - this.fireDebug("Patching Fakesigning Finished... (Patches applied: {0})", (object) num); - return num; - } - private int patchEsIdentify(ref byte[] esModule) - { - this.fireDebug("Patching ES_Identify..."); - int num = 0; - byte[] second = new byte[4] - { - (byte) 40, - (byte) 3, - (byte) 209, - (byte) 35 - }; - for (int firstIndex = 0; firstIndex < esModule.Length - 4; ++firstIndex) - { - this.fireProgress((firstIndex + 1) * 100 / esModule.Length); - if (Shared.CompareByteArrays(esModule, firstIndex, second, 0, 4)) - { - this.fireDebug(" Patching at Offset: 0x{0}", (object) firstIndex.ToString("x8").ToUpper()); - esModule[firstIndex + 2] = (byte) 0; - esModule[firstIndex + 3] = (byte) 0; - firstIndex += 4; - ++num; - } - } - this.fireDebug("Patching ES_Identify Finished... (Patches applied: {0})", (object) num); - return num; - } + /// + /// Patches fakesigning. + /// Returns the number of applied patches. + /// + /// + public int PatchFakeSigning() => this.esIndex < 0 ? -1 : this.patchFakeSigning(ref this.wadFile.Contents[this.esIndex]); - private int patchNandPermissions(ref byte[] esModule) - { - this.fireDebug("Patching NAND Permissions..."); - int num = 0; - byte[] second = new byte[6] - { - (byte) 66, - (byte) 139, - (byte) 208, - (byte) 1, - (byte) 37, - (byte) 102 - }; - for (int firstIndex = 0; firstIndex < esModule.Length - 6; ++firstIndex) - { - this.fireProgress((firstIndex + 1) * 100 / esModule.Length); - if (Shared.CompareByteArrays(esModule, firstIndex, second, 0, 6)) - { - this.fireDebug(" Patching at Offset: 0x{0}", (object) firstIndex.ToString("x8").ToUpper()); - esModule[firstIndex + 2] = (byte) 224; - firstIndex += 6; - ++num; - } - } - this.fireDebug("Patching NAND Permissions Finished... (Patches applied: {0})", (object) num); - return num; - } + /// + /// Patches es_identify. + /// Returns the number of applied patches. + /// + /// + public int PatchEsIdentify() => this.esIndex < 0 ? -1 : this.patchEsIdentify(ref this.wadFile.Contents[this.esIndex]); - private int patchVP(ref byte[] esModule) - { - this.fireDebug("Patching VP..."); - int num = 0; - byte[] second = new byte[4] - { - (byte) 210, - (byte) 1, - (byte) 78, - (byte) 86 - }; - for (int firstIndex = 0; firstIndex < esModule.Length - 4; ++firstIndex) - { - this.fireProgress((firstIndex + 1) * 100 / esModule.Length); - if (Shared.CompareByteArrays(esModule, firstIndex, second, 0, 4)) - { - this.fireDebug(" Patching for VP at Offset: 0x{0}", (object) firstIndex.ToString("x8").ToUpper()); - esModule[firstIndex] = (byte) 224; - firstIndex += 4; - ++num; - } - } - this.fireDebug("Patching VP Finished... (Patches applied: {0})", (object) num); - return num; - } + /// + /// Patches nand permissions. + /// Returns the number of applied patches. + /// + /// + public int PatchNandPermissions() => this.esIndex < 0 ? -1 : this.patchNandPermissions(ref this.wadFile.Contents[this.esIndex]); - private int patchAll(ref byte[] esModule) - { - this.fireDebug("Patching Fakesigning, ES_Identify, NAND Permissions and VP ..."); - int num = 0; - byte[] second1 = new byte[4] - { - (byte) 32, - (byte) 7, - (byte) 35, - (byte) 162 - }; - byte[] second2 = new byte[4] - { - (byte) 32, - (byte) 7, - (byte) 75, - (byte) 11 - }; - byte[] second3 = new byte[4] - { - (byte) 40, - (byte) 3, - (byte) 209, - (byte) 35 - }; - byte[] second4 = new byte[6] - { - (byte) 66, - (byte) 139, - (byte) 208, - (byte) 1, - (byte) 37, - (byte) 102 - }; - byte[] second5 = new byte[4] - { - (byte) 210, - (byte) 1, - (byte) 78, - (byte) 86 - }; - for (int firstIndex = 0; firstIndex < esModule.Length - 6; ++firstIndex) - { - this.fireProgress((firstIndex + 1) * 100 / esModule.Length); - if (Shared.CompareByteArrays(esModule, firstIndex, second1, 0, 4) || Shared.CompareByteArrays(esModule, firstIndex, second2, 0, 4)) - { - this.fireDebug(" Patching Fakesigning at Offset: 0x{0}", (object) firstIndex.ToString("x8").ToUpper()); - esModule[firstIndex + 1] = (byte) 0; - firstIndex += 4; - ++num; - } - else if (Shared.CompareByteArrays(esModule, firstIndex, second3, 0, 4)) - { - this.fireDebug(" Patching ES_Identify at Offset: 0x{0}", (object) firstIndex.ToString("x8").ToUpper()); - esModule[firstIndex + 2] = (byte) 0; - esModule[firstIndex + 3] = (byte) 0; - firstIndex += 4; - ++num; - } - else if (Shared.CompareByteArrays(esModule, firstIndex, second4, 0, 6)) - { - this.fireDebug(" Patching NAND Permissions at Offset: 0x{0}", (object) firstIndex.ToString("x8").ToUpper()); - esModule[firstIndex + 2] = (byte) 224; - firstIndex += 6; - ++num; - } - else if (Shared.CompareByteArrays(esModule, firstIndex, second5, 0, 4)) - { - this.fireDebug(" Patching VP at Offset: 0x{0}", (object) firstIndex.ToString("x8").ToUpper()); - esModule[firstIndex] = (byte) 224; - firstIndex += 4; - ++num; - } - } - this.fireDebug("Patching Fakesigning, ES_Identify, NAND Permissions and VP Finished... (Patches applied: {0})", (object) num); - return num; - } + public int PatchVP() => this.esIndex < 0 ? -1 : this.patchVP(ref this.wadFile.Contents[this.esIndex]); - private void getEsIndex() - { - this.fireDebug("Scanning for ES Module..."); - string str = "$IOSVersion:"; - for (int index1 = this.wadFile.NumOfContents - 1; index1 >= 0; --index1) - { - this.fireDebug(" Scanning Content #{0} of {1}...", (object) (index1 + 1), (object) this.wadFile.NumOfContents); - this.fireProgress((index1 + 1) * 100 / this.wadFile.NumOfContents); - for (int index2 = 0; index2 < this.wadFile.Contents[index1].Length - 64; ++index2) + /// + /// Patches fakesigning, es_identify and nand permissions. + /// Returns the number of applied patches. + /// + /// + public int PatchAll() => this.esIndex < 0 ? -1 : this.patchAll(ref this.wadFile.Contents[this.esIndex]); + + public int PatchFakeSigning(ref byte[] esModule) => this.patchFakeSigning(ref esModule); + + public int PatchEsIdentify(ref byte[] esModule) => this.patchEsIdentify(ref esModule); + + public int PatchNandPermissions(ref byte[] esModule) => this.patchNandPermissions(ref esModule); + + public int PatchVP(ref byte[] esModule) => this.patchVP(ref esModule); + + public int PatchAll(ref byte[] esModule) => this.patchAll(ref esModule); + #endregion + + #region Private Functions + private int patchFakeSigning(ref byte[] esModule) { - if (Encoding.ASCII.GetString(this.wadFile.Contents[index1], index2, 12) == str) - { - int index3 = index2 + 12; - while (this.wadFile.Contents[index1][index3] == (byte) 32) - ++index3; - if (Encoding.ASCII.GetString(this.wadFile.Contents[index1], index3, 3) == "ES:") + this.fireDebug("Patching Fakesigning..."); + int num = 0; + byte[] second1 = new byte[4] { - this.fireDebug(" -> ES Module found!"); - this.fireDebug("Scanning for ES Module Finished..."); - this.esIndex = index1; - this.fireProgress(100); - return; + (byte) 32, + (byte) 7, + (byte) 35, + (byte) 162 + }; + byte[] second2 = new byte[4] + { + (byte) 32, + (byte) 7, + (byte) 75, + (byte) 11 + }; + for (int firstIndex = 0; firstIndex < esModule.Length - 4; ++firstIndex) + { + this.fireProgress((firstIndex + 1) * 100 / esModule.Length); + if (Shared.CompareByteArrays(esModule, firstIndex, second1, 0, 4) || Shared.CompareByteArrays(esModule, firstIndex, second2, 0, 4)) + { + this.fireDebug(" Patching at Offset: 0x{0}", (object) firstIndex.ToString("x8").ToUpper()); + esModule[firstIndex + 1] = (byte) 0; + firstIndex += 4; + ++num; + } } - } + this.fireDebug("Patching Fakesigning Finished... (Patches applied: {0})", (object) num); + return num; } - } - this.fireDebug("/!\\/!\\/!\\ ES Module wasn't found! /!\\/!\\/!\\"); - throw new Exception("ES module wasn't found!"); - } - private void fireDebug(string debugMessage, params object[] args) - { - EventHandler debug = this.Debug; - if (debug == null) - return; - debug(new object(), new MessageEventArgs(string.Format(debugMessage, args))); - } + private int patchEsIdentify(ref byte[] esModule) + { + this.fireDebug("Patching ES_Identify..."); + int num = 0; + byte[] second = new byte[4] + { + (byte) 40, + (byte) 3, + (byte) 209, + (byte) 35 + }; + for (int firstIndex = 0; firstIndex < esModule.Length - 4; ++firstIndex) + { + this.fireProgress((firstIndex + 1) * 100 / esModule.Length); + if (Shared.CompareByteArrays(esModule, firstIndex, second, 0, 4)) + { + this.fireDebug(" Patching at Offset: 0x{0}", (object) firstIndex.ToString("x8").ToUpper()); + esModule[firstIndex + 2] = (byte) 0; + esModule[firstIndex + 3] = (byte) 0; + firstIndex += 4; + ++num; + } + } + this.fireDebug("Patching ES_Identify Finished... (Patches applied: {0})", (object) num); + return num; + } - private void fireProgress(int progressPercentage) - { - EventHandler progress = this.Progress; - if (progress == null) - return; - progress(new object(), new ProgressChangedEventArgs(progressPercentage, (object) string.Empty)); + private int patchNandPermissions(ref byte[] esModule) + { + this.fireDebug("Patching NAND Permissions..."); + int num = 0; + byte[] second = new byte[6] + { + (byte) 66, + (byte) 139, + (byte) 208, + (byte) 1, + (byte) 37, + (byte) 102 + }; + for (int firstIndex = 0; firstIndex < esModule.Length - 6; ++firstIndex) + { + this.fireProgress((firstIndex + 1) * 100 / esModule.Length); + if (Shared.CompareByteArrays(esModule, firstIndex, second, 0, 6)) + { + this.fireDebug(" Patching at Offset: 0x{0}", (object) firstIndex.ToString("x8").ToUpper()); + esModule[firstIndex + 2] = (byte) 224; + firstIndex += 6; + ++num; + } + } + this.fireDebug("Patching NAND Permissions Finished... (Patches applied: {0})", (object) num); + return num; + } + + private int patchVP(ref byte[] esModule) + { + this.fireDebug("Patching VP..."); + int num = 0; + byte[] second = new byte[4] + { + (byte) 210, + (byte) 1, + (byte) 78, + (byte) 86 + }; + for (int firstIndex = 0; firstIndex < esModule.Length - 4; ++firstIndex) + { + this.fireProgress((firstIndex + 1) * 100 / esModule.Length); + if (Shared.CompareByteArrays(esModule, firstIndex, second, 0, 4)) + { + this.fireDebug(" Patching for VP at Offset: 0x{0}", (object) firstIndex.ToString("x8").ToUpper()); + esModule[firstIndex] = (byte) 224; + firstIndex += 4; + ++num; + } + } + this.fireDebug("Patching VP Finished... (Patches applied: {0})", (object) num); + return num; + } + + private int patchAll(ref byte[] esModule) + { + this.fireDebug("Patching Fakesigning, ES_Identify, NAND Permissions and VP ..."); + int num = 0; + byte[] second1 = new byte[4] + { + (byte) 32, + (byte) 7, + (byte) 35, + (byte) 162 + }; + byte[] second2 = new byte[4] + { + (byte) 32, + (byte) 7, + (byte) 75, + (byte) 11 + }; + byte[] second3 = new byte[4] + { + (byte) 40, + (byte) 3, + (byte) 209, + (byte) 35 + }; + byte[] second4 = new byte[6] + { + (byte) 66, + (byte) 139, + (byte) 208, + (byte) 1, + (byte) 37, + (byte) 102 + }; + byte[] second5 = new byte[4] + { + (byte) 210, + (byte) 1, + (byte) 78, + (byte) 86 + }; + for (int firstIndex = 0; firstIndex < esModule.Length - 6; ++firstIndex) + { + this.fireProgress((firstIndex + 1) * 100 / esModule.Length); + if (Shared.CompareByteArrays(esModule, firstIndex, second1, 0, 4) || Shared.CompareByteArrays(esModule, firstIndex, second2, 0, 4)) + { + this.fireDebug(" Patching Fakesigning at Offset: 0x{0}", (object) firstIndex.ToString("x8").ToUpper()); + esModule[firstIndex + 1] = (byte) 0; + firstIndex += 4; + ++num; + } + else if (Shared.CompareByteArrays(esModule, firstIndex, second3, 0, 4)) + { + this.fireDebug(" Patching ES_Identify at Offset: 0x{0}", (object) firstIndex.ToString("x8").ToUpper()); + esModule[firstIndex + 2] = (byte) 0; + esModule[firstIndex + 3] = (byte) 0; + firstIndex += 4; + ++num; + } + else if (Shared.CompareByteArrays(esModule, firstIndex, second4, 0, 6)) + { + this.fireDebug(" Patching NAND Permissions at Offset: 0x{0}", (object) firstIndex.ToString("x8").ToUpper()); + esModule[firstIndex + 2] = (byte) 224; + firstIndex += 6; + ++num; + } + else if (Shared.CompareByteArrays(esModule, firstIndex, second5, 0, 4)) + { + this.fireDebug(" Patching VP at Offset: 0x{0}", (object) firstIndex.ToString("x8").ToUpper()); + esModule[firstIndex] = (byte) 224; + firstIndex += 4; + ++num; + } + } + this.fireDebug("Patching Fakesigning, ES_Identify, NAND Permissions and VP Finished... (Patches applied: {0})", (object) num); + return num; + } + + private void getEsIndex() + { + this.fireDebug("Scanning for ES Module..."); + string str = "$IOSVersion:"; + for (int index1 = this.wadFile.NumOfContents - 1; index1 >= 0; --index1) + { + this.fireDebug(" Scanning Content #{0} of {1}...", (object) (index1 + 1), (object) this.wadFile.NumOfContents); + this.fireProgress((index1 + 1) * 100 / this.wadFile.NumOfContents); + for (int index2 = 0; index2 < this.wadFile.Contents[index1].Length - 64; ++index2) + { + if (Encoding.ASCII.GetString(this.wadFile.Contents[index1], index2, 12) == str) + { + int index3 = index2 + 12; + while (this.wadFile.Contents[index1][index3] == (byte) 32) + ++index3; + if (Encoding.ASCII.GetString(this.wadFile.Contents[index1], index3, 3) == "ES:") + { + this.fireDebug(" -> ES Module found!"); + this.fireDebug("Scanning for ES Module Finished..."); + this.esIndex = index1; + this.fireProgress(100); + return; + } + } + } + } + this.fireDebug("/!\\/!\\/!\\ ES Module wasn't found! /!\\/!\\/!\\"); + throw new Exception("ES module wasn't found!"); + } + #endregion + + #region Events + /// + /// Fires the Progress of various operations + /// + public event EventHandler Progress; + /// + /// Fires debugging messages. You may write them into a log file or log textbox. + /// + public event EventHandler Debug; + private void fireDebug(string debugMessage, params object[] args) + { + EventHandler debug = this.Debug; + if (debug == null) + return; + debug(new object(), new MessageEventArgs(string.Format(debugMessage, args))); + } + + private void fireProgress(int progressPercentage) + { + EventHandler progress = this.Progress; + if (progress == null) + return; + progress(new object(), new ProgressChangedEventArgs(progressPercentage, (object) string.Empty)); + } + #endregion } - } } diff --git a/LowerTitleID.cs b/LowerTitleID.cs deleted file mode 100644 index bd9b486..0000000 --- a/LowerTitleID.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Decompiled with JetBrains decompiler -// Type: libWiiSharp.LowerTitleID -// Assembly: libWiiSharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=null -// MVID: FBF36F3D-B5D6-481F-B5F5-1BD3C19E13B2 -// Assembly location: C:\Users\theso\Downloads\NCPatcher\pack\libWiiSharp.dll - -namespace libWiiSharp -{ - public enum LowerTitleID : uint - { - SystemTitles = 1, - Channel = 65537, // 0x00010001 - SystemChannels = 65538, // 0x00010002 - GameChannel = 65540, // 0x00010004 - DLC = 65541, // 0x00010005 - HiddenChannels = 65544, // 0x00010008 - } -} diff --git a/Protocol.cs b/Protocol.cs deleted file mode 100644 index a695c31..0000000 --- a/Protocol.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Decompiled with JetBrains decompiler -// Type: libWiiSharp.Protocol -// Assembly: libWiiSharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=null -// MVID: FBF36F3D-B5D6-481F-B5F5-1BD3C19E13B2 -// Assembly location: C:\Users\theso\Downloads\NCPatcher\pack\libWiiSharp.dll - -namespace libWiiSharp -{ - public enum Protocol - { - HAXX, - JODI, - Custom, - } -} diff --git a/TMD.cs b/TMD.cs index 8023f54..f5bc11b 100644 --- a/TMD.cs +++ b/TMD.cs @@ -11,7 +11,13 @@ using System.Security.Cryptography; namespace libWiiSharp { - public class TMD : IDisposable + public enum ContentType : ushort + { + Normal = 1, + DLC = 16385, // 0x4001 + Shared = 32769, // 0x8001 + } + public class TMD : IDisposable { private bool fakeSign; private bool sortContents; diff --git a/Ticket.cs b/Ticket.cs index b982e67..fe2f306 100644 --- a/Ticket.cs +++ b/Ticket.cs @@ -10,8 +10,15 @@ using System.Security.Cryptography; namespace libWiiSharp { - public class Ticket : IDisposable - { + + public enum CommonKeyType : byte + { + Standard = 0x00, + Korean = 0x01, + } + + public class Ticket : IDisposable + { private byte newKeyIndex; private byte[] decryptedTitleKey = new byte[16]; private bool fakeSign; diff --git a/WAD.cs b/WAD.cs index f1019fa..46cb065 100644 --- a/WAD.cs +++ b/WAD.cs @@ -13,7 +13,16 @@ using System.Text; namespace libWiiSharp { - public class WAD : IDisposable + public enum LowerTitleID : uint + { + SystemTitles = 0x00000001, + SystemChannels = 0x00010002, + Channel = 0x00010001, + GameChannel = 0x00010004, + DLC = 0x00010005, + HiddenChannels = 0x00010008, + } + public class WAD : IDisposable { private SHA1 sha = SHA1.Create(); private DateTime creationTimeUTC = new DateTime(1970, 1, 1); @@ -999,4 +1008,38 @@ namespace libWiiSharp private void bannerApp_Warning(object sender, MessageEventArgs e) => this.fireWarning(e.Message); } + + public class WAD_Header + { + private uint headerSize = 0x20; + private uint wadType = 0x49730000; + private uint certSize = 0xA00; + private uint reserved = 0x00; + private uint tikSize = 0x2A4; + private uint tmdSize; + private uint contentSize; + private uint footerSize = 0x00; + + public uint HeaderSize { get { return headerSize; } } + public uint WadType { get { return wadType; } set { wadType = value; } } + public uint CertSize { get { return certSize; } } + public uint Reserved { get { return reserved; } } + public uint TicketSize { get { return tikSize; } } + public uint TmdSize { get { return tmdSize; } set { tmdSize = value; } } + public uint ContentSize { get { return contentSize; } set { contentSize = value; } } + public uint FooterSize { get { return footerSize; } set { footerSize = value; } } + + public void Write(Stream writeStream) + { + writeStream.Seek(0, SeekOrigin.Begin); + writeStream.Write(BitConverter.GetBytes(Shared.Swap(headerSize)), 0, 4); + writeStream.Write(BitConverter.GetBytes(Shared.Swap(wadType)), 0, 4); + writeStream.Write(BitConverter.GetBytes(Shared.Swap(certSize)), 0, 4); + writeStream.Write(BitConverter.GetBytes(Shared.Swap(reserved)), 0, 4); + writeStream.Write(BitConverter.GetBytes(Shared.Swap(tikSize)), 0, 4); + writeStream.Write(BitConverter.GetBytes(Shared.Swap(tmdSize)), 0, 4); + writeStream.Write(BitConverter.GetBytes(Shared.Swap(contentSize)), 0, 4); + writeStream.Write(BitConverter.GetBytes(Shared.Swap(footerSize)), 0, 4); + } + } } diff --git a/WAD_Header.cs b/WAD_Header.cs deleted file mode 100644 index 5579902..0000000 --- a/WAD_Header.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Decompiled with JetBrains decompiler -// Type: libWiiSharp.WAD_Header -// Assembly: libWiiSharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=null -// MVID: FBF36F3D-B5D6-481F-B5F5-1BD3C19E13B2 -// Assembly location: C:\Users\theso\Downloads\NCPatcher\pack\libWiiSharp.dll - -using System; -using System.IO; - -namespace libWiiSharp -{ - public class WAD_Header - { - private uint headerSize = 32; - private uint wadType = 1232273408; - private uint certSize = 2560; - private uint reserved; - private uint tikSize = 676; - private uint tmdSize; - private uint contentSize; - private uint footerSize; - - public uint HeaderSize => this.headerSize; - - public uint WadType - { - get => this.wadType; - set => this.wadType = value; - } - - public uint CertSize => this.certSize; - - public uint Reserved => this.reserved; - - public uint TicketSize => this.tikSize; - - public uint TmdSize - { - get => this.tmdSize; - set => this.tmdSize = value; - } - - public uint ContentSize - { - get => this.contentSize; - set => this.contentSize = value; - } - - public uint FooterSize - { - get => this.footerSize; - set => this.footerSize = value; - } - - public void Write(Stream writeStream) - { - writeStream.Seek(0L, SeekOrigin.Begin); - writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.headerSize)), 0, 4); - writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.wadType)), 0, 4); - writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.certSize)), 0, 4); - writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.reserved)), 0, 4); - writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.tikSize)), 0, 4); - writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.tmdSize)), 0, 4); - writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.contentSize)), 0, 4); - writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.footerSize)), 0, 4); - } - } -} diff --git a/libWiiSharp.csproj b/libWiiSharp.csproj index bd7f885..9b1e20a 100644 --- a/libWiiSharp.csproj +++ b/libWiiSharp.csproj @@ -55,18 +55,14 @@ - - - - @@ -85,14 +81,12 @@ - - diff --git a/libWiiSharp.csproj.user b/libWiiSharp.csproj.user new file mode 100644 index 0000000..c10e84b --- /dev/null +++ b/libWiiSharp.csproj.user @@ -0,0 +1,6 @@ + + + + ProjectFiles + + \ No newline at end of file diff --git a/zlibWrapper.cs b/zlibWrapper.cs deleted file mode 100644 index 2c61042..0000000 --- a/zlibWrapper.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Decompiled with JetBrains decompiler -// Type: libWiiSharp.zlibWrapper -// Assembly: libWiiSharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=null -// MVID: FBF36F3D-B5D6-481F-B5F5-1BD3C19E13B2 -// Assembly location: C:\Users\theso\Downloads\NCPatcher\pack\libWiiSharp.dll - -using System; -using System.Runtime.InteropServices; - -namespace libWiiSharp -{ - internal class zlibWrapper - { - [DllImport("zlib1.dll")] - private static extern zlibWrapper.ZLibError compress2( - byte[] dest, - ref int destLength, - byte[] source, - int sourceLength, - int level); - - public static byte[] Compress(byte[] inFile) - { - byte[] array = new byte[inFile.Length + 64]; - int destLength = -1; - zlibWrapper.ZLibError zlibError = zlibWrapper.compress2(array, ref destLength, inFile, inFile.Length, 6); - if (zlibError != zlibWrapper.ZLibError.Z_OK || destLength <= -1 || destLength >= inFile.Length) - throw new Exception("An error occured while compressing! Code: " + zlibError.ToString()); - Array.Resize(ref array, destLength); - return array; - } - - public enum ZLibError - { - Z_VERSION_ERROR = -6, // 0xFFFFFFFA - Z_BUF_ERROR = -5, // 0xFFFFFFFB - Z_MEM_ERROR = -4, // 0xFFFFFFFC - Z_DATA_ERROR = -3, // 0xFFFFFFFD - Z_STREAM_ERROR = -2, // 0xFFFFFFFE - Z_ERRNO = -1, // 0xFFFFFFFF - Z_OK = 0, - Z_STREAM_END = 1, - Z_NEED_DICT = 2, - } - } -}