mirror of
https://github.com/TheShadowEevee/libWiiSharp.git
synced 2025-01-11 07:28:50 -06:00
Add decompiled and edited files
I need to fix the formatting and rename some variables, but that's for another time. Licence, readme, and changelog are from the original libWiiSharp repo.
This commit is contained in:
parent
c88763d31e
commit
b9c57a8ae9
54 changed files with 10545 additions and 0 deletions
19
AssemblyInfo.cs
Normal file
19
AssemblyInfo.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Permissions;
|
||||
|
||||
[assembly: AssemblyTitle("libWiiSharp_ModMii")]
|
||||
[assembly: AssemblyDescription("a wii related .NET library modified for ModMii")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Leathl,SC reproductions")]
|
||||
[assembly: AssemblyProduct("libWiiSharp_ModMii")]
|
||||
[assembly: AssemblyCopyright("Copyright © Leathl 2011")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("af701263-5875-4866-9c09-d7f62e9f0ff0")]
|
||||
[assembly: AssemblyFileVersion("0.4.0.0")]
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
[assembly: AssemblyVersion("0.4.0.0")]
|
||||
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
|
||||
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
|
514
BNS.cs
Normal file
514
BNS.cs
Normal file
|
@ -0,0 +1,514 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.BNS
|
||||
// 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.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
|
||||
namespace libWiiSharp
|
||||
{
|
||||
public class BNS : IDisposable
|
||||
{
|
||||
private BNS_Header bnsHeader = new BNS_Header();
|
||||
private BNS_Info bnsInfo = new BNS_Info();
|
||||
private BNS_Data bnsData = new BNS_Data();
|
||||
private int[,] lSamples = new int[2, 2];
|
||||
private int[,] rlSamples = new int[2, 2];
|
||||
private int[] tlSamples = new int[2];
|
||||
private int[] hbcDefTbl = new int[16]
|
||||
{
|
||||
674,
|
||||
1040,
|
||||
3598,
|
||||
-1738,
|
||||
2270,
|
||||
-583,
|
||||
3967,
|
||||
-1969,
|
||||
1516,
|
||||
381,
|
||||
3453,
|
||||
-1468,
|
||||
2606,
|
||||
-617,
|
||||
3795,
|
||||
-1759
|
||||
};
|
||||
private int[] defTbl = new int[16]
|
||||
{
|
||||
1820,
|
||||
-856,
|
||||
3238,
|
||||
-1514,
|
||||
2333,
|
||||
-550,
|
||||
3336,
|
||||
-1376,
|
||||
2444,
|
||||
-949,
|
||||
3666,
|
||||
-1764,
|
||||
2654,
|
||||
-701,
|
||||
3420,
|
||||
-1398
|
||||
};
|
||||
private int[] pHist1 = new int[2];
|
||||
private int[] pHist2 = new int[2];
|
||||
private int tempSampleCount;
|
||||
private byte[] waveFile;
|
||||
private bool loopFromWave;
|
||||
private bool converted;
|
||||
private bool toMono;
|
||||
private bool isDisposed;
|
||||
|
||||
public bool HasLoop
|
||||
{
|
||||
get => this.bnsInfo.HasLoop == (byte) 1;
|
||||
set => this.bnsInfo.HasLoop = value ? (byte) 1 : (byte) 0;
|
||||
}
|
||||
|
||||
public uint LoopStart
|
||||
{
|
||||
get => this.bnsInfo.LoopStart;
|
||||
set => this.bnsInfo.LoopStart = value;
|
||||
}
|
||||
|
||||
public uint TotalSampleCount
|
||||
{
|
||||
get => this.bnsInfo.LoopEnd;
|
||||
set => this.bnsInfo.LoopEnd = value;
|
||||
}
|
||||
|
||||
public bool StereoToMono
|
||||
{
|
||||
get => this.toMono;
|
||||
set => this.toMono = value;
|
||||
}
|
||||
|
||||
public event EventHandler<ProgressChangedEventArgs> Progress;
|
||||
|
||||
protected BNS()
|
||||
{
|
||||
}
|
||||
|
||||
public BNS(string waveFile) => this.waveFile = File.ReadAllBytes(waveFile);
|
||||
|
||||
public BNS(string waveFile, bool loopFromWave)
|
||||
{
|
||||
this.waveFile = File.ReadAllBytes(waveFile);
|
||||
this.loopFromWave = loopFromWave;
|
||||
}
|
||||
|
||||
public BNS(byte[] waveFile) => this.waveFile = waveFile;
|
||||
|
||||
public BNS(byte[] waveFile, bool loopFromWave)
|
||||
{
|
||||
this.waveFile = waveFile;
|
||||
this.loopFromWave = loopFromWave;
|
||||
}
|
||||
|
||||
~BNS() => this.Dispose(false);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize((object) this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && !this.isDisposed)
|
||||
{
|
||||
this.bnsHeader = (BNS_Header) null;
|
||||
this.bnsInfo = (BNS_Info) null;
|
||||
this.bnsData = (BNS_Data) null;
|
||||
this.lSamples = (int[,]) null;
|
||||
this.rlSamples = (int[,]) null;
|
||||
this.tlSamples = (int[]) null;
|
||||
this.hbcDefTbl = (int[]) null;
|
||||
this.pHist1 = (int[]) null;
|
||||
this.pHist2 = (int[]) null;
|
||||
this.waveFile = (byte[]) null;
|
||||
}
|
||||
this.isDisposed = true;
|
||||
}
|
||||
|
||||
public static int GetBnsLength(byte[] bnsFile)
|
||||
{
|
||||
uint num = (uint) Shared.Swap(BitConverter.ToUInt16(bnsFile, 44));
|
||||
return (int) (Shared.Swap(BitConverter.ToUInt32(bnsFile, 52)) / num);
|
||||
}
|
||||
|
||||
public void Convert() => this.convert(this.waveFile, this.loopFromWave);
|
||||
|
||||
public byte[] ToByteArray() => this.ToMemoryStream().ToArray();
|
||||
|
||||
public MemoryStream ToMemoryStream()
|
||||
{
|
||||
if (!this.converted)
|
||||
this.convert(this.waveFile, this.loopFromWave);
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
try
|
||||
{
|
||||
this.bnsHeader.Write((Stream) memoryStream);
|
||||
this.bnsInfo.Write((Stream) memoryStream);
|
||||
this.bnsData.Write((Stream) memoryStream);
|
||||
return memoryStream;
|
||||
}
|
||||
catch
|
||||
{
|
||||
memoryStream.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void Save(string destionationFile)
|
||||
{
|
||||
if (File.Exists(destionationFile))
|
||||
File.Delete(destionationFile);
|
||||
using (FileStream fileStream = new FileStream(destionationFile, FileMode.Create))
|
||||
{
|
||||
byte[] array = this.ToMemoryStream().ToArray();
|
||||
fileStream.Write(array, 0, array.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetLoop(int loopStartSample)
|
||||
{
|
||||
this.bnsInfo.HasLoop = (byte) 1;
|
||||
this.bnsInfo.LoopStart = (uint) loopStartSample;
|
||||
}
|
||||
|
||||
private void convert(byte[] waveFile, bool loopFromWave)
|
||||
{
|
||||
Wave wave = new Wave(waveFile);
|
||||
int numLoops = wave.NumLoops;
|
||||
int loopStart = wave.LoopStart;
|
||||
this.bnsInfo.ChannelCount = (byte) wave.NumChannels;
|
||||
this.bnsInfo.SampleRate = (ushort) wave.SampleRate;
|
||||
if (this.bnsInfo.ChannelCount > (byte) 2 || this.bnsInfo.ChannelCount < (byte) 1)
|
||||
throw new Exception("Unsupported Amount of Channels!");
|
||||
if (wave.BitDepth != 16)
|
||||
throw new Exception("Only 16bit Wave files are supported!");
|
||||
this.bnsData.Data = wave.DataFormat == 1 ? this.Encode(wave.SampleData) : throw new Exception("The format of this Wave file is not supported!");
|
||||
if (this.bnsInfo.ChannelCount == (byte) 1)
|
||||
{
|
||||
this.bnsHeader.InfoLength = 96U;
|
||||
this.bnsHeader.DataOffset = 128U;
|
||||
this.bnsInfo.Size = 96U;
|
||||
this.bnsInfo.Channel1StartOffset = 28U;
|
||||
this.bnsInfo.Channel2StartOffset = 0U;
|
||||
this.bnsInfo.Channel1Start = 40U;
|
||||
this.bnsInfo.Coefficients1Offset = 0U;
|
||||
}
|
||||
this.bnsData.Size = (uint) (this.bnsData.Data.Length + 8);
|
||||
this.bnsHeader.DataLength = this.bnsData.Size;
|
||||
this.bnsHeader.FileSize = (uint) this.bnsHeader.Size + this.bnsInfo.Size + this.bnsData.Size;
|
||||
if (loopFromWave && numLoops == 1 && loopStart != -1)
|
||||
{
|
||||
this.bnsInfo.LoopStart = (uint) loopStart;
|
||||
this.bnsInfo.HasLoop = (byte) 1;
|
||||
}
|
||||
this.bnsInfo.LoopEnd = (uint) this.tempSampleCount;
|
||||
for (int index = 0; index < 16; ++index)
|
||||
{
|
||||
this.bnsInfo.Coefficients1[index] = this.defTbl[index];
|
||||
if (this.bnsInfo.ChannelCount == (byte) 2)
|
||||
this.bnsInfo.Coefficients2[index] = this.defTbl[index];
|
||||
}
|
||||
this.converted = true;
|
||||
}
|
||||
|
||||
private byte[] Encode(byte[] inputFrames)
|
||||
{
|
||||
int[] inputBuffer = new int[14];
|
||||
this.tempSampleCount = inputFrames.Length / (this.bnsInfo.ChannelCount == (byte) 2 ? 4 : 2);
|
||||
int num1 = inputFrames.Length / (this.bnsInfo.ChannelCount == (byte) 2 ? 4 : 2) % 14;
|
||||
Array.Resize<byte>(ref inputFrames, inputFrames.Length + (14 - num1) * (this.bnsInfo.ChannelCount == (byte) 2 ? 4 : 2));
|
||||
int num2 = inputFrames.Length / (this.bnsInfo.ChannelCount == (byte) 2 ? 4 : 2);
|
||||
int num3 = (num2 + 13) / 14;
|
||||
List<int> intList1 = new List<int>();
|
||||
List<int> intList2 = new List<int>();
|
||||
int startIndex = 0;
|
||||
if (this.toMono && this.bnsInfo.ChannelCount == (byte) 2)
|
||||
this.bnsInfo.ChannelCount = (byte) 1;
|
||||
else if (this.toMono)
|
||||
this.toMono = false;
|
||||
for (int index = 0; index < num2; ++index)
|
||||
{
|
||||
intList1.Add((int) BitConverter.ToInt16(inputFrames, startIndex));
|
||||
startIndex += 2;
|
||||
if (this.bnsInfo.ChannelCount == (byte) 2 || this.toMono)
|
||||
{
|
||||
intList2.Add((int) BitConverter.ToInt16(inputFrames, startIndex));
|
||||
startIndex += 2;
|
||||
}
|
||||
}
|
||||
byte[] numArray1 = new byte[this.bnsInfo.ChannelCount == (byte) 2 ? num3 * 16 : num3 * 8];
|
||||
int num4 = 0;
|
||||
int num5 = num3 * 8;
|
||||
this.bnsInfo.Channel2Start = this.bnsInfo.ChannelCount == (byte) 2 ? (uint) num5 : 0U;
|
||||
int[] array1 = intList1.ToArray();
|
||||
int[] array2 = intList2.ToArray();
|
||||
for (int index1 = 0; index1 < num3; ++index1)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (index1 % (num3 / 100) != 0)
|
||||
{
|
||||
if (index1 + 1 != num3)
|
||||
goto label_14;
|
||||
}
|
||||
this.ChangeProgress((index1 + 1) * 100 / num3);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
label_14:
|
||||
for (int index2 = 0; index2 < 14; ++index2)
|
||||
inputBuffer[index2] = array1[index1 * 14 + index2];
|
||||
byte[] numArray2 = this.RepackAdpcm(0, this.defTbl, inputBuffer);
|
||||
for (int index2 = 0; index2 < 8; ++index2)
|
||||
numArray1[num4 + index2] = numArray2[index2];
|
||||
num4 += 8;
|
||||
if (this.bnsInfo.ChannelCount == (byte) 2)
|
||||
{
|
||||
for (int index2 = 0; index2 < 14; ++index2)
|
||||
inputBuffer[index2] = array2[index1 * 14 + index2];
|
||||
byte[] numArray3 = this.RepackAdpcm(1, this.defTbl, inputBuffer);
|
||||
for (int index2 = 0; index2 < 8; ++index2)
|
||||
numArray1[num5 + index2] = numArray3[index2];
|
||||
num5 += 8;
|
||||
}
|
||||
}
|
||||
this.bnsInfo.LoopEnd = (uint) (num3 * 7);
|
||||
return numArray1;
|
||||
}
|
||||
|
||||
private byte[] RepackAdpcm(int index, int[] table, int[] inputBuffer)
|
||||
{
|
||||
byte[] numArray1 = new byte[8];
|
||||
int[] numArray2 = new int[2];
|
||||
double num1 = 999999999.0;
|
||||
for (int tableIndex = 0; tableIndex < 8; ++tableIndex)
|
||||
{
|
||||
double outError;
|
||||
byte[] numArray3 = this.CompressAdpcm(index, table, tableIndex, inputBuffer, out outError);
|
||||
if (outError < num1)
|
||||
{
|
||||
num1 = outError;
|
||||
for (int index1 = 0; index1 < 8; ++index1)
|
||||
numArray1[index1] = numArray3[index1];
|
||||
for (int index1 = 0; index1 < 2; ++index1)
|
||||
numArray2[index1] = this.tlSamples[index1];
|
||||
}
|
||||
}
|
||||
for (int index1 = 0; index1 < 2; ++index1)
|
||||
{
|
||||
int[,] rlSamples = this.rlSamples;
|
||||
int num2 = index1;
|
||||
int index2 = index;
|
||||
int index3 = num2;
|
||||
int num3 = numArray2[index1];
|
||||
rlSamples[index2, index3] = num3;
|
||||
}
|
||||
return numArray1;
|
||||
}
|
||||
|
||||
private byte[] CompressAdpcm(
|
||||
int index,
|
||||
int[] table,
|
||||
int tableIndex,
|
||||
int[] inputBuffer,
|
||||
out double outError)
|
||||
{
|
||||
byte[] numArray = new byte[8];
|
||||
int num1 = 0;
|
||||
int num2 = table[2 * tableIndex];
|
||||
int num3 = table[2 * tableIndex + 1];
|
||||
int stdExponent = this.DetermineStdExponent(index, table, tableIndex, inputBuffer);
|
||||
while (stdExponent <= 15)
|
||||
{
|
||||
bool flag = false;
|
||||
num1 = 0;
|
||||
numArray[0] = (byte) (stdExponent | tableIndex << 4);
|
||||
for (int index1 = 0; index1 < 2; ++index1)
|
||||
this.tlSamples[index1] = this.rlSamples[index, index1];
|
||||
int num4 = 0;
|
||||
for (int index1 = 0; index1 < 14; ++index1)
|
||||
{
|
||||
int num5 = this.tlSamples[1] * num2 + this.tlSamples[0] * num3 >> 11;
|
||||
int input1 = inputBuffer[index1] - num5 >> stdExponent;
|
||||
if (input1 <= 7 && input1 >= -8)
|
||||
{
|
||||
int num6 = this.Clamp(input1, -8, 7);
|
||||
numArray[index1 / 2 + 1] = (index1 & 1) == 0 ? (byte) (num6 << 4) : (byte) ((uint) numArray[index1 / 2 + 1] | (uint) (num6 & 15));
|
||||
int input2 = num5 + (num6 << stdExponent);
|
||||
this.tlSamples[0] = this.tlSamples[1];
|
||||
this.tlSamples[1] = this.Clamp(input2, (int) short.MinValue, (int) short.MaxValue);
|
||||
num1 += (int) Math.Pow((double) (this.tlSamples[1] - inputBuffer[index1]), 2.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
++stdExponent;
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
num4 = 14;
|
||||
if (num4 == 14)
|
||||
break;
|
||||
}
|
||||
outError = (double) num1;
|
||||
return numArray;
|
||||
}
|
||||
|
||||
private int DetermineStdExponent(int index, int[] table, int tableIndex, int[] inputBuffer)
|
||||
{
|
||||
int[] numArray = new int[2];
|
||||
int num1 = 0;
|
||||
int num2 = table[2 * tableIndex];
|
||||
int num3 = table[2 * tableIndex + 1];
|
||||
for (int index1 = 0; index1 < 2; ++index1)
|
||||
numArray[index1] = this.rlSamples[index, index1];
|
||||
for (int index1 = 0; index1 < 14; ++index1)
|
||||
{
|
||||
int num4 = numArray[1] * num2 + numArray[0] * num3 >> 11;
|
||||
int num5 = inputBuffer[index1] - num4;
|
||||
if (num5 > num1)
|
||||
num1 = num5;
|
||||
numArray[0] = numArray[1];
|
||||
numArray[1] = inputBuffer[index1];
|
||||
}
|
||||
return this.FindExponent((double) num1);
|
||||
}
|
||||
|
||||
private int FindExponent(double residual)
|
||||
{
|
||||
int num = 0;
|
||||
for (; residual > 7.5 || residual < -8.5; residual /= 2.0)
|
||||
++num;
|
||||
return num;
|
||||
}
|
||||
|
||||
private int Clamp(int input, int min, int max)
|
||||
{
|
||||
if (input < min)
|
||||
return min;
|
||||
return input > max ? max : input;
|
||||
}
|
||||
|
||||
private void ChangeProgress(int progressPercentage)
|
||||
{
|
||||
EventHandler<ProgressChangedEventArgs> progress = this.Progress;
|
||||
if (progress == null)
|
||||
return;
|
||||
progress(new object(), new ProgressChangedEventArgs(progressPercentage, new object()));
|
||||
}
|
||||
|
||||
public static Wave BnsToWave(Stream inputFile)
|
||||
{
|
||||
BNS bns = new BNS();
|
||||
byte[] samples = bns.Read(inputFile);
|
||||
Wave wave = new Wave((int) bns.bnsInfo.ChannelCount, 16, (int) bns.bnsInfo.SampleRate, samples);
|
||||
if (bns.bnsInfo.HasLoop == (byte) 1)
|
||||
wave.AddLoop((int) bns.bnsInfo.LoopStart);
|
||||
return wave;
|
||||
}
|
||||
|
||||
public static Wave BnsToWave(string pathToFile)
|
||||
{
|
||||
BNS bns = new BNS();
|
||||
byte[] samples = (byte[]) null;
|
||||
using (FileStream fileStream = new FileStream(pathToFile, FileMode.Open))
|
||||
samples = bns.Read((Stream) fileStream);
|
||||
Wave wave = new Wave((int) bns.bnsInfo.ChannelCount, 16, (int) bns.bnsInfo.SampleRate, samples);
|
||||
if (bns.bnsInfo.HasLoop == (byte) 1)
|
||||
wave.AddLoop((int) bns.bnsInfo.LoopStart);
|
||||
return wave;
|
||||
}
|
||||
|
||||
public static Wave BnsToWave(byte[] bnsFile)
|
||||
{
|
||||
BNS bns = new BNS();
|
||||
byte[] samples = (byte[]) null;
|
||||
using (MemoryStream memoryStream = new MemoryStream(bnsFile))
|
||||
samples = bns.Read((Stream) memoryStream);
|
||||
Wave wave = new Wave((int) bns.bnsInfo.ChannelCount, 16, (int) bns.bnsInfo.SampleRate, samples);
|
||||
if (bns.bnsInfo.HasLoop == (byte) 1)
|
||||
wave.AddLoop((int) bns.bnsInfo.LoopStart);
|
||||
return wave;
|
||||
}
|
||||
|
||||
private byte[] Read(Stream input)
|
||||
{
|
||||
input.Seek(0L, SeekOrigin.Begin);
|
||||
this.bnsHeader.Read(input);
|
||||
this.bnsInfo.Read(input);
|
||||
this.bnsData.Read(input);
|
||||
return this.Decode();
|
||||
}
|
||||
|
||||
private byte[] Decode()
|
||||
{
|
||||
List<byte> byteList = new List<byte>();
|
||||
int num = this.bnsData.Data.Length / (this.bnsInfo.ChannelCount == (byte) 2 ? 16 : 8);
|
||||
int dataOffset1 = 0;
|
||||
int dataOffset2 = num * 8;
|
||||
byte[] numArray1 = new byte[0];
|
||||
byte[] numArray2 = new byte[0];
|
||||
for (int index1 = 0; index1 < num; ++index1)
|
||||
{
|
||||
byte[] numArray3 = this.DecodeAdpcm(0, dataOffset1);
|
||||
if (this.bnsInfo.ChannelCount == (byte) 2)
|
||||
numArray2 = this.DecodeAdpcm(1, dataOffset2);
|
||||
for (int index2 = 0; index2 < 14; ++index2)
|
||||
{
|
||||
byteList.Add(numArray3[index2 * 2]);
|
||||
byteList.Add(numArray3[index2 * 2 + 1]);
|
||||
if (this.bnsInfo.ChannelCount == (byte) 2)
|
||||
{
|
||||
byteList.Add(numArray2[index2 * 2]);
|
||||
byteList.Add(numArray2[index2 * 2 + 1]);
|
||||
}
|
||||
}
|
||||
dataOffset1 += 8;
|
||||
if (this.bnsInfo.ChannelCount == (byte) 2)
|
||||
dataOffset2 += 8;
|
||||
}
|
||||
return byteList.ToArray();
|
||||
}
|
||||
|
||||
private byte[] DecodeAdpcm(int channel, int dataOffset)
|
||||
{
|
||||
byte[] numArray = new byte[28];
|
||||
int num1 = (int) this.bnsData.Data[dataOffset] >> 4 & 15;
|
||||
int num2 = 1 << ((int) this.bnsData.Data[dataOffset] & 15);
|
||||
int num3 = this.pHist1[channel];
|
||||
int num4 = this.pHist2[channel];
|
||||
int num5 = channel == 0 ? this.bnsInfo.Coefficients1[num1 * 2] : this.bnsInfo.Coefficients2[num1 * 2];
|
||||
int num6 = channel == 0 ? this.bnsInfo.Coefficients1[num1 * 2 + 1] : this.bnsInfo.Coefficients2[num1 * 2 + 1];
|
||||
for (int index = 0; index < 14; ++index)
|
||||
{
|
||||
short num7 = (short) this.bnsData.Data[dataOffset + (index / 2 + 1)];
|
||||
int num8 = (index & 1) != 0 ? (int) num7 & 15 : (int) num7 >> 4;
|
||||
if (num8 >= 8)
|
||||
num8 -= 16;
|
||||
int num9 = this.Clamp((num2 * num8 << 11) + (num5 * num3 + num6 * num4) + 1024 >> 11, (int) short.MinValue, (int) short.MaxValue);
|
||||
numArray[index * 2] = (byte) ((uint) (short) num9 & (uint) byte.MaxValue);
|
||||
numArray[index * 2 + 1] = (byte) ((uint) (short) num9 >> 8);
|
||||
num4 = num3;
|
||||
num3 = num9;
|
||||
}
|
||||
this.pHist1[channel] = num3;
|
||||
this.pHist2[channel] = num4;
|
||||
return numArray;
|
||||
}
|
||||
}
|
||||
}
|
51
BNS_Data.cs
Normal file
51
BNS_Data.cs
Normal file
|
@ -0,0 +1,51 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.BNS_Data
|
||||
// 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
|
||||
{
|
||||
internal class BNS_Data
|
||||
{
|
||||
private byte[] magic = new byte[4]
|
||||
{
|
||||
(byte) 68,
|
||||
(byte) 65,
|
||||
(byte) 84,
|
||||
(byte) 65
|
||||
};
|
||||
private uint size = 315392;
|
||||
private byte[] data;
|
||||
|
||||
public uint Size
|
||||
{
|
||||
get => this.size;
|
||||
set => this.size = value;
|
||||
}
|
||||
|
||||
public byte[] Data
|
||||
{
|
||||
get => this.data;
|
||||
set => this.data = value;
|
||||
}
|
||||
|
||||
public void Write(Stream outStream)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(Shared.Swap(this.size));
|
||||
outStream.Write(this.magic, 0, this.magic.Length);
|
||||
outStream.Write(bytes, 0, bytes.Length);
|
||||
outStream.Write(this.data, 0, this.data.Length);
|
||||
}
|
||||
|
||||
public void Read(Stream input)
|
||||
{
|
||||
BinaryReader binaryReader = new BinaryReader(input);
|
||||
this.size = Shared.CompareByteArrays(this.magic, binaryReader.ReadBytes(4)) ? Shared.Swap(binaryReader.ReadUInt32()) : throw new Exception("This is not a valid BNS audfo file!");
|
||||
this.data = binaryReader.ReadBytes((int) this.size - 8);
|
||||
}
|
||||
}
|
||||
}
|
108
BNS_Header.cs
Normal file
108
BNS_Header.cs
Normal file
|
@ -0,0 +1,108 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.BNS_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
|
||||
{
|
||||
internal class BNS_Header
|
||||
{
|
||||
private byte[] magic = new byte[4]
|
||||
{
|
||||
(byte) 66,
|
||||
(byte) 78,
|
||||
(byte) 83,
|
||||
(byte) 32
|
||||
};
|
||||
private uint flags = 4278124800;
|
||||
private uint fileSize = 315584;
|
||||
private ushort size = 32;
|
||||
private ushort chunkCount = 2;
|
||||
private uint infoOffset = 32;
|
||||
private uint infoLength = 160;
|
||||
private uint dataOffset = 192;
|
||||
private uint dataLength = 315392;
|
||||
|
||||
public uint DataOffset
|
||||
{
|
||||
get => this.dataOffset;
|
||||
set => this.dataOffset = value;
|
||||
}
|
||||
|
||||
public uint InfoLength
|
||||
{
|
||||
get => this.infoLength;
|
||||
set => this.infoLength = value;
|
||||
}
|
||||
|
||||
public ushort Size
|
||||
{
|
||||
get => this.size;
|
||||
set => this.size = value;
|
||||
}
|
||||
|
||||
public uint DataLength
|
||||
{
|
||||
get => this.dataLength;
|
||||
set => this.dataLength = value;
|
||||
}
|
||||
|
||||
public uint FileSize
|
||||
{
|
||||
get => this.fileSize;
|
||||
set => this.fileSize = value;
|
||||
}
|
||||
|
||||
public void Write(Stream outStream)
|
||||
{
|
||||
outStream.Write(this.magic, 0, this.magic.Length);
|
||||
byte[] bytes1 = BitConverter.GetBytes(this.flags);
|
||||
Array.Reverse((Array) bytes1);
|
||||
outStream.Write(bytes1, 0, bytes1.Length);
|
||||
byte[] bytes2 = BitConverter.GetBytes(this.fileSize);
|
||||
Array.Reverse((Array) bytes2);
|
||||
outStream.Write(bytes2, 0, bytes2.Length);
|
||||
byte[] bytes3 = BitConverter.GetBytes(this.size);
|
||||
Array.Reverse((Array) bytes3);
|
||||
outStream.Write(bytes3, 0, bytes3.Length);
|
||||
byte[] bytes4 = BitConverter.GetBytes(this.chunkCount);
|
||||
Array.Reverse((Array) bytes4);
|
||||
outStream.Write(bytes4, 0, bytes4.Length);
|
||||
byte[] bytes5 = BitConverter.GetBytes(this.infoOffset);
|
||||
Array.Reverse((Array) bytes5);
|
||||
outStream.Write(bytes5, 0, bytes5.Length);
|
||||
byte[] bytes6 = BitConverter.GetBytes(this.infoLength);
|
||||
Array.Reverse((Array) bytes6);
|
||||
outStream.Write(bytes6, 0, bytes6.Length);
|
||||
byte[] bytes7 = BitConverter.GetBytes(this.dataOffset);
|
||||
Array.Reverse((Array) bytes7);
|
||||
outStream.Write(bytes7, 0, bytes7.Length);
|
||||
byte[] bytes8 = BitConverter.GetBytes(this.dataLength);
|
||||
Array.Reverse((Array) bytes8);
|
||||
outStream.Write(bytes8, 0, bytes8.Length);
|
||||
}
|
||||
|
||||
public void Read(Stream input)
|
||||
{
|
||||
BinaryReader binaryReader = new BinaryReader(input);
|
||||
if (!Shared.CompareByteArrays(this.magic, binaryReader.ReadBytes(4)))
|
||||
{
|
||||
binaryReader.BaseStream.Seek(28L, SeekOrigin.Current);
|
||||
if (!Shared.CompareByteArrays(this.magic, binaryReader.ReadBytes(4)))
|
||||
throw new Exception("This is not a valid BNS audfo file!");
|
||||
}
|
||||
this.flags = Shared.Swap(binaryReader.ReadUInt32());
|
||||
this.fileSize = Shared.Swap(binaryReader.ReadUInt32());
|
||||
this.size = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.chunkCount = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.infoOffset = Shared.Swap(binaryReader.ReadUInt32());
|
||||
this.infoLength = Shared.Swap(binaryReader.ReadUInt32());
|
||||
this.dataOffset = Shared.Swap(binaryReader.ReadUInt32());
|
||||
this.dataLength = Shared.Swap(binaryReader.ReadUInt32());
|
||||
}
|
||||
}
|
||||
}
|
351
BNS_Info.cs
Normal file
351
BNS_Info.cs
Normal file
|
@ -0,0 +1,351 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.BNS_Info
|
||||
// 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
|
||||
{
|
||||
internal class BNS_Info
|
||||
{
|
||||
private byte[] magic = new byte[4]
|
||||
{
|
||||
(byte) 73,
|
||||
(byte) 78,
|
||||
(byte) 70,
|
||||
(byte) 79
|
||||
};
|
||||
private uint size = 160;
|
||||
private byte codec;
|
||||
private byte hasLoop;
|
||||
private byte channelCount = 2;
|
||||
private byte zero;
|
||||
private ushort sampleRate = 44100;
|
||||
private ushort pad0;
|
||||
private uint loopStart;
|
||||
private uint loopEnd;
|
||||
private uint offsetToChannelStart = 24;
|
||||
private uint pad1;
|
||||
private uint channel1StartOffset = 32;
|
||||
private uint channel2StartOffset = 44;
|
||||
private uint channel1Start;
|
||||
private uint coefficients1Offset = 56;
|
||||
private uint pad2;
|
||||
private uint channel2Start;
|
||||
private uint coefficients2Offset = 104;
|
||||
private uint pad3;
|
||||
private int[] coefficients1 = new int[16];
|
||||
private ushort channel1Gain;
|
||||
private ushort channel1PredictiveScale;
|
||||
private ushort channel1PreviousValue;
|
||||
private ushort channel1NextPreviousValue;
|
||||
private ushort channel1LoopPredictiveScale;
|
||||
private ushort channel1LoopPreviousValue;
|
||||
private ushort channel1LoopNextPreviousValue;
|
||||
private ushort channel1LoopPadding;
|
||||
private int[] coefficients2 = new int[16];
|
||||
private ushort channel2Gain;
|
||||
private ushort channel2PredictiveScale;
|
||||
private ushort channel2PreviousValue;
|
||||
private ushort channel2NextPreviousValue;
|
||||
private ushort channel2LoopPredictiveScale;
|
||||
private ushort channel2LoopPreviousValue;
|
||||
private ushort channel2LoopNextPreviousValue;
|
||||
private ushort channel2LoopPadding;
|
||||
|
||||
public byte HasLoop
|
||||
{
|
||||
get => this.hasLoop;
|
||||
set => this.hasLoop = value;
|
||||
}
|
||||
|
||||
public uint Coefficients1Offset
|
||||
{
|
||||
get => this.coefficients1Offset;
|
||||
set => this.coefficients1Offset = value;
|
||||
}
|
||||
|
||||
public uint Channel1StartOffset
|
||||
{
|
||||
get => this.channel1StartOffset;
|
||||
set => this.channel1StartOffset = value;
|
||||
}
|
||||
|
||||
public uint Channel2StartOffset
|
||||
{
|
||||
get => this.channel2StartOffset;
|
||||
set => this.channel2StartOffset = value;
|
||||
}
|
||||
|
||||
public uint Size
|
||||
{
|
||||
get => this.size;
|
||||
set => this.size = value;
|
||||
}
|
||||
|
||||
public ushort SampleRate
|
||||
{
|
||||
get => this.sampleRate;
|
||||
set => this.sampleRate = value;
|
||||
}
|
||||
|
||||
public byte ChannelCount
|
||||
{
|
||||
get => this.channelCount;
|
||||
set => this.channelCount = value;
|
||||
}
|
||||
|
||||
public uint Channel1Start
|
||||
{
|
||||
get => this.channel1Start;
|
||||
set => this.channel1Start = value;
|
||||
}
|
||||
|
||||
public uint Channel2Start
|
||||
{
|
||||
get => this.channel2Start;
|
||||
set => this.channel2Start = value;
|
||||
}
|
||||
|
||||
public uint LoopStart
|
||||
{
|
||||
get => this.loopStart;
|
||||
set => this.loopStart = value;
|
||||
}
|
||||
|
||||
public uint LoopEnd
|
||||
{
|
||||
get => this.loopEnd;
|
||||
set => this.loopEnd = value;
|
||||
}
|
||||
|
||||
public int[] Coefficients1
|
||||
{
|
||||
get => this.coefficients1;
|
||||
set => this.coefficients1 = value;
|
||||
}
|
||||
|
||||
public int[] Coefficients2
|
||||
{
|
||||
get => this.coefficients2;
|
||||
set => this.coefficients2 = value;
|
||||
}
|
||||
|
||||
public void Write(Stream outStream)
|
||||
{
|
||||
outStream.Write(this.magic, 0, this.magic.Length);
|
||||
byte[] bytes1 = BitConverter.GetBytes(this.size);
|
||||
Array.Reverse((Array) bytes1);
|
||||
outStream.Write(bytes1, 0, bytes1.Length);
|
||||
outStream.WriteByte(this.codec);
|
||||
outStream.WriteByte(this.hasLoop);
|
||||
outStream.WriteByte(this.channelCount);
|
||||
outStream.WriteByte(this.zero);
|
||||
byte[] bytes2 = BitConverter.GetBytes(this.sampleRate);
|
||||
Array.Reverse((Array) bytes2);
|
||||
outStream.Write(bytes2, 0, bytes2.Length);
|
||||
byte[] bytes3 = BitConverter.GetBytes(this.pad0);
|
||||
Array.Reverse((Array) bytes3);
|
||||
outStream.Write(bytes3, 0, bytes3.Length);
|
||||
byte[] bytes4 = BitConverter.GetBytes(this.loopStart);
|
||||
Array.Reverse((Array) bytes4);
|
||||
outStream.Write(bytes4, 0, bytes4.Length);
|
||||
byte[] bytes5 = BitConverter.GetBytes(this.loopEnd);
|
||||
Array.Reverse((Array) bytes5);
|
||||
outStream.Write(bytes5, 0, bytes5.Length);
|
||||
byte[] bytes6 = BitConverter.GetBytes(this.offsetToChannelStart);
|
||||
Array.Reverse((Array) bytes6);
|
||||
outStream.Write(bytes6, 0, bytes6.Length);
|
||||
byte[] bytes7 = BitConverter.GetBytes(this.pad1);
|
||||
Array.Reverse((Array) bytes7);
|
||||
outStream.Write(bytes7, 0, bytes7.Length);
|
||||
byte[] bytes8 = BitConverter.GetBytes(this.channel1StartOffset);
|
||||
Array.Reverse((Array) bytes8);
|
||||
outStream.Write(bytes8, 0, bytes8.Length);
|
||||
byte[] bytes9 = BitConverter.GetBytes(this.channel2StartOffset);
|
||||
Array.Reverse((Array) bytes9);
|
||||
outStream.Write(bytes9, 0, bytes9.Length);
|
||||
byte[] bytes10 = BitConverter.GetBytes(this.channel1Start);
|
||||
Array.Reverse((Array) bytes10);
|
||||
outStream.Write(bytes10, 0, bytes10.Length);
|
||||
byte[] bytes11 = BitConverter.GetBytes(this.coefficients1Offset);
|
||||
Array.Reverse((Array) bytes11);
|
||||
outStream.Write(bytes11, 0, bytes11.Length);
|
||||
if (this.channelCount == (byte) 2)
|
||||
{
|
||||
byte[] bytes12 = BitConverter.GetBytes(this.pad2);
|
||||
Array.Reverse((Array) bytes12);
|
||||
outStream.Write(bytes12, 0, bytes12.Length);
|
||||
byte[] bytes13 = BitConverter.GetBytes(this.channel2Start);
|
||||
Array.Reverse((Array) bytes13);
|
||||
outStream.Write(bytes13, 0, bytes13.Length);
|
||||
byte[] bytes14 = BitConverter.GetBytes(this.coefficients2Offset);
|
||||
Array.Reverse((Array) bytes14);
|
||||
outStream.Write(bytes14, 0, bytes14.Length);
|
||||
byte[] bytes15 = BitConverter.GetBytes(this.pad3);
|
||||
Array.Reverse((Array) bytes15);
|
||||
outStream.Write(bytes15, 0, bytes15.Length);
|
||||
foreach (int num in this.coefficients1)
|
||||
{
|
||||
byte[] bytes16 = BitConverter.GetBytes(num);
|
||||
Array.Reverse((Array) bytes16);
|
||||
outStream.Write(bytes16, 2, bytes16.Length - 2);
|
||||
}
|
||||
byte[] bytes17 = BitConverter.GetBytes(this.channel1Gain);
|
||||
Array.Reverse((Array) bytes17);
|
||||
outStream.Write(bytes17, 0, bytes17.Length);
|
||||
byte[] bytes18 = BitConverter.GetBytes(this.channel1PredictiveScale);
|
||||
Array.Reverse((Array) bytes18);
|
||||
outStream.Write(bytes18, 0, bytes18.Length);
|
||||
byte[] bytes19 = BitConverter.GetBytes(this.channel1PreviousValue);
|
||||
Array.Reverse((Array) bytes19);
|
||||
outStream.Write(bytes19, 0, bytes19.Length);
|
||||
byte[] bytes20 = BitConverter.GetBytes(this.channel1NextPreviousValue);
|
||||
Array.Reverse((Array) bytes20);
|
||||
outStream.Write(bytes20, 0, bytes20.Length);
|
||||
byte[] bytes21 = BitConverter.GetBytes(this.channel1LoopPredictiveScale);
|
||||
Array.Reverse((Array) bytes21);
|
||||
outStream.Write(bytes21, 0, bytes21.Length);
|
||||
byte[] bytes22 = BitConverter.GetBytes(this.channel1LoopPreviousValue);
|
||||
Array.Reverse((Array) bytes22);
|
||||
outStream.Write(bytes22, 0, bytes22.Length);
|
||||
byte[] bytes23 = BitConverter.GetBytes(this.channel1LoopNextPreviousValue);
|
||||
Array.Reverse((Array) bytes23);
|
||||
outStream.Write(bytes23, 0, bytes23.Length);
|
||||
byte[] bytes24 = BitConverter.GetBytes(this.channel1LoopPadding);
|
||||
Array.Reverse((Array) bytes24);
|
||||
outStream.Write(bytes24, 0, bytes24.Length);
|
||||
foreach (int num in this.coefficients2)
|
||||
{
|
||||
byte[] bytes16 = BitConverter.GetBytes(num);
|
||||
Array.Reverse((Array) bytes16);
|
||||
outStream.Write(bytes16, 2, bytes16.Length - 2);
|
||||
}
|
||||
byte[] bytes25 = BitConverter.GetBytes(this.channel2Gain);
|
||||
Array.Reverse((Array) bytes25);
|
||||
outStream.Write(bytes25, 0, bytes25.Length);
|
||||
byte[] bytes26 = BitConverter.GetBytes(this.channel2PredictiveScale);
|
||||
Array.Reverse((Array) bytes26);
|
||||
outStream.Write(bytes26, 0, bytes26.Length);
|
||||
byte[] bytes27 = BitConverter.GetBytes(this.channel2PreviousValue);
|
||||
Array.Reverse((Array) bytes27);
|
||||
outStream.Write(bytes27, 0, bytes27.Length);
|
||||
byte[] bytes28 = BitConverter.GetBytes(this.channel2NextPreviousValue);
|
||||
Array.Reverse((Array) bytes28);
|
||||
outStream.Write(bytes28, 0, bytes28.Length);
|
||||
byte[] bytes29 = BitConverter.GetBytes(this.channel2LoopPredictiveScale);
|
||||
Array.Reverse((Array) bytes29);
|
||||
outStream.Write(bytes29, 0, bytes29.Length);
|
||||
byte[] bytes30 = BitConverter.GetBytes(this.channel2LoopPreviousValue);
|
||||
Array.Reverse((Array) bytes30);
|
||||
outStream.Write(bytes30, 0, bytes30.Length);
|
||||
byte[] bytes31 = BitConverter.GetBytes(this.channel2LoopNextPreviousValue);
|
||||
Array.Reverse((Array) bytes31);
|
||||
outStream.Write(bytes31, 0, bytes31.Length);
|
||||
byte[] bytes32 = BitConverter.GetBytes(this.channel2LoopPadding);
|
||||
Array.Reverse((Array) bytes32);
|
||||
outStream.Write(bytes32, 0, bytes32.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.channelCount != (byte) 1)
|
||||
return;
|
||||
foreach (int num in this.coefficients1)
|
||||
{
|
||||
byte[] bytes12 = BitConverter.GetBytes(num);
|
||||
Array.Reverse((Array) bytes12);
|
||||
outStream.Write(bytes12, 2, bytes12.Length - 2);
|
||||
}
|
||||
byte[] bytes13 = BitConverter.GetBytes(this.channel1Gain);
|
||||
Array.Reverse((Array) bytes13);
|
||||
outStream.Write(bytes13, 0, bytes13.Length);
|
||||
byte[] bytes14 = BitConverter.GetBytes(this.channel1PredictiveScale);
|
||||
Array.Reverse((Array) bytes14);
|
||||
outStream.Write(bytes14, 0, bytes14.Length);
|
||||
byte[] bytes15 = BitConverter.GetBytes(this.channel1PreviousValue);
|
||||
Array.Reverse((Array) bytes15);
|
||||
outStream.Write(bytes15, 0, bytes15.Length);
|
||||
byte[] bytes16 = BitConverter.GetBytes(this.channel1NextPreviousValue);
|
||||
Array.Reverse((Array) bytes16);
|
||||
outStream.Write(bytes16, 0, bytes16.Length);
|
||||
byte[] bytes17 = BitConverter.GetBytes(this.channel1LoopPredictiveScale);
|
||||
Array.Reverse((Array) bytes17);
|
||||
outStream.Write(bytes17, 0, bytes17.Length);
|
||||
byte[] bytes18 = BitConverter.GetBytes(this.channel1LoopPreviousValue);
|
||||
Array.Reverse((Array) bytes18);
|
||||
outStream.Write(bytes18, 0, bytes18.Length);
|
||||
byte[] bytes19 = BitConverter.GetBytes(this.channel1LoopNextPreviousValue);
|
||||
Array.Reverse((Array) bytes19);
|
||||
outStream.Write(bytes19, 0, bytes19.Length);
|
||||
byte[] bytes20 = BitConverter.GetBytes(this.channel1LoopPadding);
|
||||
Array.Reverse((Array) bytes20);
|
||||
outStream.Write(bytes20, 0, bytes20.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(Stream input)
|
||||
{
|
||||
BinaryReader binaryReader = new BinaryReader(input);
|
||||
this.size = Shared.CompareByteArrays(this.magic, binaryReader.ReadBytes(4)) ? Shared.Swap(binaryReader.ReadUInt32()) : throw new Exception("This is not a valid BNS audfo file!");
|
||||
this.codec = binaryReader.ReadByte();
|
||||
this.hasLoop = binaryReader.ReadByte();
|
||||
this.channelCount = binaryReader.ReadByte();
|
||||
this.zero = binaryReader.ReadByte();
|
||||
this.sampleRate = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.pad0 = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.loopStart = Shared.Swap(binaryReader.ReadUInt32());
|
||||
this.loopEnd = Shared.Swap(binaryReader.ReadUInt32());
|
||||
this.offsetToChannelStart = Shared.Swap(binaryReader.ReadUInt32());
|
||||
this.pad1 = Shared.Swap(binaryReader.ReadUInt32());
|
||||
this.channel1StartOffset = Shared.Swap(binaryReader.ReadUInt32());
|
||||
this.channel2StartOffset = Shared.Swap(binaryReader.ReadUInt32());
|
||||
this.channel1Start = Shared.Swap(binaryReader.ReadUInt32());
|
||||
this.coefficients1Offset = Shared.Swap(binaryReader.ReadUInt32());
|
||||
if (this.channelCount == (byte) 2)
|
||||
{
|
||||
this.pad2 = Shared.Swap(binaryReader.ReadUInt32());
|
||||
this.channel2Start = Shared.Swap(binaryReader.ReadUInt32());
|
||||
this.coefficients2Offset = Shared.Swap(binaryReader.ReadUInt32());
|
||||
this.pad3 = Shared.Swap(binaryReader.ReadUInt32());
|
||||
for (int index = 0; index < 16; ++index)
|
||||
this.coefficients1[index] = (int) (short) Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel1Gain = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel1PredictiveScale = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel1PreviousValue = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel1NextPreviousValue = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel1LoopPredictiveScale = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel1LoopPreviousValue = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel1LoopNextPreviousValue = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel1LoopPadding = Shared.Swap(binaryReader.ReadUInt16());
|
||||
for (int index = 0; index < 16; ++index)
|
||||
this.coefficients2[index] = (int) (short) Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel2Gain = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel2PredictiveScale = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel2PreviousValue = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel2NextPreviousValue = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel2LoopPredictiveScale = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel2LoopPreviousValue = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel2LoopNextPreviousValue = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel2LoopPadding = Shared.Swap(binaryReader.ReadUInt16());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.channelCount != (byte) 1)
|
||||
return;
|
||||
for (int index = 0; index < 16; ++index)
|
||||
this.coefficients1[index] = (int) (short) Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel1Gain = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel1PredictiveScale = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel1PreviousValue = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel1NextPreviousValue = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel1LoopPredictiveScale = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel1LoopPreviousValue = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel1LoopNextPreviousValue = Shared.Swap(binaryReader.ReadUInt16());
|
||||
this.channel1LoopPadding = Shared.Swap(binaryReader.ReadUInt16());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
66
Brlan.cs
Normal file
66
Brlan.cs
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.Brlan
|
||||
// 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.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace libWiiSharp
|
||||
{
|
||||
public class Brlan
|
||||
{
|
||||
public static string[] GetBrlanTpls(string pathTobrlan) => Brlan.getBrlanTpls(File.ReadAllBytes(pathTobrlan));
|
||||
|
||||
public static string[] GetBrlanTpls(byte[] brlanFile) => Brlan.getBrlanTpls(brlanFile);
|
||||
|
||||
public static string[] GetBrlanTpls(WAD wad, bool banner)
|
||||
{
|
||||
if (!wad.HasBanner)
|
||||
return new string[0];
|
||||
string str = nameof (banner);
|
||||
if (!banner)
|
||||
str = "icon";
|
||||
for (int index1 = 0; index1 < wad.BannerApp.Nodes.Count; ++index1)
|
||||
{
|
||||
if (wad.BannerApp.StringTable[index1].ToLower() == str + ".bin")
|
||||
{
|
||||
U8 u8 = U8.Load(wad.BannerApp.Data[index1]);
|
||||
string[] a = new string[0];
|
||||
for (int index2 = 0; index2 < u8.Nodes.Count; ++index2)
|
||||
{
|
||||
if (u8.StringTable[index2].ToLower() == str + "_start.brlan" || u8.StringTable[index2].ToLower() == str + "_loop.brlan" || u8.StringTable[index2].ToLower() == str + ".brlan")
|
||||
a = Shared.MergeStringArrays(a, Brlan.getBrlanTpls(u8.Data[index2]));
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
return new string[0];
|
||||
}
|
||||
|
||||
private static string[] getBrlanTpls(byte[] brlanFile)
|
||||
{
|
||||
List<string> stringList = new List<string>();
|
||||
int numOfTpls = Brlan.getNumOfTpls(brlanFile);
|
||||
int index1 = 36 + numOfTpls * 4;
|
||||
for (int index2 = 0; index2 < numOfTpls; ++index2)
|
||||
{
|
||||
string empty = string.Empty;
|
||||
while (brlanFile[index1] != (byte) 0)
|
||||
empty += Convert.ToChar(brlanFile[index1++]).ToString();
|
||||
stringList.Add(empty);
|
||||
++index1;
|
||||
}
|
||||
for (int index2 = stringList.Count - 1; index2 >= 0; --index2)
|
||||
{
|
||||
if (!stringList[index2].ToLower().EndsWith(".tpl"))
|
||||
stringList.RemoveAt(index2);
|
||||
}
|
||||
return stringList.ToArray();
|
||||
}
|
||||
|
||||
private static int getNumOfTpls(byte[] brlanFile) => (int) Shared.Swap(BitConverter.ToUInt16(brlanFile, 28));
|
||||
}
|
||||
}
|
66
Brlyt.cs
Normal file
66
Brlyt.cs
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.Brlyt
|
||||
// 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.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace libWiiSharp
|
||||
{
|
||||
public class Brlyt
|
||||
{
|
||||
public static string[] GetBrlytTpls(string pathToBrlyt) => Brlyt.getBrlytTpls(File.ReadAllBytes(pathToBrlyt));
|
||||
|
||||
public static string[] GetBrlytTpls(byte[] brlytFile) => Brlyt.getBrlytTpls(brlytFile);
|
||||
|
||||
public static string[] GetBrlytTpls(WAD wad, bool banner)
|
||||
{
|
||||
if (!wad.HasBanner)
|
||||
return new string[0];
|
||||
string str = nameof (banner);
|
||||
if (!banner)
|
||||
str = "icon";
|
||||
for (int index1 = 0; index1 < wad.BannerApp.Nodes.Count; ++index1)
|
||||
{
|
||||
if (wad.BannerApp.StringTable[index1].ToLower() == str + ".bin")
|
||||
{
|
||||
U8 u8 = U8.Load(wad.BannerApp.Data[index1]);
|
||||
string[] a = new string[0];
|
||||
for (int index2 = 0; index2 < u8.Nodes.Count; ++index2)
|
||||
{
|
||||
if (u8.StringTable[index2].ToLower() == str + ".brlyt")
|
||||
a = Shared.MergeStringArrays(a, Brlyt.getBrlytTpls(u8.Data[index2]));
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
return new string[0];
|
||||
}
|
||||
|
||||
private static string[] getBrlytTpls(byte[] brlytFile)
|
||||
{
|
||||
List<string> stringList = new List<string>();
|
||||
int numOfTpls = Brlyt.getNumOfTpls(brlytFile);
|
||||
int index1 = 48 + numOfTpls * 8;
|
||||
for (int index2 = 0; index2 < numOfTpls; ++index2)
|
||||
{
|
||||
string empty = string.Empty;
|
||||
while (brlytFile[index1] != (byte) 0)
|
||||
empty += Convert.ToChar(brlytFile[index1++]).ToString();
|
||||
stringList.Add(empty);
|
||||
++index1;
|
||||
}
|
||||
for (int index2 = stringList.Count - 1; index2 >= 0; --index2)
|
||||
{
|
||||
if (!stringList[index2].ToLower().EndsWith(".tpl"))
|
||||
stringList.RemoveAt(index2);
|
||||
}
|
||||
return stringList.ToArray();
|
||||
}
|
||||
|
||||
private static int getNumOfTpls(byte[] brlytFile) => (int) Shared.Swap(BitConverter.ToUInt16(brlytFile, 44));
|
||||
}
|
||||
}
|
438
CertificateChain.cs
Normal file
438
CertificateChain.cs
Normal file
|
@ -0,0 +1,438 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.CertificateChain
|
||||
// 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;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace libWiiSharp
|
||||
{
|
||||
public class CertificateChain : IDisposable
|
||||
{
|
||||
private const string certCaHash = "5B7D3EE28706AD8DA2CBD5A6B75C15D0F9B6F318";
|
||||
private const string certCpHash = "6824D6DA4C25184F0D6DAF6EDB9C0FC57522A41C";
|
||||
private const string certXsHash = "09787045037121477824BC6A3E5E076156573F8A";
|
||||
private SHA1 sha = SHA1.Create();
|
||||
private bool[] certsComplete = new bool[3];
|
||||
private byte[] certCa = new byte[1024];
|
||||
private byte[] certCp = new byte[768];
|
||||
private byte[] certXs = new byte[768];
|
||||
private bool isDisposed;
|
||||
|
||||
public bool CertsComplete => this.certsComplete[0] && this.certsComplete[1] && this.certsComplete[2];
|
||||
|
||||
public event EventHandler<MessageEventArgs> Debug;
|
||||
|
||||
~CertificateChain() => this.Dispose(false);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize((object) this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && !this.isDisposed)
|
||||
{
|
||||
this.sha.Clear();
|
||||
this.sha = (SHA1) null;
|
||||
this.certsComplete = (bool[]) null;
|
||||
this.certCa = (byte[]) null;
|
||||
this.certCp = (byte[]) null;
|
||||
this.certXs = (byte[]) null;
|
||||
}
|
||||
this.isDisposed = true;
|
||||
}
|
||||
|
||||
public static CertificateChain Load(string pathToCert) => CertificateChain.Load(File.ReadAllBytes(pathToCert));
|
||||
|
||||
public static CertificateChain Load(byte[] certFile)
|
||||
{
|
||||
CertificateChain certificateChain = new CertificateChain();
|
||||
MemoryStream memoryStream = new MemoryStream(certFile);
|
||||
try
|
||||
{
|
||||
certificateChain.parseCert((Stream) memoryStream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
memoryStream.Dispose();
|
||||
throw;
|
||||
}
|
||||
memoryStream.Dispose();
|
||||
return certificateChain;
|
||||
}
|
||||
|
||||
public static CertificateChain Load(Stream cert)
|
||||
{
|
||||
CertificateChain certificateChain = new CertificateChain();
|
||||
certificateChain.parseCert(cert);
|
||||
return certificateChain;
|
||||
}
|
||||
|
||||
public static CertificateChain FromTikTmd(string pathToTik, string pathToTmd) => CertificateChain.FromTikTmd(File.ReadAllBytes(pathToTik), File.ReadAllBytes(pathToTmd));
|
||||
|
||||
public static CertificateChain FromTikTmd(byte[] tikFile, byte[] tmdFile)
|
||||
{
|
||||
CertificateChain certificateChain = new CertificateChain();
|
||||
MemoryStream memoryStream1 = new MemoryStream(tikFile);
|
||||
try
|
||||
{
|
||||
certificateChain.grabFromTik((Stream) memoryStream1);
|
||||
}
|
||||
catch
|
||||
{
|
||||
memoryStream1.Dispose();
|
||||
throw;
|
||||
}
|
||||
MemoryStream memoryStream2 = new MemoryStream(tmdFile);
|
||||
try
|
||||
{
|
||||
certificateChain.grabFromTmd((Stream) memoryStream2);
|
||||
}
|
||||
catch
|
||||
{
|
||||
memoryStream2.Dispose();
|
||||
throw;
|
||||
}
|
||||
memoryStream2.Dispose();
|
||||
return certificateChain.CertsComplete ? certificateChain : throw new Exception("Couldn't locate all certs!");
|
||||
}
|
||||
|
||||
public static CertificateChain FromTikTmd(Stream tik, Stream tmd)
|
||||
{
|
||||
CertificateChain certificateChain = new CertificateChain();
|
||||
certificateChain.grabFromTik(tik);
|
||||
certificateChain.grabFromTmd(tmd);
|
||||
return certificateChain;
|
||||
}
|
||||
|
||||
public void LoadFile(string pathToCert) => this.LoadFile(File.ReadAllBytes(pathToCert));
|
||||
|
||||
public void LoadFile(byte[] certFile)
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream(certFile);
|
||||
try
|
||||
{
|
||||
this.parseCert((Stream) memoryStream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
memoryStream.Dispose();
|
||||
throw;
|
||||
}
|
||||
memoryStream.Dispose();
|
||||
}
|
||||
|
||||
public void LoadFile(Stream cert) => this.parseCert(cert);
|
||||
|
||||
public void LoadFromTikTmd(string pathToTik, string pathToTmd) => this.LoadFromTikTmd(File.ReadAllBytes(pathToTik), File.ReadAllBytes(pathToTmd));
|
||||
|
||||
public void LoadFromTikTmd(byte[] tikFile, byte[] tmdFile)
|
||||
{
|
||||
MemoryStream memoryStream1 = new MemoryStream(tikFile);
|
||||
try
|
||||
{
|
||||
this.grabFromTik((Stream) memoryStream1);
|
||||
}
|
||||
catch
|
||||
{
|
||||
memoryStream1.Dispose();
|
||||
throw;
|
||||
}
|
||||
MemoryStream memoryStream2 = new MemoryStream(tmdFile);
|
||||
try
|
||||
{
|
||||
this.grabFromTmd((Stream) memoryStream2);
|
||||
}
|
||||
catch
|
||||
{
|
||||
memoryStream2.Dispose();
|
||||
throw;
|
||||
}
|
||||
memoryStream2.Dispose();
|
||||
if (!this.CertsComplete)
|
||||
throw new Exception("Couldn't locate all certs!");
|
||||
}
|
||||
|
||||
public void LoadFromTikTmd(Stream tik, Stream tmd)
|
||||
{
|
||||
this.grabFromTik(tik);
|
||||
this.grabFromTmd(tmd);
|
||||
}
|
||||
|
||||
public void Save(string savePath)
|
||||
{
|
||||
if (File.Exists(savePath))
|
||||
File.Delete(savePath);
|
||||
using (FileStream fileStream = new FileStream(savePath, FileMode.Create))
|
||||
this.writeToStream((Stream) fileStream);
|
||||
}
|
||||
|
||||
public MemoryStream ToMemoryStream()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
try
|
||||
{
|
||||
this.writeToStream((Stream) memoryStream);
|
||||
return memoryStream;
|
||||
}
|
||||
catch
|
||||
{
|
||||
memoryStream.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] ToByteArray()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
try
|
||||
{
|
||||
this.writeToStream((Stream) memoryStream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
memoryStream.Dispose();
|
||||
throw;
|
||||
}
|
||||
byte[] array = memoryStream.ToArray();
|
||||
memoryStream.Dispose();
|
||||
return array;
|
||||
}
|
||||
|
||||
private void writeToStream(Stream writeStream)
|
||||
{
|
||||
this.fireDebug("Writing Certificate Chain...");
|
||||
if (!this.CertsComplete)
|
||||
{
|
||||
this.fireDebug(" Certificate Chain incomplete...");
|
||||
throw new Exception("At least one certificate is missing!");
|
||||
}
|
||||
writeStream.Seek(0L, SeekOrigin.Begin);
|
||||
object[] objArray1 = new object[1];
|
||||
long position = writeStream.Position;
|
||||
objArray1[0] = (object) position.ToString("x8");
|
||||
this.fireDebug(" Writing Certificate CA... (Offset: 0x{0})", objArray1);
|
||||
writeStream.Write(this.certCa, 0, this.certCa.Length);
|
||||
object[] objArray2 = new object[1];
|
||||
position = writeStream.Position;
|
||||
objArray2[0] = (object) position.ToString("x8");
|
||||
this.fireDebug(" Writing Certificate CP... (Offset: 0x{0})", objArray2);
|
||||
writeStream.Write(this.certCp, 0, this.certCp.Length);
|
||||
object[] objArray3 = new object[1];
|
||||
position = writeStream.Position;
|
||||
objArray3[0] = (object) position.ToString("x8");
|
||||
this.fireDebug(" Writing Certificate XS... (Offset: 0x{0})", objArray3);
|
||||
writeStream.Write(this.certXs, 0, this.certXs.Length);
|
||||
this.fireDebug("Writing Certificate Chain Finished...");
|
||||
}
|
||||
|
||||
private void parseCert(Stream certFile)
|
||||
{
|
||||
this.fireDebug("Parsing Certificate Chain...");
|
||||
int num = 0;
|
||||
for (int index = 0; index < 3; ++index)
|
||||
{
|
||||
this.fireDebug(" Scanning at Offset 0x{0}:", (object) num.ToString("x8"));
|
||||
try
|
||||
{
|
||||
certFile.Seek((long) num, SeekOrigin.Begin);
|
||||
byte[] array = new byte[1024];
|
||||
certFile.Read(array, 0, array.Length);
|
||||
this.fireDebug(" Checking for Certificate CA...");
|
||||
if (this.isCertCa(array) && !this.certsComplete[1])
|
||||
{
|
||||
this.fireDebug(" Certificate CA detected...");
|
||||
this.certCa = array;
|
||||
this.certsComplete[1] = true;
|
||||
num += 1024;
|
||||
continue;
|
||||
}
|
||||
this.fireDebug(" Checking for Certificate CP...");
|
||||
if (this.isCertCp(array) && !this.certsComplete[2])
|
||||
{
|
||||
this.fireDebug(" Certificate CP detected...");
|
||||
Array.Resize<byte>(ref array, 768);
|
||||
this.certCp = array;
|
||||
this.certsComplete[2] = true;
|
||||
num += 768;
|
||||
continue;
|
||||
}
|
||||
this.fireDebug(" Checking for Certificate XS...");
|
||||
if (this.isCertXs(array))
|
||||
{
|
||||
if (!this.certsComplete[0])
|
||||
{
|
||||
this.fireDebug(" Certificate XS detected...");
|
||||
Array.Resize<byte>(ref array, 768);
|
||||
this.certXs = array;
|
||||
this.certsComplete[0] = true;
|
||||
num += 768;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.fireDebug("Error: {0}", (object) ex.Message);
|
||||
}
|
||||
num += 768;
|
||||
}
|
||||
if (!this.CertsComplete)
|
||||
{
|
||||
this.fireDebug(" Couldn't locate all Certificates...");
|
||||
throw new Exception("Couldn't locate all certs!");
|
||||
}
|
||||
this.fireDebug("Parsing Certificate Chain Finished...");
|
||||
}
|
||||
|
||||
private void grabFromTik(Stream tik)
|
||||
{
|
||||
this.fireDebug("Scanning Ticket for Certificates...");
|
||||
int num = 676;
|
||||
for (int index = 0; index < 3; ++index)
|
||||
{
|
||||
this.fireDebug(" Scanning at Offset 0x{0}:", (object) num.ToString("x8"));
|
||||
try
|
||||
{
|
||||
tik.Seek((long) num, SeekOrigin.Begin);
|
||||
byte[] array = new byte[1024];
|
||||
tik.Read(array, 0, array.Length);
|
||||
this.fireDebug(" Checking for Certificate CA...");
|
||||
if (this.isCertCa(array) && !this.certsComplete[1])
|
||||
{
|
||||
this.fireDebug(" Certificate CA detected...");
|
||||
this.certCa = array;
|
||||
this.certsComplete[1] = true;
|
||||
num += 1024;
|
||||
continue;
|
||||
}
|
||||
this.fireDebug(" Checking for Certificate CP...");
|
||||
if (this.isCertCp(array) && !this.certsComplete[2])
|
||||
{
|
||||
this.fireDebug(" Certificate CP detected...");
|
||||
Array.Resize<byte>(ref array, 768);
|
||||
this.certCp = array;
|
||||
this.certsComplete[2] = true;
|
||||
num += 768;
|
||||
continue;
|
||||
}
|
||||
this.fireDebug(" Checking for Certificate XS...");
|
||||
if (this.isCertXs(array))
|
||||
{
|
||||
if (!this.certsComplete[0])
|
||||
{
|
||||
this.fireDebug(" Certificate XS detected...");
|
||||
Array.Resize<byte>(ref array, 768);
|
||||
this.certXs = array;
|
||||
this.certsComplete[0] = true;
|
||||
num += 768;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
num += 768;
|
||||
}
|
||||
this.fireDebug("Scanning Ticket for Certificates Finished...");
|
||||
}
|
||||
|
||||
private void grabFromTmd(Stream tmd)
|
||||
{
|
||||
this.fireDebug("Scanning TMD for Certificates...");
|
||||
byte[] buffer = new byte[2];
|
||||
tmd.Seek(478L, SeekOrigin.Begin);
|
||||
tmd.Read(buffer, 0, 2);
|
||||
int num = 484 + (int) Shared.Swap(BitConverter.ToUInt16(buffer, 0)) * 36;
|
||||
for (int index = 0; index < 3; ++index)
|
||||
{
|
||||
this.fireDebug(" Scanning at Offset 0x{0}:", (object) num.ToString("x8"));
|
||||
try
|
||||
{
|
||||
tmd.Seek((long) num, SeekOrigin.Begin);
|
||||
byte[] array = new byte[1024];
|
||||
tmd.Read(array, 0, array.Length);
|
||||
this.fireDebug(" Checking for Certificate CA...");
|
||||
if (this.isCertCa(array) && !this.certsComplete[1])
|
||||
{
|
||||
this.fireDebug(" Certificate CA detected...");
|
||||
this.certCa = array;
|
||||
this.certsComplete[1] = true;
|
||||
num += 1024;
|
||||
continue;
|
||||
}
|
||||
this.fireDebug(" Checking for Certificate CP...");
|
||||
if (this.isCertCp(array) && !this.certsComplete[2])
|
||||
{
|
||||
this.fireDebug(" Certificate CP detected...");
|
||||
Array.Resize<byte>(ref array, 768);
|
||||
this.certCp = array;
|
||||
this.certsComplete[2] = true;
|
||||
num += 768;
|
||||
continue;
|
||||
}
|
||||
this.fireDebug(" Checking for Certificate XS...");
|
||||
if (this.isCertXs(array))
|
||||
{
|
||||
if (!this.certsComplete[0])
|
||||
{
|
||||
this.fireDebug(" Certificate XS detected...");
|
||||
Array.Resize<byte>(ref array, 768);
|
||||
this.certXs = array;
|
||||
this.certsComplete[0] = true;
|
||||
num += 768;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
num += 768;
|
||||
}
|
||||
this.fireDebug("Scanning TMD for Certificates Finished...");
|
||||
}
|
||||
|
||||
private bool isCertXs(byte[] part)
|
||||
{
|
||||
if (part.Length < 768)
|
||||
return false;
|
||||
if (part.Length > 768)
|
||||
Array.Resize<byte>(ref part, 768);
|
||||
return part[388] == (byte) 88 && part[389] == (byte) 83 && Shared.CompareByteArrays(this.sha.ComputeHash(part), Shared.HexStringToByteArray("09787045037121477824BC6A3E5E076156573F8A"));
|
||||
}
|
||||
|
||||
private bool isCertCa(byte[] part)
|
||||
{
|
||||
if (part.Length < 1024)
|
||||
return false;
|
||||
if (part.Length > 1024)
|
||||
Array.Resize<byte>(ref part, 1024);
|
||||
return part[644] == (byte) 67 && part[645] == (byte) 65 && Shared.CompareByteArrays(this.sha.ComputeHash(part), Shared.HexStringToByteArray("5B7D3EE28706AD8DA2CBD5A6B75C15D0F9B6F318"));
|
||||
}
|
||||
|
||||
private bool isCertCp(byte[] part)
|
||||
{
|
||||
if (part.Length < 768)
|
||||
return false;
|
||||
if (part.Length > 768)
|
||||
Array.Resize<byte>(ref part, 768);
|
||||
return part[388] == (byte) 67 && part[389] == (byte) 80 && Shared.CompareByteArrays(this.sha.ComputeHash(part), Shared.HexStringToByteArray("6824D6DA4C25184F0D6DAF6EDB9C0FC57522A41C"));
|
||||
}
|
||||
|
||||
private void fireDebug(string debugMessage, params object[] args)
|
||||
{
|
||||
EventHandler<MessageEventArgs> debug = this.Debug;
|
||||
if (debug == null)
|
||||
return;
|
||||
debug(new object(), new MessageEventArgs(string.Format(debugMessage, args)));
|
||||
}
|
||||
}
|
||||
}
|
34
Changelog_libWiiSharp.txt
Normal file
34
Changelog_libWiiSharp.txt
Normal file
|
@ -0,0 +1,34 @@
|
|||
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
libWiiSharp
|
||||
by Leathl
|
||||
Modified by TheShadowEevee
|
||||
https://github.com/TheShadowEevee/libWiiSharp
|
||||
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
|
||||
|
||||
Changelog:
|
||||
-=-=-=-=-=-
|
||||
|
||||
Version 0.4 (TheShadowEevee's takeover)
|
||||
- Checks for an existing CETK now, which helps for some files that needed one but couldn't get it through other means.
|
||||
|
||||
Version 0.3
|
||||
- Added support to change the common key index of the ticket in the WAD class
|
||||
- Made the sorting of wad/tmd contents optional (off by default!)
|
||||
|
||||
Version 0.21
|
||||
- Fixed smpl region not read in Wave class
|
||||
|
||||
Version 0.2
|
||||
- Added support to pass streams
|
||||
- Speed up in TPL conversion
|
||||
- Further changes in TPL class (e.g. changed saving to be compatible with official TPL files)
|
||||
- Fixed IA8 TPL code (from/to)
|
||||
- Fixed CI14X2 TPL code (from)
|
||||
- Added TPL conversion to CI4 and CI8
|
||||
- Added BNS to Wave conversion
|
||||
- Wave class completely rewritten
|
||||
|
||||
Version 0.1
|
||||
- Initial Release
|
279
ColorIndexConverter.cs
Normal file
279
ColorIndexConverter.cs
Normal file
|
@ -0,0 +1,279 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.ColorIndexConverter
|
||||
// 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.Collections.Generic;
|
||||
|
||||
namespace libWiiSharp
|
||||
{
|
||||
internal class ColorIndexConverter
|
||||
{
|
||||
private uint[] rgbaPalette;
|
||||
private byte[] tplPalette;
|
||||
private uint[] rgbaData;
|
||||
private byte[] tplData;
|
||||
private TPL_TextureFormat tplFormat;
|
||||
private TPL_PaletteFormat paletteFormat;
|
||||
private int width;
|
||||
private int height;
|
||||
|
||||
public byte[] Palette => this.tplPalette;
|
||||
|
||||
public byte[] Data => this.tplData;
|
||||
|
||||
public ColorIndexConverter(
|
||||
uint[] rgbaData,
|
||||
int width,
|
||||
int height,
|
||||
TPL_TextureFormat tplFormat,
|
||||
TPL_PaletteFormat paletteFormat)
|
||||
{
|
||||
if (tplFormat != TPL_TextureFormat.CI4 && tplFormat != TPL_TextureFormat.CI8)
|
||||
throw new Exception("Texture format must be either CI4 or CI8");
|
||||
if (paletteFormat != TPL_PaletteFormat.IA8 && paletteFormat != TPL_PaletteFormat.RGB565 && paletteFormat != TPL_PaletteFormat.RGB5A3)
|
||||
throw new Exception("Palette format must be either IA8, RGB565 or RGB5A3!");
|
||||
this.rgbaData = rgbaData;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.tplFormat = tplFormat;
|
||||
this.paletteFormat = paletteFormat;
|
||||
this.buildPalette();
|
||||
if (tplFormat != TPL_TextureFormat.CI4)
|
||||
{
|
||||
if (tplFormat == TPL_TextureFormat.CI8)
|
||||
this.toCI8();
|
||||
else
|
||||
this.toCI14X2();
|
||||
}
|
||||
else
|
||||
this.toCI4();
|
||||
}
|
||||
|
||||
private void toCI4()
|
||||
{
|
||||
byte[] numArray = new byte[Shared.AddPadding(this.width, 8) * Shared.AddPadding(this.height, 8) / 2];
|
||||
int num = 0;
|
||||
for (int index1 = 0; index1 < this.height; index1 += 8)
|
||||
{
|
||||
for (int index2 = 0; index2 < this.width; index2 += 8)
|
||||
{
|
||||
for (int index3 = index1; index3 < index1 + 8; ++index3)
|
||||
{
|
||||
for (int index4 = index2; index4 < index2 + 8; index4 += 2)
|
||||
{
|
||||
uint colorIndex1 = this.getColorIndex(index3 >= this.height || index4 >= this.width ? 0U : this.rgbaData[index3 * this.width + index4]);
|
||||
uint colorIndex2 = this.getColorIndex(index3 >= this.height || index4 >= this.width ? 0U : (index3 * this.width + index4 + 1 < this.rgbaData.Length ? this.rgbaData[index3 * this.width + index4 + 1] : 0U));
|
||||
numArray[num++] = (byte) ((uint) (byte) colorIndex1 << 4 | (uint) (byte) colorIndex2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.tplData = numArray;
|
||||
}
|
||||
|
||||
private void toCI8()
|
||||
{
|
||||
byte[] numArray = new byte[Shared.AddPadding(this.width, 8) * Shared.AddPadding(this.height, 4)];
|
||||
int num1 = 0;
|
||||
for (int index1 = 0; index1 < this.height; index1 += 4)
|
||||
{
|
||||
for (int index2 = 0; index2 < this.width; index2 += 8)
|
||||
{
|
||||
for (int index3 = index1; index3 < index1 + 4; ++index3)
|
||||
{
|
||||
for (int index4 = index2; index4 < index2 + 8; ++index4)
|
||||
{
|
||||
uint num2 = index3 >= this.height || index4 >= this.width ? 0U : this.rgbaData[index3 * this.width + index4];
|
||||
numArray[num1++] = (byte) this.getColorIndex(num2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.tplData = numArray;
|
||||
}
|
||||
|
||||
private void toCI14X2()
|
||||
{
|
||||
byte[] numArray1 = new byte[Shared.AddPadding(this.width, 4) * Shared.AddPadding(this.height, 4) * 2];
|
||||
int num1 = 0;
|
||||
for (int index1 = 0; index1 < this.height; index1 += 4)
|
||||
{
|
||||
for (int index2 = 0; index2 < this.width; index2 += 4)
|
||||
{
|
||||
for (int index3 = index1; index3 < index1 + 4; ++index3)
|
||||
{
|
||||
for (int index4 = index2; index4 < index2 + 4; ++index4)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes((ushort) this.getColorIndex(index3 >= this.height || index4 >= this.width ? 0U : this.rgbaData[index3 * this.width + index4]));
|
||||
byte[] numArray2 = numArray1;
|
||||
int index5 = num1;
|
||||
int num2 = index5 + 1;
|
||||
int num3 = (int) bytes[1];
|
||||
numArray2[index5] = (byte) num3;
|
||||
byte[] numArray3 = numArray1;
|
||||
int index6 = num2;
|
||||
num1 = index6 + 1;
|
||||
int num4 = (int) bytes[0];
|
||||
numArray3[index6] = (byte) num4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.tplData = numArray1;
|
||||
}
|
||||
|
||||
private void buildPalette()
|
||||
{
|
||||
int num1 = 256;
|
||||
if (this.tplFormat == TPL_TextureFormat.CI4)
|
||||
num1 = 16;
|
||||
else if (this.tplFormat == TPL_TextureFormat.CI14X2)
|
||||
num1 = 16384;
|
||||
List<uint> uintList = new List<uint>();
|
||||
List<ushort> ushortList = new List<ushort>();
|
||||
uintList.Add(0U);
|
||||
ushortList.Add((ushort) 0);
|
||||
for (int index = 1; index < this.rgbaData.Length && uintList.Count != num1; ++index)
|
||||
{
|
||||
if ((long) (this.rgbaData[index] >> 24 & (uint) byte.MaxValue) >= (this.tplFormat == TPL_TextureFormat.CI14X2 ? 1L : 25L))
|
||||
{
|
||||
ushort num2 = Shared.Swap(this.convertToPaletteValue((int) this.rgbaData[index]));
|
||||
if (!uintList.Contains(this.rgbaData[index]) && !ushortList.Contains(num2))
|
||||
{
|
||||
uintList.Add(this.rgbaData[index]);
|
||||
ushortList.Add(num2);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (uintList.Count % 16 != 0)
|
||||
{
|
||||
uintList.Add(uint.MaxValue);
|
||||
ushortList.Add(ushort.MaxValue);
|
||||
}
|
||||
this.tplPalette = Shared.UShortArrayToByteArray(ushortList.ToArray());
|
||||
this.rgbaPalette = uintList.ToArray();
|
||||
}
|
||||
|
||||
private ushort convertToPaletteValue(int rgba)
|
||||
{
|
||||
int num1 = 0;
|
||||
int num2;
|
||||
if (this.paletteFormat == TPL_PaletteFormat.IA8)
|
||||
{
|
||||
int num3 = ((rgba & (int) byte.MaxValue) + (rgba >> 8 & (int) byte.MaxValue) + (rgba >> 16 & (int) byte.MaxValue)) / 3 & (int) byte.MaxValue;
|
||||
num2 = (int) (ushort) ((rgba >> 24 & (int) byte.MaxValue) << 8 | num3);
|
||||
}
|
||||
else if (this.paletteFormat == TPL_PaletteFormat.RGB565)
|
||||
{
|
||||
num2 = (int) (ushort) ((rgba >> 16 & (int) byte.MaxValue) >> 3 << 11 | (rgba >> 8 & (int) byte.MaxValue) >> 2 << 5 | (rgba & (int) byte.MaxValue) >> 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
int num3 = rgba >> 16 & (int) byte.MaxValue;
|
||||
int num4 = rgba >> 8 & (int) byte.MaxValue;
|
||||
int num5 = rgba & (int) byte.MaxValue;
|
||||
int num6 = rgba >> 24 & (int) byte.MaxValue;
|
||||
if (num6 <= 218)
|
||||
{
|
||||
int num7 = num1 & -32769;
|
||||
int num8 = num3 * 15 / (int) byte.MaxValue & 15;
|
||||
int num9 = num4 * 15 / (int) byte.MaxValue & 15;
|
||||
int num10 = num5 * 15 / (int) byte.MaxValue & 15;
|
||||
int num11 = num6 * 7 / (int) byte.MaxValue & 7;
|
||||
num2 = num7 | num11 << 12 | num10 | num9 << 4 | num8 << 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
int num7 = num1 | 32768;
|
||||
int num8 = num3 * 31 / (int) byte.MaxValue & 31;
|
||||
int num9 = num4 * 31 / (int) byte.MaxValue & 31;
|
||||
int num10 = num5 * 31 / (int) byte.MaxValue & 31;
|
||||
num2 = num7 | num10 | num9 << 5 | num8 << 10;
|
||||
}
|
||||
}
|
||||
return (ushort) num2;
|
||||
}
|
||||
|
||||
private uint getColorIndex(uint value)
|
||||
{
|
||||
uint num1 = (uint) int.MaxValue;
|
||||
uint num2 = 0;
|
||||
if ((long) (value >> 24 & (uint) byte.MaxValue) < (this.tplFormat == TPL_TextureFormat.CI14X2 ? 1L : 25L))
|
||||
return 0;
|
||||
ushort paletteValue1 = this.convertToPaletteValue((int) value);
|
||||
for (int index = 0; index < this.rgbaPalette.Length; ++index)
|
||||
{
|
||||
ushort paletteValue2 = this.convertToPaletteValue((int) this.rgbaPalette[index]);
|
||||
if ((int) paletteValue1 == (int) paletteValue2)
|
||||
return (uint) index;
|
||||
uint distance = this.getDistance(paletteValue1, paletteValue2);
|
||||
if (distance < num1)
|
||||
{
|
||||
num1 = distance;
|
||||
num2 = (uint) index;
|
||||
}
|
||||
}
|
||||
return num2;
|
||||
}
|
||||
|
||||
private uint getDistance(ushort color, ushort paletteColor)
|
||||
{
|
||||
int rgbaValue1 = (int) this.convertToRgbaValue(color);
|
||||
uint rgbaValue2 = this.convertToRgbaValue(paletteColor);
|
||||
uint val1_1 = (uint) rgbaValue1 >> 24 & (uint) byte.MaxValue;
|
||||
uint val1_2 = (uint) rgbaValue1 >> 16 & (uint) byte.MaxValue;
|
||||
uint val1_3 = (uint) rgbaValue1 >> 8 & (uint) byte.MaxValue;
|
||||
uint val1_4 = (uint) (rgbaValue1 & (int) byte.MaxValue);
|
||||
uint val2_1 = rgbaValue2 >> 24 & (uint) byte.MaxValue;
|
||||
uint val2_2 = rgbaValue2 >> 16 & (uint) byte.MaxValue;
|
||||
uint val2_3 = rgbaValue2 >> 8 & (uint) byte.MaxValue;
|
||||
uint val2_4 = rgbaValue2 & (uint) byte.MaxValue;
|
||||
int num1 = (int) Math.Max(val1_1, val2_1) - (int) Math.Min(val1_1, val2_1);
|
||||
uint num2 = Math.Max(val1_2, val2_2) - Math.Min(val1_2, val2_2);
|
||||
uint num3 = Math.Max(val1_3, val2_3) - Math.Min(val1_3, val2_3);
|
||||
uint num4 = Math.Max(val1_4, val2_4) - Math.Min(val1_4, val2_4);
|
||||
int num5 = (int) num2;
|
||||
return (uint) (num1 + num5) + num3 + num4;
|
||||
}
|
||||
|
||||
private uint convertToRgbaValue(ushort pixel)
|
||||
{
|
||||
if (this.paletteFormat == TPL_PaletteFormat.IA8)
|
||||
{
|
||||
int num1 = (int) pixel >> 8;
|
||||
int num2 = (int) pixel & (int) byte.MaxValue;
|
||||
return (uint) (num1 | num1 << 8 | num1 << 16 | num2 << 24);
|
||||
}
|
||||
if (this.paletteFormat == TPL_PaletteFormat.RGB565)
|
||||
{
|
||||
int num1 = ((int) pixel >> 11 & 31) << 3 & (int) byte.MaxValue;
|
||||
int num2 = ((int) pixel >> 5 & 63) << 2 & (int) byte.MaxValue;
|
||||
int num3 = ((int) pixel & 31) << 3 & (int) byte.MaxValue;
|
||||
int maxValue = (int) byte.MaxValue;
|
||||
return (uint) (num3 | num2 << 8 | num1 << 16 | maxValue << 24);
|
||||
}
|
||||
int num4;
|
||||
int num5;
|
||||
int num6;
|
||||
int num7;
|
||||
if (((int) pixel & 32768) != 0)
|
||||
{
|
||||
num4 = ((int) pixel >> 10 & 31) * (int) byte.MaxValue / 31;
|
||||
num5 = ((int) pixel >> 5 & 31) * (int) byte.MaxValue / 31;
|
||||
num6 = ((int) pixel & 31) * (int) byte.MaxValue / 31;
|
||||
num7 = (int) byte.MaxValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
num7 = ((int) pixel >> 12 & 7) * (int) byte.MaxValue / 7;
|
||||
num4 = ((int) pixel >> 8 & 15) * (int) byte.MaxValue / 15;
|
||||
num5 = ((int) pixel >> 4 & 15) * (int) byte.MaxValue / 15;
|
||||
num6 = ((int) pixel & 15) * (int) byte.MaxValue / 15;
|
||||
}
|
||||
return (uint) (num6 | num5 << 8 | num4 << 16 | num7 << 24);
|
||||
}
|
||||
}
|
||||
}
|
18
CommonKey.cs
Normal file
18
CommonKey.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
// 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
|
||||
|
||||
namespace libWiiSharp
|
||||
{
|
||||
public class CommonKey
|
||||
{
|
||||
private static string standardKey = "ebe42a225e8593e448d9c5457381aaf7";
|
||||
private static string koreanKey = "63b82bb4f4614e2e13f2fefbba4c9b7e";
|
||||
|
||||
public static byte[] GetStandardKey() => Shared.HexStringToByteArray(CommonKey.standardKey);
|
||||
|
||||
public static byte[] GetKoreanKey() => Shared.HexStringToByteArray(CommonKey.koreanKey);
|
||||
}
|
||||
}
|
14
CommonKeyType.cs
Normal file
14
CommonKeyType.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
// 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,
|
||||
}
|
||||
}
|
33
ContentIndices.cs
Normal file
33
ContentIndices.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
// 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
|
||||
|
||||
using System;
|
||||
|
||||
namespace libWiiSharp
|
||||
{
|
||||
public struct ContentIndices : IComparable
|
||||
{
|
||||
private int index;
|
||||
private int contentIndex;
|
||||
|
||||
public int Index => this.index;
|
||||
|
||||
public int ContentIndex => this.contentIndex;
|
||||
|
||||
public ContentIndices(int index, int contentIndex)
|
||||
{
|
||||
this.index = index;
|
||||
this.contentIndex = contentIndex;
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
if (obj is ContentIndices contentIndices)
|
||||
return this.contentIndex.CompareTo(contentIndices.contentIndex);
|
||||
throw new ArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
15
ContentType.cs
Normal file
15
ContentType.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.ContentType
|
||||
// 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 ContentType : ushort
|
||||
{
|
||||
Normal = 1,
|
||||
DLC = 16385, // 0x4001
|
||||
Shared = 32769, // 0x8001
|
||||
}
|
||||
}
|
301
HbcTransmitter.cs
Normal file
301
HbcTransmitter.cs
Normal file
|
@ -0,0 +1,301 @@
|
|||
// 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
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
|
||||
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
|
||||
{
|
||||
get => this.blocksize;
|
||||
set => this.blocksize = value;
|
||||
}
|
||||
|
||||
public int WiiloadVersionMayor
|
||||
{
|
||||
get => this.wiiloadMayor;
|
||||
set => this.wiiloadMayor = value;
|
||||
}
|
||||
|
||||
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<ProgressChangedEventArgs> Progress;
|
||||
|
||||
public event EventHandler<MessageEventArgs> 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)
|
||||
{
|
||||
this.nwStream.Close();
|
||||
this.nwStream = (NetworkStream) null;
|
||||
}
|
||||
if (this.tcpClient != null)
|
||||
{
|
||||
this.tcpClient.Close();
|
||||
this.tcpClient = (TcpClient) null;
|
||||
}
|
||||
}
|
||||
this.isDisposed = true;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
private void fireDebug(string debugMessage, params object[] args)
|
||||
{
|
||||
EventHandler<MessageEventArgs> debug = this.Debug;
|
||||
if (debug == null)
|
||||
return;
|
||||
debug(new object(), new MessageEventArgs(string.Format(debugMessage, args)));
|
||||
}
|
||||
|
||||
private void fireProgress(int progressPercentage)
|
||||
{
|
||||
EventHandler<ProgressChangedEventArgs> progress = this.Progress;
|
||||
if (progress == null)
|
||||
return;
|
||||
progress(new object(), new ProgressChangedEventArgs(progressPercentage, (object) string.Empty));
|
||||
}
|
||||
}
|
||||
}
|
590
Headers.cs
Normal file
590
Headers.cs
Normal file
|
@ -0,0 +1,590 @@
|
|||
// 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
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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!");
|
||||
}
|
||||
}
|
||||
|
||||
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!");
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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!");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetAllTitles(string newTitle)
|
||||
{
|
||||
for (int titleIndex = 0; titleIndex < 10; ++titleIndex)
|
||||
this.setTitleFromString(newTitle, titleIndex);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
260
HexView.cs
Normal file
260
HexView.cs
Normal file
|
@ -0,0 +1,260 @@
|
|||
// 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
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
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)
|
||||
{
|
||||
richTextBox.Clear();
|
||||
richTextBox.Font = new Font("Courier New", 9f);
|
||||
richTextBox.ReadOnly = true;
|
||||
richTextBox.Text = HexView.DumpAsString(data);
|
||||
}
|
||||
|
||||
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<string> stringList = new List<string>();
|
||||
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<byte> byteList = new List<byte>();
|
||||
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;
|
||||
}
|
||||
}
|
286
IosPatcher.cs
Normal file
286
IosPatcher.cs
Normal file
|
@ -0,0 +1,286 @@
|
|||
// 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
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
|
||||
namespace libWiiSharp
|
||||
{
|
||||
public class IosPatcher
|
||||
{
|
||||
private WAD wadFile;
|
||||
private int esIndex = -1;
|
||||
|
||||
public event EventHandler<ProgressChangedEventArgs> Progress;
|
||||
|
||||
public event EventHandler<MessageEventArgs> Debug;
|
||||
|
||||
public void LoadIOS(ref WAD iosWad)
|
||||
{
|
||||
this.wadFile = iosWad;
|
||||
this.getEsIndex();
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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 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!");
|
||||
}
|
||||
|
||||
private void fireDebug(string debugMessage, params object[] args)
|
||||
{
|
||||
EventHandler<MessageEventArgs> debug = this.Debug;
|
||||
if (debug == null)
|
||||
return;
|
||||
debug(new object(), new MessageEventArgs(string.Format(debugMessage, args)));
|
||||
}
|
||||
|
||||
private void fireProgress(int progressPercentage)
|
||||
{
|
||||
EventHandler<ProgressChangedEventArgs> progress = this.Progress;
|
||||
if (progress == null)
|
||||
return;
|
||||
progress(new object(), new ProgressChangedEventArgs(progressPercentage, (object) string.Empty));
|
||||
}
|
||||
}
|
||||
}
|
674
License_libWiiSharp.txt
Normal file
674
License_libWiiSharp.txt
Normal file
|
@ -0,0 +1,674 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
18
LowerTitleID.cs
Normal file
18
LowerTitleID.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
// 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
|
||||
}
|
||||
}
|
360
Lz77.cs
Normal file
360
Lz77.cs
Normal file
|
@ -0,0 +1,360 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.Lz77
|
||||
// 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 Lz77
|
||||
{
|
||||
private const int N = 4096;
|
||||
private const int F = 18;
|
||||
private const int threshold = 2;
|
||||
private static uint lz77Magic = 1280980791;
|
||||
private int[] leftSon = new int[4097];
|
||||
private int[] rightSon = new int[4353];
|
||||
private int[] dad = new int[4097];
|
||||
private ushort[] textBuffer = new ushort[4113];
|
||||
private int matchPosition;
|
||||
private int matchLength;
|
||||
|
||||
public static uint Lz77Magic => Lz77.lz77Magic;
|
||||
|
||||
public static bool IsLz77Compressed(string file) => Lz77.IsLz77Compressed(File.ReadAllBytes(file));
|
||||
|
||||
public static bool IsLz77Compressed(byte[] file)
|
||||
{
|
||||
Headers.HeaderType headerType = Headers.DetectHeader(file);
|
||||
return (int) Shared.Swap(BitConverter.ToUInt32(file, (int) headerType)) == (int) Lz77.lz77Magic;
|
||||
}
|
||||
|
||||
public static bool IsLz77Compressed(Stream file)
|
||||
{
|
||||
Headers.HeaderType headerType = Headers.DetectHeader(file);
|
||||
byte[] buffer = new byte[4];
|
||||
file.Seek((long) headerType, SeekOrigin.Begin);
|
||||
file.Read(buffer, 0, buffer.Length);
|
||||
return (int) Shared.Swap(BitConverter.ToUInt32(buffer, 0)) == (int) Lz77.lz77Magic;
|
||||
}
|
||||
|
||||
public void Compress(string inFile, string outFile)
|
||||
{
|
||||
Stream stream = (Stream) null;
|
||||
using (FileStream fileStream = new FileStream(inFile, FileMode.Open))
|
||||
stream = this.compress((Stream) fileStream);
|
||||
byte[] buffer = new byte[stream.Length];
|
||||
stream.Read(buffer, 0, buffer.Length);
|
||||
if (File.Exists(outFile))
|
||||
File.Delete(outFile);
|
||||
using (FileStream fileStream = new FileStream(outFile, FileMode.Create))
|
||||
fileStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
public byte[] Compress(byte[] file) => ((MemoryStream) this.compress((Stream) new MemoryStream(file))).ToArray();
|
||||
|
||||
public Stream Compress(Stream file) => this.compress(file);
|
||||
|
||||
public void Decompress(string inFile, string outFile)
|
||||
{
|
||||
Stream stream = (Stream) null;
|
||||
using (FileStream fileStream = new FileStream(inFile, FileMode.Open))
|
||||
stream = this.decompress((Stream) fileStream);
|
||||
byte[] buffer = new byte[stream.Length];
|
||||
stream.Read(buffer, 0, buffer.Length);
|
||||
if (File.Exists(outFile))
|
||||
File.Delete(outFile);
|
||||
using (FileStream fileStream = new FileStream(outFile, FileMode.Create))
|
||||
fileStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
public byte[] Decompress(byte[] file) => ((MemoryStream) this.decompress((Stream) new MemoryStream(file))).ToArray();
|
||||
|
||||
public Stream Decompress(Stream file) => this.decompress(file);
|
||||
|
||||
private Stream decompress(Stream inFile)
|
||||
{
|
||||
if (!Lz77.IsLz77Compressed(inFile))
|
||||
return inFile;
|
||||
inFile.Seek(0L, SeekOrigin.Begin);
|
||||
uint num1 = 0;
|
||||
Headers.HeaderType headerType = Headers.DetectHeader(inFile);
|
||||
byte[] buffer = new byte[8];
|
||||
inFile.Seek((long) headerType, SeekOrigin.Begin);
|
||||
inFile.Read(buffer, 0, 8);
|
||||
if ((int) Shared.Swap(BitConverter.ToUInt32(buffer, 0)) != (int) Lz77.lz77Magic)
|
||||
{
|
||||
inFile.Dispose();
|
||||
throw new Exception("Invaild Magic!");
|
||||
}
|
||||
if (buffer[4] != (byte) 16)
|
||||
{
|
||||
inFile.Dispose();
|
||||
throw new Exception("Unsupported Compression Type!");
|
||||
}
|
||||
uint num2 = BitConverter.ToUInt32(buffer, 4) >> 8;
|
||||
for (int index = 0; index < 4078; ++index)
|
||||
this.textBuffer[index] = (ushort) 223;
|
||||
int num3 = 4078;
|
||||
uint num4 = 7;
|
||||
int num5 = 7;
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
label_10:
|
||||
while (true)
|
||||
{
|
||||
num4 <<= 1;
|
||||
++num5;
|
||||
if (num5 == 8)
|
||||
{
|
||||
int num6;
|
||||
if ((num6 = inFile.ReadByte()) != -1)
|
||||
{
|
||||
num4 = (uint) num6;
|
||||
num5 = 0;
|
||||
}
|
||||
else
|
||||
goto label_24;
|
||||
}
|
||||
if (((int) num4 & 128) == 0)
|
||||
{
|
||||
int num6;
|
||||
if ((long) (num6 = inFile.ReadByte()) != inFile.Length - 1L)
|
||||
{
|
||||
if (num1 < num2)
|
||||
memoryStream.WriteByte((byte) num6);
|
||||
ushort[] textBuffer = this.textBuffer;
|
||||
int index = num3;
|
||||
int num7 = index + 1;
|
||||
int num8 = (int) (byte) num6;
|
||||
textBuffer[index] = (ushort) num8;
|
||||
num3 = num7 & 4095;
|
||||
++num1;
|
||||
}
|
||||
else
|
||||
goto label_24;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
int num9;
|
||||
int num10;
|
||||
if ((num9 = inFile.ReadByte()) != -1 && (num10 = inFile.ReadByte()) != -1)
|
||||
{
|
||||
int num6 = num10 | num9 << 8 & 3840;
|
||||
int num7 = (num9 >> 4 & 15) + 2;
|
||||
for (int index1 = 0; index1 <= num7; ++index1)
|
||||
{
|
||||
int num8 = (int) this.textBuffer[num3 - num6 - 1 & 4095];
|
||||
if (num1 < num2)
|
||||
memoryStream.WriteByte((byte) num8);
|
||||
ushort[] textBuffer = this.textBuffer;
|
||||
int index2 = num3;
|
||||
int num11 = index2 + 1;
|
||||
int num12 = (int) (byte) num8;
|
||||
textBuffer[index2] = (ushort) num12;
|
||||
num3 = num11 & 4095;
|
||||
++num1;
|
||||
}
|
||||
goto label_10;
|
||||
}
|
||||
label_24:
|
||||
return (Stream) memoryStream;
|
||||
}
|
||||
|
||||
private Stream compress(Stream inFile)
|
||||
{
|
||||
if (Lz77.IsLz77Compressed(inFile))
|
||||
return inFile;
|
||||
inFile.Seek(0L, SeekOrigin.Begin);
|
||||
int num1 = 0;
|
||||
int[] numArray1 = new int[17];
|
||||
uint num2 = (uint) (((int) Convert.ToUInt32(inFile.Length) << 8) + 16);
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(Lz77.lz77Magic)), 0, 4);
|
||||
memoryStream.Write(BitConverter.GetBytes(num2), 0, 4);
|
||||
this.InitTree();
|
||||
numArray1[0] = 0;
|
||||
int num3 = 1;
|
||||
int num4 = 128;
|
||||
int p = 0;
|
||||
int r = 4078;
|
||||
for (int index = p; index < r; ++index)
|
||||
this.textBuffer[index] = ushort.MaxValue;
|
||||
int num5;
|
||||
int num6;
|
||||
for (num5 = 0; num5 < 18 && (num6 = inFile.ReadByte()) != -1; ++num5)
|
||||
this.textBuffer[r + num5] = (ushort) num6;
|
||||
if (num5 == 0)
|
||||
return inFile;
|
||||
for (int index = 1; index <= 18; ++index)
|
||||
this.InsertNode(r - index);
|
||||
this.InsertNode(r);
|
||||
do
|
||||
{
|
||||
if (this.matchLength > num5)
|
||||
this.matchLength = num5;
|
||||
if (this.matchLength <= 2)
|
||||
{
|
||||
this.matchLength = 1;
|
||||
numArray1[num3++] = (int) this.textBuffer[r];
|
||||
}
|
||||
else
|
||||
{
|
||||
numArray1[0] |= num4;
|
||||
int[] numArray2 = numArray1;
|
||||
int index1 = num3;
|
||||
int num7 = index1 + 1;
|
||||
int num8 = (int) (ushort) (r - this.matchPosition - 1 >> 8 & 15) | this.matchLength - 3 << 4;
|
||||
numArray2[index1] = num8;
|
||||
int[] numArray3 = numArray1;
|
||||
int index2 = num7;
|
||||
num3 = index2 + 1;
|
||||
int num9 = (int) (ushort) (r - this.matchPosition - 1 & (int) byte.MaxValue);
|
||||
numArray3[index2] = num9;
|
||||
}
|
||||
if ((num4 >>= 1) == 0)
|
||||
{
|
||||
for (int index = 0; index < num3; ++index)
|
||||
memoryStream.WriteByte((byte) numArray1[index]);
|
||||
num1 += num3;
|
||||
numArray1[0] = 0;
|
||||
num3 = 1;
|
||||
num4 = 128;
|
||||
}
|
||||
int matchLength = this.matchLength;
|
||||
int num10;
|
||||
int num11;
|
||||
for (num10 = 0; num10 < matchLength && (num11 = inFile.ReadByte()) != -1; ++num10)
|
||||
{
|
||||
this.DeleteNode(p);
|
||||
this.textBuffer[p] = (ushort) num11;
|
||||
if (p < 17)
|
||||
this.textBuffer[p + 4096] = (ushort) num11;
|
||||
p = p + 1 & 4095;
|
||||
r = r + 1 & 4095;
|
||||
this.InsertNode(r);
|
||||
}
|
||||
while (num10++ < matchLength)
|
||||
{
|
||||
this.DeleteNode(p);
|
||||
p = p + 1 & 4095;
|
||||
r = r + 1 & 4095;
|
||||
if (--num5 != 0)
|
||||
this.InsertNode(r);
|
||||
}
|
||||
}
|
||||
while (num5 > 0);
|
||||
if (num3 > 1)
|
||||
{
|
||||
for (int index = 0; index < num3; ++index)
|
||||
memoryStream.WriteByte((byte) numArray1[index]);
|
||||
num1 += num3;
|
||||
}
|
||||
if (num1 % 4 != 0)
|
||||
{
|
||||
for (int index = 0; index < 4 - num1 % 4; ++index)
|
||||
memoryStream.WriteByte((byte) 0);
|
||||
}
|
||||
return (Stream) memoryStream;
|
||||
}
|
||||
|
||||
private void InitTree()
|
||||
{
|
||||
for (int index = 4097; index <= 4352; ++index)
|
||||
this.rightSon[index] = 4096;
|
||||
for (int index = 0; index < 4096; ++index)
|
||||
this.dad[index] = 4096;
|
||||
}
|
||||
|
||||
private void InsertNode(int r)
|
||||
{
|
||||
int num1 = 1;
|
||||
int index = 4097 + (this.textBuffer[r] != ushort.MaxValue ? (int) this.textBuffer[r] : 0);
|
||||
this.rightSon[r] = this.leftSon[r] = 4096;
|
||||
this.matchLength = 0;
|
||||
int num2;
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
if (num1 >= 0)
|
||||
{
|
||||
if (this.rightSon[index] == 4096)
|
||||
{
|
||||
this.rightSon[index] = r;
|
||||
this.dad[r] = index;
|
||||
return;
|
||||
}
|
||||
index = this.rightSon[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.leftSon[index] == 4096)
|
||||
{
|
||||
this.leftSon[index] = r;
|
||||
this.dad[r] = index;
|
||||
return;
|
||||
}
|
||||
index = this.leftSon[index];
|
||||
}
|
||||
num2 = 1;
|
||||
while (num2 < 18 && (num1 = (int) this.textBuffer[r + num2] - (int) this.textBuffer[index + num2]) == 0)
|
||||
++num2;
|
||||
}
|
||||
while (num2 <= this.matchLength);
|
||||
this.matchPosition = index;
|
||||
}
|
||||
while ((this.matchLength = num2) < 18);
|
||||
this.dad[r] = this.dad[index];
|
||||
this.leftSon[r] = this.leftSon[index];
|
||||
this.rightSon[r] = this.rightSon[index];
|
||||
this.dad[this.leftSon[index]] = r;
|
||||
this.dad[this.rightSon[index]] = r;
|
||||
if (this.rightSon[this.dad[index]] == index)
|
||||
this.rightSon[this.dad[index]] = r;
|
||||
else
|
||||
this.leftSon[this.dad[index]] = r;
|
||||
this.dad[index] = 4096;
|
||||
}
|
||||
|
||||
private void DeleteNode(int p)
|
||||
{
|
||||
if (this.dad[p] == 4096)
|
||||
return;
|
||||
int index;
|
||||
if (this.rightSon[p] == 4096)
|
||||
index = this.leftSon[p];
|
||||
else if (this.leftSon[p] == 4096)
|
||||
{
|
||||
index = this.rightSon[p];
|
||||
}
|
||||
else
|
||||
{
|
||||
index = this.leftSon[p];
|
||||
if (this.rightSon[index] != 4096)
|
||||
{
|
||||
do
|
||||
{
|
||||
index = this.rightSon[index];
|
||||
}
|
||||
while (this.rightSon[index] != 4096);
|
||||
this.rightSon[this.dad[index]] = this.leftSon[index];
|
||||
this.dad[this.leftSon[index]] = this.dad[index];
|
||||
this.leftSon[index] = this.leftSon[p];
|
||||
this.dad[this.leftSon[p]] = index;
|
||||
}
|
||||
this.rightSon[index] = this.rightSon[p];
|
||||
this.dad[this.rightSon[p]] = index;
|
||||
}
|
||||
this.dad[index] = this.dad[p];
|
||||
if (this.rightSon[this.dad[p]] == p)
|
||||
this.rightSon[this.dad[p]] = index;
|
||||
else
|
||||
this.leftSon[this.dad[p]] = index;
|
||||
this.dad[p] = 4096;
|
||||
}
|
||||
}
|
||||
}
|
19
MessageEventArgs.cs
Normal file
19
MessageEventArgs.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.MessageEventArgs
|
||||
// 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;
|
||||
|
||||
namespace libWiiSharp
|
||||
{
|
||||
public class MessageEventArgs : EventArgs
|
||||
{
|
||||
private string message;
|
||||
|
||||
public string Message => this.message;
|
||||
|
||||
public MessageEventArgs(string message) => this.message = message;
|
||||
}
|
||||
}
|
436
NusClient.cs
Normal file
436
NusClient.cs
Normal file
|
@ -0,0 +1,436 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.NusClient
|
||||
// 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.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace libWiiSharp
|
||||
{
|
||||
public class NusClient : IDisposable
|
||||
{
|
||||
private const string nusUrl = "http://nus.cdn.shop.wii.com/ccs/download/";
|
||||
private WebClient wcNus = new WebClient();
|
||||
private bool useLocalFiles;
|
||||
private bool continueWithoutTicket;
|
||||
private bool isDisposed;
|
||||
|
||||
public bool UseLocalFiles
|
||||
{
|
||||
get => this.useLocalFiles;
|
||||
set => this.useLocalFiles = value;
|
||||
}
|
||||
|
||||
public bool ContinueWithoutTicket
|
||||
{
|
||||
get => this.continueWithoutTicket;
|
||||
set => this.continueWithoutTicket = value;
|
||||
}
|
||||
|
||||
public event EventHandler<ProgressChangedEventArgs> Progress;
|
||||
|
||||
public event EventHandler<MessageEventArgs> Debug;
|
||||
|
||||
~NusClient() => this.Dispose(false);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize((object) this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && !this.isDisposed)
|
||||
this.wcNus.Dispose();
|
||||
this.isDisposed = true;
|
||||
}
|
||||
|
||||
public void DownloadTitle(
|
||||
string titleId,
|
||||
string titleVersion,
|
||||
string outputDir,
|
||||
params StoreType[] storeTypes)
|
||||
{
|
||||
if (titleId.Length != 16)
|
||||
throw new Exception("Title ID must be 16 characters long!");
|
||||
this.downloadTitle(titleId, titleVersion, outputDir, storeTypes);
|
||||
}
|
||||
|
||||
public TMD DownloadTMD(string titleId, string titleVersion) => titleId.Length == 16 ? this.downloadTmd(titleId, titleVersion) : throw new Exception("Title ID must be 16 characters long!");
|
||||
|
||||
public Ticket DownloadTicket(string titleId) => titleId.Length == 16 ? this.downloadTicket(titleId) : throw new Exception("Title ID must be 16 characters long!");
|
||||
|
||||
public byte[] DownloadSingleContent(string titleId, string titleVersion, string contentId)
|
||||
{
|
||||
if (titleId.Length != 16)
|
||||
throw new Exception("Title ID must be 16 characters long!");
|
||||
return this.downloadSingleContent(titleId, titleVersion, contentId);
|
||||
}
|
||||
|
||||
public void DownloadSingleContent(
|
||||
string titleId,
|
||||
string titleVersion,
|
||||
string contentId,
|
||||
string savePath)
|
||||
{
|
||||
if (titleId.Length != 16)
|
||||
throw new Exception("Title ID must be 16 characters long!");
|
||||
if (!Directory.Exists(Path.GetDirectoryName(savePath)))
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(savePath));
|
||||
if (System.IO.File.Exists(savePath))
|
||||
System.IO.File.Delete(savePath);
|
||||
byte[] bytes = this.downloadSingleContent(titleId, titleVersion, contentId);
|
||||
System.IO.File.WriteAllBytes(savePath, bytes);
|
||||
}
|
||||
|
||||
private byte[] downloadSingleContent(string titleId, string titleVersion, string contentId)
|
||||
{
|
||||
uint num = uint.Parse(contentId, NumberStyles.HexNumber);
|
||||
contentId = num.ToString("x8");
|
||||
this.fireDebug("Downloading Content (Content ID: {0}) of Title {1} v{2}...", (object) contentId, (object) titleId, string.IsNullOrEmpty(titleVersion) ? (object) "[Latest]" : (object) titleVersion);
|
||||
this.fireDebug(" Checking for Internet connection...");
|
||||
if (!this.CheckInet())
|
||||
{
|
||||
this.fireDebug(" Connection not found...");
|
||||
throw new Exception("You're not connected to the internet!");
|
||||
}
|
||||
this.fireProgress(0);
|
||||
string str1 = "tmd" + (string.IsNullOrEmpty(titleVersion) ? string.Empty : "." + titleVersion);
|
||||
string str2 = string.Format("{0}{1}/", (object) "http://nus.cdn.shop.wii.com/ccs/download/", (object) titleId);
|
||||
string empty = string.Empty;
|
||||
int contentIndex = 0;
|
||||
this.fireDebug(" Downloading TMD...");
|
||||
byte[] tmdFile = this.wcNus.DownloadData(str2 + str1);
|
||||
this.fireDebug(" Parsing TMD...");
|
||||
TMD tmd = TMD.Load(tmdFile);
|
||||
this.fireProgress(20);
|
||||
this.fireDebug(" Looking for Content ID {0} in TMD...", (object) contentId);
|
||||
bool flag = false;
|
||||
for (int index = 0; index < tmd.Contents.Length; ++index)
|
||||
{
|
||||
if ((int) tmd.Contents[index].ContentID == (int) num)
|
||||
{
|
||||
this.fireDebug(" Content ID {0} found in TMD...", (object) contentId);
|
||||
flag = true;
|
||||
empty = tmd.Contents[index].ContentID.ToString("x8");
|
||||
contentIndex = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
this.fireDebug(" Content ID {0} wasn't found in TMD...", (object) contentId);
|
||||
throw new Exception("Content ID wasn't found in the TMD!");
|
||||
}
|
||||
if (!File.Exists("cetk"))
|
||||
{
|
||||
fireDebug(" Downloading Ticket...");
|
||||
byte[] tikArray = wcNus.DownloadData(str2 + "cetk");
|
||||
Console.WriteLine("Downloading");
|
||||
}
|
||||
Console.WriteLine("Continuing");
|
||||
this.fireDebug("Parsing Ticket...");
|
||||
Ticket tik = Ticket.Load("cetk");
|
||||
this.fireProgress(40);
|
||||
this.fireDebug(" Downloading Content... ({0} bytes)", (object) tmd.Contents[contentIndex].Size);
|
||||
byte[] content = this.wcNus.DownloadData(str2 + empty);
|
||||
this.fireProgress(80);
|
||||
this.fireDebug(" Decrypting Content...");
|
||||
byte[] array = this.decryptContent(content, contentIndex, tik, tmd);
|
||||
Array.Resize<byte>(ref array, (int) tmd.Contents[contentIndex].Size);
|
||||
if (!Shared.CompareByteArrays(SHA1.Create().ComputeHash(array), tmd.Contents[contentIndex].Hash))
|
||||
{
|
||||
this.fireDebug("/!\\ /!\\ /!\\ Hashes do not match /!\\ /!\\ /!\\");
|
||||
throw new Exception("Hashes do not match!");
|
||||
}
|
||||
this.fireProgress(100);
|
||||
this.fireDebug("Downloading Content (Content ID: {0}) of Title {1} v{2} Finished...", (object) contentId, (object) titleId, string.IsNullOrEmpty(titleVersion) ? (object) "[Latest]" : (object) titleVersion);
|
||||
return array;
|
||||
}
|
||||
|
||||
private Ticket downloadTicket(string titleId)
|
||||
{
|
||||
if (!CheckInet())
|
||||
throw new Exception("You're not connected to the internet!");
|
||||
|
||||
string titleUrl = string.Format("{0}{1}/", nusUrl, titleId);
|
||||
byte[] tikArray = wcNus.DownloadData(titleUrl + "cetk");
|
||||
|
||||
return Ticket.Load(tikArray);
|
||||
}
|
||||
|
||||
private TMD downloadTmd(string titleId, string titleVersion)
|
||||
{
|
||||
if (!this.CheckInet())
|
||||
throw new Exception("You're not connected to the internet!");
|
||||
return TMD.Load(this.wcNus.DownloadData(string.Format("{0}{1}/", (object) "http://nus.cdn.shop.wii.com/ccs/download/", (object) titleId) + ("tmd" + (string.IsNullOrEmpty(titleVersion) ? string.Empty : "." + titleVersion))));
|
||||
}
|
||||
|
||||
private void downloadTitle(
|
||||
string titleId,
|
||||
string titleVersion,
|
||||
string outputDir,
|
||||
StoreType[] storeTypes)
|
||||
{
|
||||
this.fireDebug("Downloading Title {0} v{1}...", (object) titleId, string.IsNullOrEmpty(titleVersion) ? (object) "[Latest]" : (object) titleVersion);
|
||||
if (storeTypes.Length < 1)
|
||||
{
|
||||
this.fireDebug(" No store types were defined...");
|
||||
throw new Exception("You must at least define one store type!");
|
||||
}
|
||||
string str1 = string.Format("{0}{1}/", (object) "http://nus.cdn.shop.wii.com/ccs/download/", (object) titleId);
|
||||
bool flag1 = false;
|
||||
bool flag2 = false;
|
||||
bool flag3 = false;
|
||||
this.fireProgress(0);
|
||||
for (int index = 0; index < storeTypes.Length; ++index)
|
||||
{
|
||||
switch (storeTypes[index])
|
||||
{
|
||||
case StoreType.EncryptedContent:
|
||||
this.fireDebug(" -> Storing Encrypted Content...");
|
||||
flag1 = true;
|
||||
break;
|
||||
case StoreType.DecryptedContent:
|
||||
this.fireDebug(" -> Storing Decrypted Content...");
|
||||
flag2 = true;
|
||||
break;
|
||||
case StoreType.WAD:
|
||||
this.fireDebug(" -> Storing WAD...");
|
||||
flag3 = true;
|
||||
break;
|
||||
case StoreType.All:
|
||||
this.fireDebug(" -> Storing Decrypted Content...");
|
||||
this.fireDebug(" -> Storing Encrypted Content...");
|
||||
this.fireDebug(" -> Storing WAD...");
|
||||
flag2 = true;
|
||||
flag1 = true;
|
||||
flag3 = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.fireDebug(" Checking for Internet connection...");
|
||||
if (!this.CheckInet())
|
||||
{
|
||||
this.fireDebug(" Connection not found...");
|
||||
throw new Exception("You're not connected to the internet!");
|
||||
}
|
||||
if ((int) outputDir[outputDir.Length - 1] != (int) Path.DirectorySeparatorChar)
|
||||
outputDir += Path.DirectorySeparatorChar.ToString();
|
||||
if (!Directory.Exists(outputDir))
|
||||
Directory.CreateDirectory(outputDir);
|
||||
string str2 = "tmd" + (string.IsNullOrEmpty(titleVersion) ? string.Empty : "." + titleVersion);
|
||||
this.fireDebug(" Downloading TMD...");
|
||||
try
|
||||
{
|
||||
this.wcNus.DownloadFile(str1 + str2, outputDir + str2);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.fireDebug(" Downloading TMD Failed...");
|
||||
throw new Exception("Downloading TMD Failed:\n" + ex.Message);
|
||||
}
|
||||
|
||||
if (!File.Exists(outputDir + "cetk"))
|
||||
{
|
||||
//Download cetk
|
||||
fireDebug(" Downloading Ticket...");
|
||||
try
|
||||
{
|
||||
wcNus.DownloadFile(string.Format("{0}{1}/", nusUrl, titleId) + "cetk", outputDir + "cetk");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (!continueWithoutTicket || !flag1)
|
||||
{
|
||||
fireDebug(" Downloading Ticket Failed...");
|
||||
throw new Exception("CETK Doesn't Exist and Downloading Ticket Failed:\n" + ex.Message);
|
||||
}
|
||||
|
||||
flag2 = false;
|
||||
flag3 = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.fireProgress(10);
|
||||
this.fireDebug(" Parsing TMD...");
|
||||
TMD tmd = TMD.Load(outputDir + str2);
|
||||
if (string.IsNullOrEmpty(titleVersion))
|
||||
this.fireDebug(" -> Title Version: {0}", (object) tmd.TitleVersion);
|
||||
this.fireDebug(" -> {0} Contents", (object) tmd.NumOfContents);
|
||||
this.fireDebug(" Parsing Ticket...");
|
||||
Ticket tik = Ticket.Load(outputDir + "cetk");
|
||||
string[] strArray1 = new string[(int) tmd.NumOfContents];
|
||||
uint contentId;
|
||||
for (int index1 = 0; index1 < (int) tmd.NumOfContents; ++index1)
|
||||
{
|
||||
this.fireDebug(" Downloading Content #{0} of {1}... ({2} bytes)", (object) (index1 + 1), (object) tmd.NumOfContents, (object) tmd.Contents[index1].Size);
|
||||
this.fireProgress((index1 + 1) * 60 / (int) tmd.NumOfContents + 10);
|
||||
if (this.useLocalFiles)
|
||||
{
|
||||
string str3 = outputDir;
|
||||
contentId = tmd.Contents[index1].ContentID;
|
||||
string str4 = contentId.ToString("x8");
|
||||
if (System.IO.File.Exists(str3 + str4))
|
||||
{
|
||||
this.fireDebug(" Using Local File, Skipping...");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
WebClient wcNus = this.wcNus;
|
||||
string str3 = str1;
|
||||
contentId = tmd.Contents[index1].ContentID;
|
||||
string str4 = contentId.ToString("x8");
|
||||
string address = str3 + str4;
|
||||
string str5 = outputDir;
|
||||
contentId = tmd.Contents[index1].ContentID;
|
||||
string str6 = contentId.ToString("x8");
|
||||
string fileName = str5 + str6;
|
||||
wcNus.DownloadFile(address, fileName);
|
||||
string[] strArray2 = strArray1;
|
||||
int index2 = index1;
|
||||
contentId = tmd.Contents[index1].ContentID;
|
||||
string str7 = contentId.ToString("x8");
|
||||
strArray2[index2] = str7;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.fireDebug(" Downloading Content #{0} of {1} failed...", (object) (index1 + 1), (object) tmd.NumOfContents);
|
||||
throw new Exception("Downloading Content Failed:\n" + ex.Message);
|
||||
}
|
||||
}
|
||||
if (flag2 | flag3)
|
||||
{
|
||||
SHA1 shA1 = SHA1.Create();
|
||||
for (int contentIndex = 0; contentIndex < (int) tmd.NumOfContents; ++contentIndex)
|
||||
{
|
||||
this.fireDebug(" Decrypting Content #{0} of {1}...", (object) (contentIndex + 1), (object) tmd.NumOfContents);
|
||||
this.fireProgress((contentIndex + 1) * 20 / (int) tmd.NumOfContents + 75);
|
||||
string str3 = outputDir;
|
||||
contentId = tmd.Contents[contentIndex].ContentID;
|
||||
string str4 = contentId.ToString("x8");
|
||||
byte[] array = this.decryptContent(System.IO.File.ReadAllBytes(str3 + str4), contentIndex, tik, tmd);
|
||||
Array.Resize<byte>(ref array, (int) tmd.Contents[contentIndex].Size);
|
||||
if (!Shared.CompareByteArrays(shA1.ComputeHash(array), tmd.Contents[contentIndex].Hash))
|
||||
{
|
||||
this.fireDebug("/!\\ /!\\ /!\\ Hashes do not match /!\\ /!\\ /!\\");
|
||||
throw new Exception(string.Format("Content #{0}: Hashes do not match!", (object) contentIndex));
|
||||
}
|
||||
string str5 = outputDir;
|
||||
contentId = tmd.Contents[contentIndex].ContentID;
|
||||
string str6 = contentId.ToString("x8");
|
||||
System.IO.File.WriteAllBytes(str5 + str6 + ".app", array);
|
||||
}
|
||||
shA1.Clear();
|
||||
}
|
||||
if (flag3)
|
||||
{
|
||||
this.fireDebug(" Building Certificate Chain...");
|
||||
CertificateChain cert = CertificateChain.FromTikTmd(outputDir + "cetk", outputDir + str2);
|
||||
byte[][] contents = new byte[(int) tmd.NumOfContents][];
|
||||
for (int index1 = 0; index1 < (int) tmd.NumOfContents; ++index1)
|
||||
{
|
||||
byte[][] numArray1 = contents;
|
||||
int index2 = index1;
|
||||
string str3 = outputDir;
|
||||
contentId = tmd.Contents[index1].ContentID;
|
||||
string str4 = contentId.ToString("x8");
|
||||
byte[] numArray2 = System.IO.File.ReadAllBytes(str3 + str4 + ".app");
|
||||
numArray1[index2] = numArray2;
|
||||
}
|
||||
this.fireDebug(" Creating WAD...");
|
||||
WAD.Create(cert, tik, tmd, contents).Save(outputDir + tmd.TitleID.ToString("x16") + "v" + tmd.TitleVersion.ToString() + ".wad");
|
||||
}
|
||||
if (!flag1)
|
||||
{
|
||||
this.fireDebug(" Deleting Encrypted Contents...");
|
||||
for (int index = 0; index < strArray1.Length; ++index)
|
||||
{
|
||||
if (System.IO.File.Exists(outputDir + strArray1[index]))
|
||||
System.IO.File.Delete(outputDir + strArray1[index]);
|
||||
}
|
||||
}
|
||||
if (flag3 && !flag2)
|
||||
{
|
||||
this.fireDebug(" Deleting Decrypted Contents...");
|
||||
for (int index = 0; index < strArray1.Length; ++index)
|
||||
{
|
||||
if (System.IO.File.Exists(outputDir + strArray1[index] + ".app"))
|
||||
System.IO.File.Delete(outputDir + strArray1[index] + ".app");
|
||||
}
|
||||
}
|
||||
if (!flag2 && !flag1)
|
||||
{
|
||||
this.fireDebug(" Deleting TMD and Ticket...");
|
||||
System.IO.File.Delete(outputDir + str2);
|
||||
System.IO.File.Delete(outputDir + "cetk");
|
||||
}
|
||||
this.fireDebug("Downloading Title {0} v{1} Finished...", (object) titleId, string.IsNullOrEmpty(titleVersion) ? (object) "[Latest]" : (object) titleVersion);
|
||||
this.fireProgress(100);
|
||||
}
|
||||
|
||||
private byte[] decryptContent(byte[] content, int contentIndex, Ticket tik, TMD tmd)
|
||||
{
|
||||
Array.Resize<byte>(ref content, Shared.AddPadding(content.Length, 16));
|
||||
byte[] titleKey = tik.TitleKey;
|
||||
byte[] numArray = new byte[16];
|
||||
byte[] bytes = BitConverter.GetBytes(tmd.Contents[contentIndex].Index);
|
||||
numArray[0] = bytes[1];
|
||||
numArray[1] = bytes[0];
|
||||
RijndaelManaged rijndaelManaged = new RijndaelManaged();
|
||||
rijndaelManaged.Mode = CipherMode.CBC;
|
||||
rijndaelManaged.Padding = PaddingMode.None;
|
||||
rijndaelManaged.KeySize = 128;
|
||||
rijndaelManaged.BlockSize = 128;
|
||||
rijndaelManaged.Key = titleKey;
|
||||
rijndaelManaged.IV = numArray;
|
||||
ICryptoTransform decryptor = rijndaelManaged.CreateDecryptor();
|
||||
MemoryStream memoryStream = new MemoryStream(content);
|
||||
CryptoStream cryptoStream = new CryptoStream((Stream) memoryStream, decryptor, CryptoStreamMode.Read);
|
||||
byte[] buffer = new byte[content.Length];
|
||||
cryptoStream.Read(buffer, 0, buffer.Length);
|
||||
cryptoStream.Dispose();
|
||||
memoryStream.Dispose();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private bool CheckInet()
|
||||
{
|
||||
try
|
||||
{
|
||||
Dns.GetHostEntry("www.google.com");
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void fireDebug(string debugMessage, params object[] args)
|
||||
{
|
||||
EventHandler<MessageEventArgs> debug = this.Debug;
|
||||
if (debug == null)
|
||||
return;
|
||||
debug(new object(), new MessageEventArgs(string.Format(debugMessage, args)));
|
||||
}
|
||||
|
||||
private void fireProgress(int progressPercentage)
|
||||
{
|
||||
EventHandler<ProgressChangedEventArgs> progress = this.Progress;
|
||||
if (progress == null)
|
||||
return;
|
||||
progress(new object(), new ProgressChangedEventArgs(progressPercentage, (object) string.Empty));
|
||||
}
|
||||
}
|
||||
}
|
15
Protocol.cs
Normal file
15
Protocol.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
// 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,
|
||||
}
|
||||
}
|
45
Readme_libWiiSharp.txt
Normal file
45
Readme_libWiiSharp.txt
Normal file
|
@ -0,0 +1,45 @@
|
|||
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
libWiiSharp
|
||||
by Leathl
|
||||
Modified by TheShadowEevee
|
||||
https://github.com/TheShadowEevee/libWiiSharp
|
||||
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
|
||||
|
||||
Info:
|
||||
-=-=-
|
||||
|
||||
libWiiSharp is a Wii related .NET (2.0+) library.
|
||||
It can be used with any .NET language to easily develop Wii related applications.
|
||||
|
||||
All public functions are documented and most should be pretty self-explanatory.
|
||||
There are also some example applications that use libWiiSharp included.
|
||||
|
||||
If you want to contribute, you can do so at the github repo.
|
||||
|
||||
|
||||
|
||||
Thanks:
|
||||
-=-=-=-
|
||||
|
||||
- Xuzz, SquidMan, megazig, Matt_P, Omega and The Lemon Man for Wii.py
|
||||
- megazig for his bns conversion code (bns.py)
|
||||
- SquidMan for Zetsubou
|
||||
- Arikado and Lunatik for Dop-Mii
|
||||
- Andre Perrot for gbalzss
|
||||
|
||||
|
||||
|
||||
License:
|
||||
-=-=-=-=-
|
||||
|
||||
libWiiSharp is released under the terms of the GNU General Public License v3.
|
||||
See "License_libWiiSharp.txt" for more information.
|
||||
|
||||
|
||||
|
||||
Changelog:
|
||||
-=-=-=-=-=-
|
||||
|
||||
See "Changelog_libWiiSharp.txt"
|
16
Region.cs
Normal file
16
Region.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.Region
|
||||
// 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 Region : ushort
|
||||
{
|
||||
Japan,
|
||||
USA,
|
||||
Europe,
|
||||
Free,
|
||||
}
|
||||
}
|
148
Shared.cs
Normal file
148
Shared.cs
Normal file
|
@ -0,0 +1,148 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.Shared
|
||||
// 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.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
|
||||
namespace libWiiSharp
|
||||
{
|
||||
public static class Shared
|
||||
{
|
||||
public static string[] MergeStringArrays(string[] a, string[] b)
|
||||
{
|
||||
List<string> stringList = new List<string>((IEnumerable<string>) a);
|
||||
foreach (string str in b)
|
||||
{
|
||||
if (!stringList.Contains(str))
|
||||
stringList.Add(str);
|
||||
}
|
||||
stringList.Sort();
|
||||
return stringList.ToArray();
|
||||
}
|
||||
|
||||
public static bool CompareByteArrays(
|
||||
byte[] first,
|
||||
int firstIndex,
|
||||
byte[] second,
|
||||
int secondIndex,
|
||||
int length)
|
||||
{
|
||||
if (first.Length < length || second.Length < length)
|
||||
return false;
|
||||
for (int index = 0; index < length; ++index)
|
||||
{
|
||||
if ((int) first[firstIndex + index] != (int) second[secondIndex + index])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool CompareByteArrays(byte[] first, byte[] second)
|
||||
{
|
||||
if (first.Length != second.Length)
|
||||
return false;
|
||||
for (int index = 0; index < first.Length; ++index)
|
||||
{
|
||||
if ((int) first[index] != (int) second[index])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static string ByteArrayToString(byte[] byteArray, char separator = ' ')
|
||||
{
|
||||
string str = string.Empty;
|
||||
foreach (byte num in byteArray)
|
||||
str = str + num.ToString("x2").ToUpper() + separator.ToString();
|
||||
return str.Remove(str.Length - 1);
|
||||
}
|
||||
|
||||
public static byte[] HexStringToByteArray(string hexString)
|
||||
{
|
||||
byte[] numArray = new byte[hexString.Length / 2];
|
||||
for (int index = 0; index < hexString.Length / 2; ++index)
|
||||
numArray[index] = byte.Parse(hexString.Substring(index * 2, 2), NumberStyles.HexNumber);
|
||||
return numArray;
|
||||
}
|
||||
|
||||
public static int CountCharsInString(string theString, char theChar)
|
||||
{
|
||||
int num1 = 0;
|
||||
foreach (int num2 in theString)
|
||||
{
|
||||
if (num2 == (int) theChar)
|
||||
++num1;
|
||||
}
|
||||
return num1;
|
||||
}
|
||||
|
||||
public static long AddPadding(long value) => Shared.AddPadding(value, 64);
|
||||
|
||||
public static long AddPadding(long value, int padding)
|
||||
{
|
||||
if (value % (long) padding != 0L)
|
||||
value += (long) padding - value % (long) padding;
|
||||
return value;
|
||||
}
|
||||
|
||||
public static int AddPadding(int value) => Shared.AddPadding(value, 64);
|
||||
|
||||
public static int AddPadding(int value, int padding)
|
||||
{
|
||||
if (value % padding != 0)
|
||||
value += padding - value % padding;
|
||||
return value;
|
||||
}
|
||||
|
||||
public static ushort Swap(ushort value) => (ushort) IPAddress.HostToNetworkOrder((short) value);
|
||||
|
||||
public static uint Swap(uint value) => (uint) IPAddress.HostToNetworkOrder((int) value);
|
||||
|
||||
public static ulong Swap(ulong value) => (ulong) IPAddress.HostToNetworkOrder((long) value);
|
||||
|
||||
public static byte[] UShortArrayToByteArray(ushort[] array)
|
||||
{
|
||||
List<byte> byteList = new List<byte>();
|
||||
foreach (ushort num in array)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(num);
|
||||
byteList.AddRange((IEnumerable<byte>) bytes);
|
||||
}
|
||||
return byteList.ToArray();
|
||||
}
|
||||
|
||||
public static byte[] UIntArrayToByteArray(uint[] array)
|
||||
{
|
||||
List<byte> byteList = new List<byte>();
|
||||
foreach (uint num in array)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(num);
|
||||
byteList.AddRange((IEnumerable<byte>) bytes);
|
||||
}
|
||||
return byteList.ToArray();
|
||||
}
|
||||
|
||||
public static uint[] ByteArrayToUIntArray(byte[] array)
|
||||
{
|
||||
uint[] numArray = new uint[array.Length / 4];
|
||||
int num = 0;
|
||||
for (int startIndex = 0; startIndex < array.Length; startIndex += 4)
|
||||
numArray[num++] = BitConverter.ToUInt32(array, startIndex);
|
||||
return numArray;
|
||||
}
|
||||
|
||||
public static ushort[] ByteArrayToUShortArray(byte[] array)
|
||||
{
|
||||
ushort[] numArray = new ushort[array.Length / 2];
|
||||
int num = 0;
|
||||
for (int startIndex = 0; startIndex < array.Length; startIndex += 2)
|
||||
numArray[num++] = BitConverter.ToUInt16(array, startIndex);
|
||||
return numArray;
|
||||
}
|
||||
}
|
||||
}
|
16
StoreType.cs
Normal file
16
StoreType.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.StoreType
|
||||
// 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 StoreType
|
||||
{
|
||||
EncryptedContent,
|
||||
DecryptedContent,
|
||||
WAD,
|
||||
All,
|
||||
}
|
||||
}
|
521
TMD.cs
Normal file
521
TMD.cs
Normal file
|
@ -0,0 +1,521 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.TMD
|
||||
// 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.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace libWiiSharp
|
||||
{
|
||||
public class TMD : IDisposable
|
||||
{
|
||||
private bool fakeSign;
|
||||
private bool sortContents;
|
||||
private uint signatureExponent = 65537;
|
||||
private byte[] signature = new byte[256];
|
||||
private byte[] padding = new byte[60];
|
||||
private byte[] issuer = new byte[64];
|
||||
private byte version;
|
||||
private byte caCrlVersion;
|
||||
private byte signerCrlVersion;
|
||||
private byte paddingByte;
|
||||
private ulong startupIos;
|
||||
private ulong titleId;
|
||||
private uint titleType;
|
||||
private ushort groupId;
|
||||
private ushort padding2;
|
||||
private ushort region;
|
||||
private byte[] reserved = new byte[58];
|
||||
private uint accessRights;
|
||||
private ushort titleVersion;
|
||||
private ushort numOfContents;
|
||||
private ushort bootIndex;
|
||||
private ushort padding3;
|
||||
private List<TMD_Content> contents;
|
||||
private bool isDisposed;
|
||||
|
||||
public Region Region
|
||||
{
|
||||
get => (Region) this.region;
|
||||
set => this.region = (ushort) value;
|
||||
}
|
||||
|
||||
public ulong StartupIOS
|
||||
{
|
||||
get => this.startupIos;
|
||||
set => this.startupIos = value;
|
||||
}
|
||||
|
||||
public ulong TitleID
|
||||
{
|
||||
get => this.titleId;
|
||||
set => this.titleId = value;
|
||||
}
|
||||
|
||||
public ushort TitleVersion
|
||||
{
|
||||
get => this.titleVersion;
|
||||
set => this.titleVersion = value;
|
||||
}
|
||||
|
||||
public ushort NumOfContents => this.numOfContents;
|
||||
|
||||
public ushort BootIndex
|
||||
{
|
||||
get => this.bootIndex;
|
||||
set
|
||||
{
|
||||
if ((int) value > (int) this.numOfContents)
|
||||
return;
|
||||
this.bootIndex = value;
|
||||
}
|
||||
}
|
||||
|
||||
public TMD_Content[] Contents
|
||||
{
|
||||
get => this.contents.ToArray();
|
||||
set
|
||||
{
|
||||
this.contents = new List<TMD_Content>((IEnumerable<TMD_Content>) value);
|
||||
this.numOfContents = (ushort) value.Length;
|
||||
}
|
||||
}
|
||||
|
||||
public bool FakeSign
|
||||
{
|
||||
get => this.fakeSign;
|
||||
set => this.fakeSign = value;
|
||||
}
|
||||
|
||||
public bool SortContents
|
||||
{
|
||||
get => this.sortContents;
|
||||
set => this.sortContents = true;
|
||||
}
|
||||
|
||||
public event EventHandler<MessageEventArgs> Debug;
|
||||
|
||||
~TMD() => this.Dispose(false);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize((object) this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && !this.isDisposed)
|
||||
{
|
||||
this.signature = (byte[]) null;
|
||||
this.padding = (byte[]) null;
|
||||
this.issuer = (byte[]) null;
|
||||
this.reserved = (byte[]) null;
|
||||
this.contents.Clear();
|
||||
this.contents = (List<TMD_Content>) null;
|
||||
}
|
||||
this.isDisposed = true;
|
||||
}
|
||||
|
||||
public static TMD Load(string pathToTmd) => TMD.Load(File.ReadAllBytes(pathToTmd));
|
||||
|
||||
public static TMD Load(byte[] tmdFile)
|
||||
{
|
||||
TMD tmd = new TMD();
|
||||
MemoryStream memoryStream = new MemoryStream(tmdFile);
|
||||
try
|
||||
{
|
||||
tmd.parseTmd((Stream) memoryStream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
memoryStream.Dispose();
|
||||
throw;
|
||||
}
|
||||
memoryStream.Dispose();
|
||||
return tmd;
|
||||
}
|
||||
|
||||
public static TMD Load(Stream tmd)
|
||||
{
|
||||
TMD tmd1 = new TMD();
|
||||
tmd1.parseTmd(tmd);
|
||||
return tmd1;
|
||||
}
|
||||
|
||||
public void LoadFile(string pathToTmd) => this.LoadFile(File.ReadAllBytes(pathToTmd));
|
||||
|
||||
public void LoadFile(byte[] tmdFile)
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream(tmdFile);
|
||||
try
|
||||
{
|
||||
this.parseTmd((Stream) memoryStream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
memoryStream.Dispose();
|
||||
throw;
|
||||
}
|
||||
memoryStream.Dispose();
|
||||
}
|
||||
|
||||
public void LoadFile(Stream tmd) => this.parseTmd(tmd);
|
||||
|
||||
public void Save(string savePath) => this.Save(savePath, false);
|
||||
|
||||
public void Save(string savePath, bool fakeSign)
|
||||
{
|
||||
if (fakeSign)
|
||||
this.fakeSign = true;
|
||||
if (File.Exists(savePath))
|
||||
File.Delete(savePath);
|
||||
using (FileStream fileStream = new FileStream(savePath, FileMode.Create))
|
||||
this.writeToStream((Stream) fileStream);
|
||||
}
|
||||
|
||||
public MemoryStream ToMemoryStream() => this.ToMemoryStream(false);
|
||||
|
||||
public MemoryStream ToMemoryStream(bool fakeSign)
|
||||
{
|
||||
if (fakeSign)
|
||||
this.fakeSign = true;
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
try
|
||||
{
|
||||
this.writeToStream((Stream) memoryStream);
|
||||
return memoryStream;
|
||||
}
|
||||
catch
|
||||
{
|
||||
memoryStream.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] ToByteArray() => this.ToByteArray(false);
|
||||
|
||||
public byte[] ToByteArray(bool fakeSign)
|
||||
{
|
||||
if (fakeSign)
|
||||
this.fakeSign = true;
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
try
|
||||
{
|
||||
this.writeToStream((Stream) memoryStream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
memoryStream.Dispose();
|
||||
throw;
|
||||
}
|
||||
byte[] array = memoryStream.ToArray();
|
||||
memoryStream.Dispose();
|
||||
return array;
|
||||
}
|
||||
|
||||
public void UpdateContents(string contentDir)
|
||||
{
|
||||
bool flag = true;
|
||||
char directorySeparatorChar;
|
||||
for (int index = 0; index < this.contents.Count; ++index)
|
||||
{
|
||||
string str1 = contentDir;
|
||||
directorySeparatorChar = Path.DirectorySeparatorChar;
|
||||
string str2 = directorySeparatorChar.ToString();
|
||||
string str3 = this.contents[index].ContentID.ToString("x8");
|
||||
if (!File.Exists(str1 + str2 + str3 + ".app"))
|
||||
{
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
for (int index = 0; index < this.contents.Count; ++index)
|
||||
{
|
||||
string str1 = contentDir;
|
||||
directorySeparatorChar = Path.DirectorySeparatorChar;
|
||||
string str2 = directorySeparatorChar.ToString();
|
||||
string str3 = this.contents[index].ContentID.ToString("x8");
|
||||
if (!File.Exists(str1 + str2 + str3 + ".app"))
|
||||
throw new Exception("Couldn't find all content files!");
|
||||
}
|
||||
}
|
||||
byte[][] conts = new byte[this.contents.Count][];
|
||||
for (int index = 0; index < this.contents.Count; ++index)
|
||||
{
|
||||
string str1 = contentDir;
|
||||
directorySeparatorChar = Path.DirectorySeparatorChar;
|
||||
string str2 = directorySeparatorChar.ToString();
|
||||
string str3 = flag ? this.contents[index].ContentID.ToString("x8") : this.contents[index].Index.ToString("x8");
|
||||
string path = str1 + str2 + str3 + ".app";
|
||||
conts[index] = File.ReadAllBytes(path);
|
||||
}
|
||||
this.updateContents(conts);
|
||||
}
|
||||
|
||||
public void UpdateContents(byte[][] contents) => this.updateContents(contents);
|
||||
|
||||
public string GetUpperTitleID()
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(Shared.Swap((uint) this.titleId));
|
||||
return new string(new char[4]
|
||||
{
|
||||
(char) bytes[0],
|
||||
(char) bytes[1],
|
||||
(char) bytes[2],
|
||||
(char) bytes[3]
|
||||
});
|
||||
}
|
||||
|
||||
public string GetNandBlocks() => this.calculateNandBlocks();
|
||||
|
||||
public void AddContent(TMD_Content content)
|
||||
{
|
||||
this.contents.Add(content);
|
||||
this.numOfContents = (ushort) this.contents.Count;
|
||||
}
|
||||
|
||||
public void RemoveContent(int contentIndex)
|
||||
{
|
||||
for (int index = 0; index < (int) this.numOfContents; ++index)
|
||||
{
|
||||
if ((int) this.contents[index].Index == contentIndex)
|
||||
{
|
||||
this.contents.RemoveAt(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.numOfContents = (ushort) this.contents.Count;
|
||||
}
|
||||
|
||||
public void RemoveContentByID(int contentId)
|
||||
{
|
||||
for (int index = 0; index < (int) this.numOfContents; ++index)
|
||||
{
|
||||
if ((long) this.contents[index].ContentID == (long) contentId)
|
||||
{
|
||||
this.contents.RemoveAt(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.numOfContents = (ushort) this.contents.Count;
|
||||
}
|
||||
|
||||
public ContentIndices[] GetSortedContentList()
|
||||
{
|
||||
List<ContentIndices> contentIndicesList = new List<ContentIndices>();
|
||||
for (int index = 0; index < this.contents.Count; ++index)
|
||||
contentIndicesList.Add(new ContentIndices(index, (int) this.contents[index].Index));
|
||||
if (this.sortContents)
|
||||
contentIndicesList.Sort();
|
||||
return contentIndicesList.ToArray();
|
||||
}
|
||||
|
||||
private void writeToStream(Stream writeStream)
|
||||
{
|
||||
this.fireDebug("Writing TMD...");
|
||||
if (this.fakeSign)
|
||||
{
|
||||
this.fireDebug(" Clearing Signature...");
|
||||
this.signature = new byte[256];
|
||||
}
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
memoryStream.Seek(0L, SeekOrigin.Begin);
|
||||
this.fireDebug(" Writing Signature Exponent... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.signatureExponent)), 0, 4);
|
||||
this.fireDebug(" Writing Signature... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(this.signature, 0, this.signature.Length);
|
||||
this.fireDebug(" Writing Padding... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(this.padding, 0, this.padding.Length);
|
||||
this.fireDebug(" Writing Issuer... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(this.issuer, 0, this.issuer.Length);
|
||||
this.fireDebug(" Writing Version... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.WriteByte(this.version);
|
||||
this.fireDebug(" Writing CA Crl Version... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.WriteByte(this.caCrlVersion);
|
||||
this.fireDebug(" Writing Signer Crl Version... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.WriteByte(this.signerCrlVersion);
|
||||
this.fireDebug(" Writing Padding Byte... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.WriteByte(this.paddingByte);
|
||||
this.fireDebug(" Writing Startup IOS... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.startupIos)), 0, 8);
|
||||
this.fireDebug(" Writing Title ID... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.titleId)), 0, 8);
|
||||
this.fireDebug(" Writing Title Type... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.titleType)), 0, 4);
|
||||
this.fireDebug(" Writing Group ID... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.groupId)), 0, 2);
|
||||
this.fireDebug(" Writing Padding2... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.padding2)), 0, 2);
|
||||
this.fireDebug(" Writing Region... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.region)), 0, 2);
|
||||
this.fireDebug(" Writing Reserved... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(this.reserved, 0, this.reserved.Length);
|
||||
this.fireDebug(" Writing Access Rights... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.accessRights)), 0, 4);
|
||||
this.fireDebug(" Writing Title Version... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.titleVersion)), 0, 2);
|
||||
this.fireDebug(" Writing NumOfContents... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.numOfContents)), 0, 2);
|
||||
this.fireDebug(" Writing Boot Index... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.bootIndex)), 0, 2);
|
||||
this.fireDebug(" Writing Padding3... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.padding3)), 0, 2);
|
||||
List<ContentIndices> contentIndicesList = new List<ContentIndices>();
|
||||
for (int index = 0; index < this.contents.Count; ++index)
|
||||
contentIndicesList.Add(new ContentIndices(index, (int) this.contents[index].Index));
|
||||
if (this.sortContents)
|
||||
contentIndicesList.Sort();
|
||||
for (int index = 0; index < contentIndicesList.Count; ++index)
|
||||
{
|
||||
this.fireDebug(" Writing Content #{1} of {2}... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper().ToUpper(), (object) (index + 1), (object) this.numOfContents);
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.contents[contentIndicesList[index].Index].ContentID)), 0, 4);
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.contents[contentIndicesList[index].Index].Index)), 0, 2);
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap((ushort) this.contents[contentIndicesList[index].Index].Type)), 0, 2);
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.contents[contentIndicesList[index].Index].Size)), 0, 8);
|
||||
memoryStream.Write(this.contents[contentIndicesList[index].Index].Hash, 0, this.contents[contentIndicesList[index].Index].Hash.Length);
|
||||
}
|
||||
byte[] array = memoryStream.ToArray();
|
||||
memoryStream.Dispose();
|
||||
if (this.fakeSign)
|
||||
{
|
||||
this.fireDebug(" Fakesigning TMD...");
|
||||
byte[] numArray = new byte[20];
|
||||
SHA1 shA1 = SHA1.Create();
|
||||
for (ushort index = 0; index < ushort.MaxValue; ++index)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(index);
|
||||
array[482] = bytes[1];
|
||||
array[483] = bytes[0];
|
||||
if (shA1.ComputeHash(array)[0] == (byte) 0)
|
||||
{
|
||||
this.fireDebug(" -> Signed ({0})", (object) index);
|
||||
break;
|
||||
}
|
||||
if (index == (ushort) 65534)
|
||||
{
|
||||
this.fireDebug(" -> Signing Failed...");
|
||||
throw new Exception("Fakesigning failed...");
|
||||
}
|
||||
}
|
||||
shA1.Clear();
|
||||
}
|
||||
writeStream.Seek(0L, SeekOrigin.Begin);
|
||||
writeStream.Write(array, 0, array.Length);
|
||||
this.fireDebug("Writing TMD Finished...");
|
||||
}
|
||||
|
||||
private void updateContents(byte[][] conts)
|
||||
{
|
||||
SHA1 shA1 = SHA1.Create();
|
||||
for (int index = 0; index < this.contents.Count; ++index)
|
||||
{
|
||||
this.contents[index].Size = (ulong) conts[index].Length;
|
||||
this.contents[index].Hash = shA1.ComputeHash(conts[index]);
|
||||
}
|
||||
shA1.Clear();
|
||||
}
|
||||
|
||||
private void parseTmd(Stream tmdFile)
|
||||
{
|
||||
this.fireDebug("Pasing TMD...");
|
||||
tmdFile.Seek(0L, SeekOrigin.Begin);
|
||||
byte[] buffer = new byte[8];
|
||||
this.fireDebug(" Reading Signature Exponent... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
tmdFile.Read(buffer, 0, 4);
|
||||
this.signatureExponent = Shared.Swap(BitConverter.ToUInt32(buffer, 0));
|
||||
this.fireDebug(" Reading Signature... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
tmdFile.Read(this.signature, 0, this.signature.Length);
|
||||
this.fireDebug(" Reading Padding... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
tmdFile.Read(this.padding, 0, this.padding.Length);
|
||||
this.fireDebug(" Reading Issuer... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
tmdFile.Read(this.issuer, 0, this.issuer.Length);
|
||||
this.fireDebug(" Reading Version... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
this.fireDebug(" Reading CA Crl Version... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
this.fireDebug(" Reading Signer Crl Version... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
this.fireDebug(" Reading Padding Byte... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
tmdFile.Read(buffer, 0, 4);
|
||||
this.version = buffer[0];
|
||||
this.caCrlVersion = buffer[1];
|
||||
this.signerCrlVersion = buffer[2];
|
||||
this.paddingByte = buffer[3];
|
||||
this.fireDebug(" Reading Startup IOS... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
tmdFile.Read(buffer, 0, 8);
|
||||
this.startupIos = Shared.Swap(BitConverter.ToUInt64(buffer, 0));
|
||||
this.fireDebug(" Reading Title ID... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
tmdFile.Read(buffer, 0, 8);
|
||||
this.titleId = Shared.Swap(BitConverter.ToUInt64(buffer, 0));
|
||||
this.fireDebug(" Reading Title Type... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
tmdFile.Read(buffer, 0, 4);
|
||||
this.titleType = Shared.Swap(BitConverter.ToUInt32(buffer, 0));
|
||||
this.fireDebug(" Reading Group ID... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
tmdFile.Read(buffer, 0, 2);
|
||||
this.groupId = Shared.Swap(BitConverter.ToUInt16(buffer, 0));
|
||||
this.fireDebug(" Reading Padding2... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
tmdFile.Read(buffer, 0, 2);
|
||||
this.padding2 = Shared.Swap(BitConverter.ToUInt16(buffer, 0));
|
||||
this.fireDebug(" Reading Region... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
tmdFile.Read(buffer, 0, 2);
|
||||
this.region = Shared.Swap(BitConverter.ToUInt16(buffer, 0));
|
||||
this.fireDebug(" Reading Reserved... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
tmdFile.Read(this.reserved, 0, this.reserved.Length);
|
||||
this.fireDebug(" Reading Access Rights... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
tmdFile.Read(buffer, 0, 4);
|
||||
this.accessRights = Shared.Swap(BitConverter.ToUInt32(buffer, 0));
|
||||
this.fireDebug(" Reading Title Version... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
this.fireDebug(" Reading NumOfContents... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
this.fireDebug(" Reading Boot Index... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
this.fireDebug(" Reading Padding3... (Offset: 0x{0})", (object) tmdFile.Position.ToString("x8").ToUpper());
|
||||
tmdFile.Read(buffer, 0, 8);
|
||||
this.titleVersion = Shared.Swap(BitConverter.ToUInt16(buffer, 0));
|
||||
this.numOfContents = Shared.Swap(BitConverter.ToUInt16(buffer, 2));
|
||||
this.bootIndex = Shared.Swap(BitConverter.ToUInt16(buffer, 4));
|
||||
this.padding3 = Shared.Swap(BitConverter.ToUInt16(buffer, 6));
|
||||
this.contents = new List<TMD_Content>();
|
||||
for (int index = 0; index < (int) this.numOfContents; ++index)
|
||||
{
|
||||
this.fireDebug(" Reading Content #{0} of {1}... (Offset: 0x{2})", (object) (index + 1), (object) this.numOfContents, (object) tmdFile.Position.ToString("x8").ToUpper().ToUpper());
|
||||
TMD_Content tmdContent = new TMD_Content();
|
||||
tmdContent.Hash = new byte[20];
|
||||
tmdFile.Read(buffer, 0, 8);
|
||||
tmdContent.ContentID = Shared.Swap(BitConverter.ToUInt32(buffer, 0));
|
||||
tmdContent.Index = Shared.Swap(BitConverter.ToUInt16(buffer, 4));
|
||||
tmdContent.Type = (ContentType) Shared.Swap(BitConverter.ToUInt16(buffer, 6));
|
||||
tmdFile.Read(buffer, 0, 8);
|
||||
tmdContent.Size = Shared.Swap(BitConverter.ToUInt64(buffer, 0));
|
||||
tmdFile.Read(tmdContent.Hash, 0, tmdContent.Hash.Length);
|
||||
this.contents.Add(tmdContent);
|
||||
}
|
||||
this.fireDebug("Pasing TMD Finished...");
|
||||
}
|
||||
|
||||
private string calculateNandBlocks()
|
||||
{
|
||||
int num1 = 0;
|
||||
int num2 = 0;
|
||||
for (int index = 0; index < (int) this.numOfContents; ++index)
|
||||
{
|
||||
num2 += (int) this.contents[index].Size;
|
||||
if (this.contents[index].Type == ContentType.Normal)
|
||||
num1 += (int) this.contents[index].Size;
|
||||
}
|
||||
int num3 = (int) Math.Ceiling((double) num1 / 131072.0);
|
||||
int num4 = (int) Math.Ceiling((double) num2 / 131072.0);
|
||||
return num3 == num4 ? num4.ToString() : string.Format("{0} - {1}", (object) num3, (object) num4);
|
||||
}
|
||||
|
||||
private void fireDebug(string debugMessage, params object[] args)
|
||||
{
|
||||
EventHandler<MessageEventArgs> debug = this.Debug;
|
||||
if (debug == null)
|
||||
return;
|
||||
debug(new object(), new MessageEventArgs(string.Format(debugMessage, args)));
|
||||
}
|
||||
}
|
||||
}
|
47
TMD_Content.cs
Normal file
47
TMD_Content.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.TMD_Content
|
||||
// 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 class TMD_Content
|
||||
{
|
||||
private uint contentId;
|
||||
private ushort index;
|
||||
private ushort type;
|
||||
private ulong size;
|
||||
private byte[] hash = new byte[20];
|
||||
|
||||
public uint ContentID
|
||||
{
|
||||
get => this.contentId;
|
||||
set => this.contentId = value;
|
||||
}
|
||||
|
||||
public ushort Index
|
||||
{
|
||||
get => this.index;
|
||||
set => this.index = value;
|
||||
}
|
||||
|
||||
public ContentType Type
|
||||
{
|
||||
get => (ContentType) this.type;
|
||||
set => this.type = (ushort) value;
|
||||
}
|
||||
|
||||
public ulong Size
|
||||
{
|
||||
get => this.size;
|
||||
set => this.size = value;
|
||||
}
|
||||
|
||||
public byte[] Hash
|
||||
{
|
||||
get => this.hash;
|
||||
set => this.hash = value;
|
||||
}
|
||||
}
|
||||
}
|
35
TPL_Header.cs
Normal file
35
TPL_Header.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.TPL_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 TPL_Header
|
||||
{
|
||||
private uint tplMagic = 2142000;
|
||||
private uint numOfTextures;
|
||||
private uint headerSize = 12;
|
||||
|
||||
public uint TplMagic => this.tplMagic;
|
||||
|
||||
public uint NumOfTextures
|
||||
{
|
||||
get => this.numOfTextures;
|
||||
set => this.numOfTextures = value;
|
||||
}
|
||||
|
||||
public uint HeaderSize => this.headerSize;
|
||||
|
||||
public void Write(Stream writeStream)
|
||||
{
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.tplMagic)), 0, 4);
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.numOfTextures)), 0, 4);
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.headerSize)), 0, 4);
|
||||
}
|
||||
}
|
||||
}
|
16
TPL_PaletteFormat.cs
Normal file
16
TPL_PaletteFormat.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.TPL_PaletteFormat
|
||||
// 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 TPL_PaletteFormat
|
||||
{
|
||||
IA8 = 0,
|
||||
RGB565 = 1,
|
||||
RGB5A3 = 2,
|
||||
None = 255, // 0x000000FF
|
||||
}
|
||||
}
|
59
TPL_PaletteHeader.cs
Normal file
59
TPL_PaletteHeader.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.TPL_PaletteHeader
|
||||
// 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 TPL_PaletteHeader
|
||||
{
|
||||
private ushort numberOfItems;
|
||||
private byte unpacked;
|
||||
private byte pad;
|
||||
private uint paletteFormat = (uint) byte.MaxValue;
|
||||
private uint paletteDataOffset;
|
||||
|
||||
public ushort NumberOfItems
|
||||
{
|
||||
get => this.numberOfItems;
|
||||
set => this.numberOfItems = value;
|
||||
}
|
||||
|
||||
public byte Unpacked
|
||||
{
|
||||
get => this.unpacked;
|
||||
set => this.unpacked = value;
|
||||
}
|
||||
|
||||
public byte Pad
|
||||
{
|
||||
get => this.pad;
|
||||
set => this.pad = value;
|
||||
}
|
||||
|
||||
public uint PaletteFormat
|
||||
{
|
||||
get => this.paletteFormat;
|
||||
set => this.paletteFormat = value;
|
||||
}
|
||||
|
||||
public uint PaletteDataOffset
|
||||
{
|
||||
get => this.paletteDataOffset;
|
||||
set => this.paletteDataOffset = value;
|
||||
}
|
||||
|
||||
public void Write(Stream writeStream)
|
||||
{
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.numberOfItems)), 0, 2);
|
||||
writeStream.WriteByte(this.unpacked);
|
||||
writeStream.WriteByte(this.pad);
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.paletteFormat)), 0, 4);
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.paletteDataOffset)), 0, 4);
|
||||
}
|
||||
}
|
||||
}
|
35
TPL_TextureEntry.cs
Normal file
35
TPL_TextureEntry.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.TPL_TextureEntry
|
||||
// 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 TPL_TextureEntry
|
||||
{
|
||||
private uint textureHeaderOffset;
|
||||
private uint paletteHeaderOffset;
|
||||
|
||||
public uint TextureHeaderOffset
|
||||
{
|
||||
get => this.textureHeaderOffset;
|
||||
set => this.textureHeaderOffset = value;
|
||||
}
|
||||
|
||||
public uint PaletteHeaderOffset
|
||||
{
|
||||
get => this.paletteHeaderOffset;
|
||||
set => this.paletteHeaderOffset = value;
|
||||
}
|
||||
|
||||
public void Write(Stream writeStream)
|
||||
{
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.textureHeaderOffset)), 0, 4);
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.paletteHeaderOffset)), 0, 4);
|
||||
}
|
||||
}
|
||||
}
|
23
TPL_TextureFormat.cs
Normal file
23
TPL_TextureFormat.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.TPL_TextureFormat
|
||||
// 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 TPL_TextureFormat
|
||||
{
|
||||
I4 = 0,
|
||||
I8 = 1,
|
||||
IA4 = 2,
|
||||
IA8 = 3,
|
||||
RGB565 = 4,
|
||||
RGB5A3 = 5,
|
||||
RGBA8 = 6,
|
||||
CI4 = 8,
|
||||
CI8 = 9,
|
||||
CI14X2 = 10, // 0x0000000A
|
||||
CMP = 14, // 0x0000000E
|
||||
}
|
||||
}
|
123
TPL_TextureHeader.cs
Normal file
123
TPL_TextureHeader.cs
Normal file
|
@ -0,0 +1,123 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.TPL_TextureHeader
|
||||
// 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 TPL_TextureHeader
|
||||
{
|
||||
private ushort textureHeight;
|
||||
private ushort textureWidth;
|
||||
private uint textureFormat;
|
||||
private uint textureDataOffset;
|
||||
private uint wrapS;
|
||||
private uint wrapT;
|
||||
private uint minFilter = 1;
|
||||
private uint magFilter = 1;
|
||||
private uint lodBias;
|
||||
private byte edgeLod;
|
||||
private byte minLod;
|
||||
private byte maxLod;
|
||||
private byte unpacked;
|
||||
|
||||
public ushort TextureHeight
|
||||
{
|
||||
get => this.textureHeight;
|
||||
set => this.textureHeight = value;
|
||||
}
|
||||
|
||||
public ushort TextureWidth
|
||||
{
|
||||
get => this.textureWidth;
|
||||
set => this.textureWidth = value;
|
||||
}
|
||||
|
||||
public uint TextureFormat
|
||||
{
|
||||
get => this.textureFormat;
|
||||
set => this.textureFormat = value;
|
||||
}
|
||||
|
||||
public uint TextureDataOffset
|
||||
{
|
||||
get => this.textureDataOffset;
|
||||
set => this.textureDataOffset = value;
|
||||
}
|
||||
|
||||
public uint WrapS
|
||||
{
|
||||
get => this.wrapS;
|
||||
set => this.wrapS = value;
|
||||
}
|
||||
|
||||
public uint WrapT
|
||||
{
|
||||
get => this.wrapT;
|
||||
set => this.wrapT = value;
|
||||
}
|
||||
|
||||
public uint MinFilter
|
||||
{
|
||||
get => this.minFilter;
|
||||
set => this.minFilter = value;
|
||||
}
|
||||
|
||||
public uint MagFilter
|
||||
{
|
||||
get => this.magFilter;
|
||||
set => this.magFilter = value;
|
||||
}
|
||||
|
||||
public uint LodBias
|
||||
{
|
||||
get => this.lodBias;
|
||||
set => this.lodBias = value;
|
||||
}
|
||||
|
||||
public byte EdgeLod
|
||||
{
|
||||
get => this.edgeLod;
|
||||
set => this.edgeLod = value;
|
||||
}
|
||||
|
||||
public byte MinLod
|
||||
{
|
||||
get => this.minLod;
|
||||
set => this.minLod = value;
|
||||
}
|
||||
|
||||
public byte MaxLod
|
||||
{
|
||||
get => this.maxLod;
|
||||
set => this.maxLod = value;
|
||||
}
|
||||
|
||||
public byte Unpacked
|
||||
{
|
||||
get => this.unpacked;
|
||||
set => this.unpacked = value;
|
||||
}
|
||||
|
||||
public void Write(Stream writeStream)
|
||||
{
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.textureHeight)), 0, 2);
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.textureWidth)), 0, 2);
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.textureFormat)), 0, 4);
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.textureDataOffset)), 0, 4);
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.wrapS)), 0, 4);
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.wrapT)), 0, 4);
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.minFilter)), 0, 4);
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.magFilter)), 0, 4);
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.lodBias)), 0, 4);
|
||||
writeStream.WriteByte(this.edgeLod);
|
||||
writeStream.WriteByte(this.minLod);
|
||||
writeStream.WriteByte(this.maxLod);
|
||||
writeStream.WriteByte(this.unpacked);
|
||||
}
|
||||
}
|
||||
}
|
485
Ticket.cs
Normal file
485
Ticket.cs
Normal file
|
@ -0,0 +1,485 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.Ticket
|
||||
// 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;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace libWiiSharp
|
||||
{
|
||||
public class Ticket : IDisposable
|
||||
{
|
||||
private byte newKeyIndex;
|
||||
private byte[] decryptedTitleKey = new byte[16];
|
||||
private bool fakeSign;
|
||||
private bool titleKeyChanged;
|
||||
private byte[] newEncryptedTitleKey = new byte[0];
|
||||
private bool reDecrypt;
|
||||
private uint signatureExponent = 65537;
|
||||
private byte[] signature = new byte[256];
|
||||
private byte[] padding = new byte[60];
|
||||
private byte[] issuer = new byte[64];
|
||||
private byte[] unknown = new byte[63];
|
||||
private byte[] encryptedTitleKey = new byte[16];
|
||||
private byte unknown2;
|
||||
private ulong ticketId;
|
||||
private uint consoleId;
|
||||
private ulong titleId;
|
||||
private ushort unknown3 = ushort.MaxValue;
|
||||
private ushort numOfDlc;
|
||||
private ulong unknown4;
|
||||
private byte padding2;
|
||||
private byte commonKeyIndex;
|
||||
private byte[] unknown5 = new byte[48];
|
||||
private byte[] unknown6 = new byte[32];
|
||||
private ushort padding3;
|
||||
private uint enableTimeLimit;
|
||||
private uint timeLimit;
|
||||
private byte[] padding4 = new byte[88];
|
||||
private bool isDisposed;
|
||||
|
||||
public byte[] TitleKey
|
||||
{
|
||||
get => this.decryptedTitleKey;
|
||||
set
|
||||
{
|
||||
this.decryptedTitleKey = value;
|
||||
this.titleKeyChanged = true;
|
||||
this.reDecrypt = false;
|
||||
}
|
||||
}
|
||||
|
||||
public CommonKeyType CommonKeyIndex
|
||||
{
|
||||
get => (CommonKeyType) this.newKeyIndex;
|
||||
set => this.newKeyIndex = (byte) value;
|
||||
}
|
||||
|
||||
public ulong TicketID
|
||||
{
|
||||
get => this.ticketId;
|
||||
set => this.ticketId = value;
|
||||
}
|
||||
|
||||
public uint ConsoleID
|
||||
{
|
||||
get => this.consoleId;
|
||||
set => this.consoleId = value;
|
||||
}
|
||||
|
||||
public ulong TitleID
|
||||
{
|
||||
get => this.titleId;
|
||||
set
|
||||
{
|
||||
this.titleId = value;
|
||||
if (!this.reDecrypt)
|
||||
return;
|
||||
this.reDecryptTitleKey();
|
||||
}
|
||||
}
|
||||
|
||||
public ushort NumOfDLC
|
||||
{
|
||||
get => this.numOfDlc;
|
||||
set => this.numOfDlc = value;
|
||||
}
|
||||
|
||||
public bool FakeSign
|
||||
{
|
||||
get => this.fakeSign;
|
||||
set => this.fakeSign = value;
|
||||
}
|
||||
|
||||
public bool TitleKeyChanged => this.titleKeyChanged;
|
||||
|
||||
public event EventHandler<MessageEventArgs> Debug;
|
||||
|
||||
~Ticket() => this.Dispose(false);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize((object) this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && !this.isDisposed)
|
||||
{
|
||||
this.decryptedTitleKey = (byte[]) null;
|
||||
this.newEncryptedTitleKey = (byte[]) null;
|
||||
this.signature = (byte[]) null;
|
||||
this.padding = (byte[]) null;
|
||||
this.issuer = (byte[]) null;
|
||||
this.unknown = (byte[]) null;
|
||||
this.encryptedTitleKey = (byte[]) null;
|
||||
this.unknown5 = (byte[]) null;
|
||||
this.unknown6 = (byte[]) null;
|
||||
this.padding4 = (byte[]) null;
|
||||
}
|
||||
this.isDisposed = true;
|
||||
}
|
||||
|
||||
public static Ticket Load(string pathToTicket) => Ticket.Load(File.ReadAllBytes(pathToTicket));
|
||||
|
||||
public static Ticket Load(byte[] ticket)
|
||||
{
|
||||
Ticket ticket1 = new Ticket();
|
||||
MemoryStream memoryStream = new MemoryStream(ticket);
|
||||
try
|
||||
{
|
||||
ticket1.parseTicket((Stream) memoryStream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
memoryStream.Dispose();
|
||||
throw;
|
||||
}
|
||||
memoryStream.Dispose();
|
||||
return ticket1;
|
||||
}
|
||||
|
||||
public static Ticket Load(Stream ticket)
|
||||
{
|
||||
Ticket ticket1 = new Ticket();
|
||||
ticket1.parseTicket(ticket);
|
||||
return ticket1;
|
||||
}
|
||||
|
||||
public void LoadFile(string pathToTicket) => this.LoadFile(File.ReadAllBytes(pathToTicket));
|
||||
|
||||
public void LoadFile(byte[] ticket)
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream(ticket);
|
||||
try
|
||||
{
|
||||
this.parseTicket((Stream) memoryStream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
memoryStream.Dispose();
|
||||
throw;
|
||||
}
|
||||
memoryStream.Dispose();
|
||||
}
|
||||
|
||||
public void LoadFile(Stream ticket) => this.parseTicket(ticket);
|
||||
|
||||
public void Save(string savePath) => this.Save(savePath, false);
|
||||
|
||||
public void Save(string savePath, bool fakeSign)
|
||||
{
|
||||
if (fakeSign)
|
||||
this.fakeSign = true;
|
||||
if (File.Exists(savePath))
|
||||
File.Delete(savePath);
|
||||
using (FileStream fileStream = new FileStream(savePath, FileMode.Create))
|
||||
this.writeToStream((Stream) fileStream);
|
||||
}
|
||||
|
||||
public MemoryStream ToMemoryStream() => this.ToMemoryStream(false);
|
||||
|
||||
public MemoryStream ToMemoryStream(bool fakeSign)
|
||||
{
|
||||
if (fakeSign)
|
||||
this.fakeSign = true;
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
try
|
||||
{
|
||||
this.writeToStream((Stream) memoryStream);
|
||||
return memoryStream;
|
||||
}
|
||||
catch
|
||||
{
|
||||
memoryStream.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] ToByteArray() => this.ToByteArray(false);
|
||||
|
||||
public byte[] ToByteArray(bool fakeSign)
|
||||
{
|
||||
if (fakeSign)
|
||||
this.fakeSign = true;
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
try
|
||||
{
|
||||
this.writeToStream((Stream) memoryStream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
memoryStream.Dispose();
|
||||
throw;
|
||||
}
|
||||
byte[] array = memoryStream.ToArray();
|
||||
memoryStream.Dispose();
|
||||
return array;
|
||||
}
|
||||
|
||||
public void SetTitleKey(string newTitleKey) => this.SetTitleKey(newTitleKey.ToCharArray());
|
||||
|
||||
public void SetTitleKey(char[] newTitleKey)
|
||||
{
|
||||
if (newTitleKey.Length != 16)
|
||||
throw new Exception("The title key must be 16 characters long!");
|
||||
for (int index = 0; index < 16; ++index)
|
||||
this.encryptedTitleKey[index] = (byte) newTitleKey[index];
|
||||
this.decryptTitleKey();
|
||||
this.titleKeyChanged = true;
|
||||
this.reDecrypt = true;
|
||||
this.newEncryptedTitleKey = this.encryptedTitleKey;
|
||||
}
|
||||
|
||||
public void SetTitleKey(byte[] newTitleKey)
|
||||
{
|
||||
this.encryptedTitleKey = newTitleKey.Length == 16 ? newTitleKey : throw new Exception("The title key must be 16 characters long!");
|
||||
this.decryptTitleKey();
|
||||
this.titleKeyChanged = true;
|
||||
this.reDecrypt = true;
|
||||
this.newEncryptedTitleKey = newTitleKey;
|
||||
}
|
||||
|
||||
public string GetUpperTitleID()
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(Shared.Swap((uint) this.titleId));
|
||||
return new string(new char[4]
|
||||
{
|
||||
(char) bytes[0],
|
||||
(char) bytes[1],
|
||||
(char) bytes[2],
|
||||
(char) bytes[3]
|
||||
});
|
||||
}
|
||||
|
||||
private void writeToStream(Stream writeStream)
|
||||
{
|
||||
this.fireDebug("Writing Ticket...");
|
||||
this.fireDebug(" Encrypting Title Key...");
|
||||
this.encryptTitleKey();
|
||||
this.fireDebug(" -> Decrypted Title Key: {0}", (object) Shared.ByteArrayToString(this.decryptedTitleKey));
|
||||
this.fireDebug(" -> Encrypted Title Key: {0}", (object) Shared.ByteArrayToString(this.encryptedTitleKey));
|
||||
if (this.fakeSign)
|
||||
{
|
||||
this.fireDebug(" Clearing Signature...");
|
||||
this.signature = new byte[256];
|
||||
}
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
memoryStream.Seek(0L, SeekOrigin.Begin);
|
||||
this.fireDebug(" Writing Signature Exponent... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.signatureExponent)), 0, 4);
|
||||
this.fireDebug(" Writing Signature... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(this.signature, 0, this.signature.Length);
|
||||
this.fireDebug(" Writing Padding... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(this.padding, 0, this.padding.Length);
|
||||
this.fireDebug(" Writing Issuer... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(this.issuer, 0, this.issuer.Length);
|
||||
this.fireDebug(" Writing Unknown... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(this.unknown, 0, this.unknown.Length);
|
||||
this.fireDebug(" Writing Title Key... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(this.encryptedTitleKey, 0, this.encryptedTitleKey.Length);
|
||||
this.fireDebug(" Writing Unknown2... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.WriteByte(this.unknown2);
|
||||
this.fireDebug(" Writing Ticket ID... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.ticketId)), 0, 8);
|
||||
this.fireDebug(" Writing Console ID... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.consoleId)), 0, 4);
|
||||
this.fireDebug(" Writing Title ID... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.titleId)), 0, 8);
|
||||
this.fireDebug(" Writing Unknwon3... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.unknown3)), 0, 2);
|
||||
this.fireDebug(" Writing NumOfDLC... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.numOfDlc)), 0, 2);
|
||||
this.fireDebug(" Writing Unknwon4... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.unknown4)), 0, 8);
|
||||
this.fireDebug(" Writing Padding2... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.WriteByte(this.padding2);
|
||||
this.fireDebug(" Writing Common Key Index... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.WriteByte(this.commonKeyIndex);
|
||||
object[] objArray1 = new object[1];
|
||||
long position = memoryStream.Position;
|
||||
objArray1[0] = (object) position.ToString("x8").ToUpper();
|
||||
this.fireDebug(" Writing Unknown5... (Offset: 0x{0})", objArray1);
|
||||
memoryStream.Write(this.unknown5, 0, this.unknown5.Length);
|
||||
object[] objArray2 = new object[1];
|
||||
position = memoryStream.Position;
|
||||
objArray2[0] = (object) position.ToString("x8").ToUpper();
|
||||
this.fireDebug(" Writing Unknown6... (Offset: 0x{0})", objArray2);
|
||||
memoryStream.Write(this.unknown6, 0, this.unknown6.Length);
|
||||
object[] objArray3 = new object[1];
|
||||
position = memoryStream.Position;
|
||||
objArray3[0] = (object) position.ToString("x8").ToUpper();
|
||||
this.fireDebug(" Writing Padding3... (Offset: 0x{0})", objArray3);
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.padding3)), 0, 2);
|
||||
object[] objArray4 = new object[1];
|
||||
position = memoryStream.Position;
|
||||
objArray4[0] = (object) position.ToString("x8").ToUpper();
|
||||
this.fireDebug(" Writing Enable Time Limit... (Offset: 0x{0})", objArray4);
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.enableTimeLimit)), 0, 4);
|
||||
object[] objArray5 = new object[1];
|
||||
position = memoryStream.Position;
|
||||
objArray5[0] = (object) position.ToString("x8").ToUpper();
|
||||
this.fireDebug(" Writing Time Limit... (Offset: 0x{0})", objArray5);
|
||||
memoryStream.Write(BitConverter.GetBytes(Shared.Swap(this.timeLimit)), 0, 4);
|
||||
object[] objArray6 = new object[1];
|
||||
position = memoryStream.Position;
|
||||
objArray6[0] = (object) position.ToString("x8").ToUpper();
|
||||
this.fireDebug(" Writing Padding4... (Offset: 0x{0})", objArray6);
|
||||
memoryStream.Write(this.padding4, 0, this.padding4.Length);
|
||||
byte[] array = memoryStream.ToArray();
|
||||
memoryStream.Dispose();
|
||||
if (this.fakeSign)
|
||||
{
|
||||
this.fireDebug(" Fakesigning Ticket...");
|
||||
byte[] numArray = new byte[20];
|
||||
SHA1 shA1 = SHA1.Create();
|
||||
for (ushort index = 0; index < ushort.MaxValue; ++index)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(index);
|
||||
array[498] = bytes[1];
|
||||
array[499] = bytes[0];
|
||||
if (shA1.ComputeHash(array)[0] == (byte) 0)
|
||||
{
|
||||
this.fireDebug(" -> Signed ({0})", (object) index);
|
||||
break;
|
||||
}
|
||||
if (index == (ushort) 65534)
|
||||
{
|
||||
this.fireDebug(" -> Signing Failed...");
|
||||
throw new Exception("Fakesigning failed...");
|
||||
}
|
||||
}
|
||||
shA1.Clear();
|
||||
}
|
||||
writeStream.Seek(0L, SeekOrigin.Begin);
|
||||
writeStream.Write(array, 0, array.Length);
|
||||
this.fireDebug("Writing Ticket Finished...");
|
||||
}
|
||||
|
||||
private void parseTicket(Stream ticketFile)
|
||||
{
|
||||
this.fireDebug("Parsing Ticket...");
|
||||
ticketFile.Seek(0L, SeekOrigin.Begin);
|
||||
byte[] buffer = new byte[8];
|
||||
this.fireDebug(" Reading Signature Exponent... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
ticketFile.Read(buffer, 0, 4);
|
||||
this.signatureExponent = Shared.Swap(BitConverter.ToUInt32(buffer, 0));
|
||||
this.fireDebug(" Reading Signature... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
ticketFile.Read(this.signature, 0, this.signature.Length);
|
||||
this.fireDebug(" Reading Padding... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
ticketFile.Read(this.padding, 0, this.padding.Length);
|
||||
this.fireDebug(" Reading Issuer... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
ticketFile.Read(this.issuer, 0, this.issuer.Length);
|
||||
this.fireDebug(" Reading Unknown... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
ticketFile.Read(this.unknown, 0, this.unknown.Length);
|
||||
this.fireDebug(" Reading Title Key... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
ticketFile.Read(this.encryptedTitleKey, 0, this.encryptedTitleKey.Length);
|
||||
this.fireDebug(" Reading Unknown2... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
this.unknown2 = (byte) ticketFile.ReadByte();
|
||||
this.fireDebug(" Reading Ticket ID.. (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
ticketFile.Read(buffer, 0, 8);
|
||||
this.ticketId = Shared.Swap(BitConverter.ToUInt64(buffer, 0));
|
||||
this.fireDebug(" Reading Console ID... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
ticketFile.Read(buffer, 0, 4);
|
||||
this.consoleId = Shared.Swap(BitConverter.ToUInt32(buffer, 0));
|
||||
this.fireDebug(" Reading Title ID... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
ticketFile.Read(buffer, 0, 8);
|
||||
this.titleId = Shared.Swap(BitConverter.ToUInt64(buffer, 0));
|
||||
this.fireDebug(" Reading Unknown3... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
this.fireDebug(" Reading NumOfDLC... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
ticketFile.Read(buffer, 0, 4);
|
||||
this.unknown3 = Shared.Swap(BitConverter.ToUInt16(buffer, 0));
|
||||
this.numOfDlc = Shared.Swap(BitConverter.ToUInt16(buffer, 2));
|
||||
this.fireDebug(" Reading Unknown4... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
ticketFile.Read(buffer, 0, 8);
|
||||
this.unknown4 = Shared.Swap(BitConverter.ToUInt64(buffer, 0));
|
||||
this.fireDebug(" Reading Padding2... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
this.padding2 = (byte) ticketFile.ReadByte();
|
||||
this.fireDebug(" Reading Common Key Index... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
this.commonKeyIndex = (byte) ticketFile.ReadByte();
|
||||
this.newKeyIndex = this.commonKeyIndex;
|
||||
this.fireDebug(" Reading Unknown5... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
ticketFile.Read(this.unknown5, 0, this.unknown5.Length);
|
||||
this.fireDebug(" Reading Unknown6... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
ticketFile.Read(this.unknown6, 0, this.unknown6.Length);
|
||||
this.fireDebug(" Reading Padding3... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
ticketFile.Read(buffer, 0, 2);
|
||||
this.padding3 = Shared.Swap(BitConverter.ToUInt16(buffer, 0));
|
||||
this.fireDebug(" Reading Enable Time Limit... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
this.fireDebug(" Reading Time Limit... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
ticketFile.Read(buffer, 0, 8);
|
||||
this.enableTimeLimit = Shared.Swap(BitConverter.ToUInt32(buffer, 0));
|
||||
this.timeLimit = Shared.Swap(BitConverter.ToUInt32(buffer, 4));
|
||||
this.fireDebug(" Reading Padding4... (Offset: 0x{0})", (object) ticketFile.Position.ToString("x8").ToUpper());
|
||||
ticketFile.Read(this.padding4, 0, this.padding4.Length);
|
||||
this.fireDebug(" Decrypting Title Key...");
|
||||
this.decryptTitleKey();
|
||||
this.fireDebug(" -> Encrypted Title Key: {0}", (object) Shared.ByteArrayToString(this.encryptedTitleKey));
|
||||
this.fireDebug(" -> Decrypted Title Key: {0}", (object) Shared.ByteArrayToString(this.decryptedTitleKey));
|
||||
this.fireDebug("Parsing Ticket Finished...");
|
||||
}
|
||||
|
||||
private void decryptTitleKey()
|
||||
{
|
||||
byte[] numArray = this.commonKeyIndex == (byte) 1 ? CommonKey.GetKoreanKey() : CommonKey.GetStandardKey();
|
||||
byte[] bytes = BitConverter.GetBytes(Shared.Swap(this.titleId));
|
||||
Array.Resize<byte>(ref bytes, 16);
|
||||
RijndaelManaged rijndaelManaged = new RijndaelManaged();
|
||||
rijndaelManaged.Mode = CipherMode.CBC;
|
||||
rijndaelManaged.Padding = PaddingMode.None;
|
||||
rijndaelManaged.KeySize = 128;
|
||||
rijndaelManaged.BlockSize = 128;
|
||||
rijndaelManaged.Key = numArray;
|
||||
rijndaelManaged.IV = bytes;
|
||||
ICryptoTransform decryptor = rijndaelManaged.CreateDecryptor();
|
||||
MemoryStream memoryStream = new MemoryStream(this.encryptedTitleKey);
|
||||
CryptoStream cryptoStream = new CryptoStream((Stream) memoryStream, decryptor, CryptoStreamMode.Read);
|
||||
cryptoStream.Read(this.decryptedTitleKey, 0, this.decryptedTitleKey.Length);
|
||||
cryptoStream.Dispose();
|
||||
memoryStream.Dispose();
|
||||
decryptor.Dispose();
|
||||
rijndaelManaged.Clear();
|
||||
}
|
||||
|
||||
private void encryptTitleKey()
|
||||
{
|
||||
this.commonKeyIndex = this.newKeyIndex;
|
||||
byte[] numArray = this.commonKeyIndex == (byte) 1 ? CommonKey.GetKoreanKey() : CommonKey.GetStandardKey();
|
||||
byte[] bytes = BitConverter.GetBytes(Shared.Swap(this.titleId));
|
||||
Array.Resize<byte>(ref bytes, 16);
|
||||
RijndaelManaged rijndaelManaged = new RijndaelManaged();
|
||||
rijndaelManaged.Mode = CipherMode.CBC;
|
||||
rijndaelManaged.Padding = PaddingMode.None;
|
||||
rijndaelManaged.KeySize = 128;
|
||||
rijndaelManaged.BlockSize = 128;
|
||||
rijndaelManaged.Key = numArray;
|
||||
rijndaelManaged.IV = bytes;
|
||||
ICryptoTransform encryptor = rijndaelManaged.CreateEncryptor();
|
||||
MemoryStream memoryStream = new MemoryStream(this.decryptedTitleKey);
|
||||
CryptoStream cryptoStream = new CryptoStream((Stream) memoryStream, encryptor, CryptoStreamMode.Read);
|
||||
cryptoStream.Read(this.encryptedTitleKey, 0, this.encryptedTitleKey.Length);
|
||||
cryptoStream.Dispose();
|
||||
memoryStream.Dispose();
|
||||
encryptor.Dispose();
|
||||
rijndaelManaged.Clear();
|
||||
}
|
||||
|
||||
private void reDecryptTitleKey()
|
||||
{
|
||||
this.encryptedTitleKey = this.newEncryptedTitleKey;
|
||||
this.decryptTitleKey();
|
||||
}
|
||||
|
||||
private void fireDebug(string debugMessage, params object[] args)
|
||||
{
|
||||
EventHandler<MessageEventArgs> debug = this.Debug;
|
||||
if (debug == null)
|
||||
return;
|
||||
debug(new object(), new MessageEventArgs(string.Format(debugMessage, args)));
|
||||
}
|
||||
}
|
||||
}
|
785
U8.cs
Normal file
785
U8.cs
Normal file
|
@ -0,0 +1,785 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.U8
|
||||
// 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.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace libWiiSharp
|
||||
{
|
||||
public class U8 : IDisposable
|
||||
{
|
||||
private const int dataPadding = 32;
|
||||
private Headers.HeaderType headerType;
|
||||
private object header;
|
||||
private U8_Header u8Header = new U8_Header();
|
||||
private U8_Node rootNode = new U8_Node();
|
||||
private List<U8_Node> u8Nodes = new List<U8_Node>();
|
||||
private List<string> stringTable = new List<string>();
|
||||
private List<byte[]> data = new List<byte[]>();
|
||||
private int iconSize = -1;
|
||||
private int bannerSize = -1;
|
||||
private int soundSize = -1;
|
||||
private bool lz77;
|
||||
private bool isDisposed;
|
||||
|
||||
public Headers.HeaderType HeaderType => this.headerType;
|
||||
|
||||
public object Header => this.header;
|
||||
|
||||
public U8_Node RootNode => this.rootNode;
|
||||
|
||||
public List<U8_Node> Nodes => this.u8Nodes;
|
||||
|
||||
public string[] StringTable => this.stringTable.ToArray();
|
||||
|
||||
public byte[][] Data => this.data.ToArray();
|
||||
|
||||
public int NumOfNodes => (int) this.rootNode.SizeOfData - 1;
|
||||
|
||||
public int IconSize => this.iconSize;
|
||||
|
||||
public int BannerSize => this.bannerSize;
|
||||
|
||||
public int SoundSize => this.soundSize;
|
||||
|
||||
public bool Lz77Compress
|
||||
{
|
||||
get => this.lz77;
|
||||
set => this.lz77 = value;
|
||||
}
|
||||
|
||||
public event EventHandler<ProgressChangedEventArgs> Progress;
|
||||
|
||||
public event EventHandler<MessageEventArgs> Warning;
|
||||
|
||||
public event EventHandler<MessageEventArgs> Debug;
|
||||
|
||||
public U8() => this.rootNode.Type = U8_NodeType.Directory;
|
||||
|
||||
~U8() => this.Dispose(false);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize((object) this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && !this.isDisposed)
|
||||
{
|
||||
this.header = (object) null;
|
||||
this.u8Header = (U8_Header) null;
|
||||
this.rootNode = (U8_Node) null;
|
||||
this.u8Nodes.Clear();
|
||||
this.u8Nodes = (List<U8_Node>) null;
|
||||
this.stringTable.Clear();
|
||||
this.stringTable = (List<string>) null;
|
||||
this.data.Clear();
|
||||
this.data = (List<byte[]>) null;
|
||||
}
|
||||
this.isDisposed = true;
|
||||
}
|
||||
|
||||
public static bool IsU8(string pathToFile) => U8.IsU8(File.ReadAllBytes(pathToFile));
|
||||
|
||||
public static bool IsU8(byte[] file)
|
||||
{
|
||||
if (Lz77.IsLz77Compressed(file))
|
||||
{
|
||||
byte[] file1 = new byte[file.Length > 2000 ? 2000 : file.Length];
|
||||
for (int index = 0; index < file1.Length; ++index)
|
||||
file1[index] = file[index];
|
||||
return U8.IsU8(new Lz77().Decompress(file1));
|
||||
}
|
||||
Headers.HeaderType headerType = Headers.DetectHeader(file);
|
||||
return Shared.Swap(BitConverter.ToUInt32(file, (int) headerType)) == 1437218861U;
|
||||
}
|
||||
|
||||
public static U8 Load(string pathToU8) => U8.Load(File.ReadAllBytes(pathToU8));
|
||||
|
||||
public static U8 Load(byte[] u8File)
|
||||
{
|
||||
U8 u8 = new U8();
|
||||
MemoryStream memoryStream = new MemoryStream(u8File);
|
||||
try
|
||||
{
|
||||
u8.parseU8((Stream) memoryStream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
memoryStream.Dispose();
|
||||
throw;
|
||||
}
|
||||
memoryStream.Dispose();
|
||||
return u8;
|
||||
}
|
||||
|
||||
public static U8 Load(Stream u8File)
|
||||
{
|
||||
U8 u8 = new U8();
|
||||
u8.parseU8(u8File);
|
||||
return u8;
|
||||
}
|
||||
|
||||
public static U8 FromDirectory(string pathToDirectory)
|
||||
{
|
||||
U8 u8 = new U8();
|
||||
u8.createFromDir(pathToDirectory);
|
||||
return u8;
|
||||
}
|
||||
|
||||
public void LoadFile(string pathToU8) => this.LoadFile(File.ReadAllBytes(pathToU8));
|
||||
|
||||
public void LoadFile(byte[] u8File)
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream(u8File);
|
||||
try
|
||||
{
|
||||
this.parseU8((Stream) memoryStream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
memoryStream.Dispose();
|
||||
throw;
|
||||
}
|
||||
memoryStream.Dispose();
|
||||
}
|
||||
|
||||
public void LoadFile(Stream u8File) => this.parseU8(u8File);
|
||||
|
||||
public void CreateFromDirectory(string pathToDirectory) => this.createFromDir(pathToDirectory);
|
||||
|
||||
public void Save(string savePath)
|
||||
{
|
||||
if (File.Exists(savePath))
|
||||
File.Delete(savePath);
|
||||
using (FileStream fileStream = new FileStream(savePath, FileMode.Create))
|
||||
this.writeToStream((Stream) fileStream);
|
||||
}
|
||||
|
||||
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 Unpack(string saveDir) => this.unpackToDir(saveDir);
|
||||
|
||||
public void Extract(string saveDir) => this.unpackToDir(saveDir);
|
||||
|
||||
public void AddHeaderImet(bool shortImet, params string[] titles)
|
||||
{
|
||||
if (this.iconSize == -1)
|
||||
throw new Exception("icon.bin wasn't found!");
|
||||
if (this.bannerSize == -1)
|
||||
throw new Exception("banner.bin wasn't found!");
|
||||
if (this.soundSize == -1)
|
||||
throw new Exception("sound.bin wasn't found!");
|
||||
this.header = (object) Headers.IMET.Create(shortImet, this.iconSize, this.bannerSize, this.soundSize, titles);
|
||||
this.headerType = shortImet ? Headers.HeaderType.ShortIMET : Headers.HeaderType.IMET;
|
||||
}
|
||||
|
||||
public void AddHeaderImd5() => this.headerType = Headers.HeaderType.IMD5;
|
||||
|
||||
public void ReplaceFile(int fileIndex, string pathToNewFile, bool changeFileName = false)
|
||||
{
|
||||
if (this.u8Nodes[fileIndex].Type == U8_NodeType.Directory)
|
||||
throw new Exception("You can't replace a directory with a file!");
|
||||
this.data[fileIndex] = File.ReadAllBytes(pathToNewFile);
|
||||
if (changeFileName)
|
||||
this.stringTable[fileIndex] = Path.GetFileName(pathToNewFile);
|
||||
if (this.stringTable[fileIndex].ToLower() == "icon.bin")
|
||||
this.iconSize = this.getRealSize(File.ReadAllBytes(pathToNewFile));
|
||||
else if (this.stringTable[fileIndex].ToLower() == "banner.bin")
|
||||
{
|
||||
this.bannerSize = this.getRealSize(File.ReadAllBytes(pathToNewFile));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(this.stringTable[fileIndex].ToLower() == "sound.bin"))
|
||||
return;
|
||||
this.soundSize = this.getRealSize(File.ReadAllBytes(pathToNewFile));
|
||||
}
|
||||
}
|
||||
|
||||
public void ReplaceFile(int fileIndex, byte[] newData)
|
||||
{
|
||||
if (this.u8Nodes[fileIndex].Type == U8_NodeType.Directory)
|
||||
throw new Exception("You can't replace a directory with a file!");
|
||||
this.data[fileIndex] = newData;
|
||||
if (this.stringTable[fileIndex].ToLower() == "icon.bin")
|
||||
this.iconSize = this.getRealSize(newData);
|
||||
else if (this.stringTable[fileIndex].ToLower() == "banner.bin")
|
||||
{
|
||||
this.bannerSize = this.getRealSize(newData);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(this.stringTable[fileIndex].ToLower() == "sound.bin"))
|
||||
return;
|
||||
this.soundSize = this.getRealSize(newData);
|
||||
}
|
||||
}
|
||||
|
||||
public int GetNodeIndex(string fileOrDirName)
|
||||
{
|
||||
for (int index = 0; index < this.u8Nodes.Count; ++index)
|
||||
{
|
||||
if (this.stringTable[index].ToLower() == fileOrDirName.ToLower())
|
||||
return index;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void RenameNode(int index, string newName) => this.stringTable[index] = newName;
|
||||
|
||||
public void RenameNode(string oldName, string newName) => this.stringTable[this.GetNodeIndex(oldName)] = newName;
|
||||
|
||||
public void AddDirectory(string path) => this.addEntry(path, new byte[0]);
|
||||
|
||||
public void AddFile(string path, byte[] data) => this.addEntry(path, data);
|
||||
|
||||
public void RemoveDirectory(string path) => this.removeEntry(path);
|
||||
|
||||
public void RemoveFile(string path) => this.removeEntry(path);
|
||||
|
||||
private void writeToStream(Stream writeStream)
|
||||
{
|
||||
this.fireDebug("Writing U8 File...");
|
||||
this.fireDebug(" Updating Rootnode...");
|
||||
this.rootNode.SizeOfData = (uint) (this.u8Nodes.Count + 1);
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
memoryStream.Seek((long) this.u8Header.OffsetToRootNode + (long) ((this.u8Nodes.Count + 1) * 12), SeekOrigin.Begin);
|
||||
this.fireDebug(" Writing String Table... (Offset: 0x{0})", (object) memoryStream.Position.ToString("x8").ToUpper());
|
||||
memoryStream.WriteByte((byte) 0);
|
||||
int num = (int) memoryStream.Position - 1;
|
||||
long position;
|
||||
for (int index = 0; index < this.u8Nodes.Count; ++index)
|
||||
{
|
||||
object[] objArray = new object[4];
|
||||
position = memoryStream.Position;
|
||||
objArray[0] = (object) position.ToString("x8").ToUpper();
|
||||
objArray[1] = (object) (index + 1);
|
||||
objArray[2] = (object) this.u8Nodes.Count;
|
||||
objArray[3] = (object) this.stringTable[index];
|
||||
this.fireDebug(" -> Entry #{1} of {2}: \"{3}\"... (Offset: 0x{0})", objArray);
|
||||
this.u8Nodes[index].OffsetToName = (ushort) ((ulong) memoryStream.Position - (ulong) num);
|
||||
byte[] bytes = Encoding.ASCII.GetBytes(this.stringTable[index]);
|
||||
memoryStream.Write(bytes, 0, bytes.Length);
|
||||
memoryStream.WriteByte((byte) 0);
|
||||
}
|
||||
this.u8Header.HeaderSize = (uint) ((ulong) memoryStream.Position - (ulong) this.u8Header.OffsetToRootNode);
|
||||
this.u8Header.OffsetToData = 0U;
|
||||
for (int index = 0; index < this.u8Nodes.Count; ++index)
|
||||
{
|
||||
this.fireProgress((index + 1) * 100 / this.u8Nodes.Count);
|
||||
if (this.u8Nodes[index].Type == U8_NodeType.File)
|
||||
{
|
||||
memoryStream.Seek((long) Shared.AddPadding((int) memoryStream.Position, 32), SeekOrigin.Begin);
|
||||
object[] objArray = new object[3];
|
||||
position = memoryStream.Position;
|
||||
objArray[0] = (object) position.ToString("x8").ToUpper();
|
||||
objArray[1] = (object) (index + 1);
|
||||
objArray[2] = (object) this.u8Nodes.Count;
|
||||
this.fireDebug(" Writing Data #{1} of {2}... (Offset: 0x{0})", objArray);
|
||||
if (this.u8Header.OffsetToData == 0U)
|
||||
this.u8Header.OffsetToData = (uint) memoryStream.Position;
|
||||
this.u8Nodes[index].OffsetToData = (uint) memoryStream.Position;
|
||||
this.u8Nodes[index].SizeOfData = (uint) this.data[index].Length;
|
||||
memoryStream.Write(this.data[index], 0, this.data[index].Length);
|
||||
}
|
||||
else
|
||||
this.fireDebug(" Node #{0} of {1} is a Directory...", (object) (index + 1), (object) this.u8Nodes.Count);
|
||||
}
|
||||
while (memoryStream.Position % 16L != 0L)
|
||||
memoryStream.WriteByte((byte) 0);
|
||||
memoryStream.Seek(0L, SeekOrigin.Begin);
|
||||
object[] objArray1 = new object[1];
|
||||
position = memoryStream.Position;
|
||||
objArray1[0] = (object) position.ToString("x8").ToUpper();
|
||||
this.fireDebug(" Writing Header... (Offset: 0x{0})", objArray1);
|
||||
this.u8Header.Write((Stream) memoryStream);
|
||||
object[] objArray2 = new object[1];
|
||||
position = memoryStream.Position;
|
||||
objArray2[0] = (object) position.ToString("x8").ToUpper();
|
||||
this.fireDebug(" Writing Rootnode... (Offset: 0x{0})", objArray2);
|
||||
this.rootNode.Write((Stream) memoryStream);
|
||||
for (int index = 0; index < this.u8Nodes.Count; ++index)
|
||||
{
|
||||
object[] objArray3 = new object[3];
|
||||
position = memoryStream.Position;
|
||||
objArray3[0] = (object) position.ToString("x8").ToUpper();
|
||||
objArray3[1] = (object) (index + 1);
|
||||
objArray3[2] = (object) this.u8Nodes.Count;
|
||||
this.fireDebug(" Writing Node Entry #{1} of {2}... (Offset: 0x{0})", objArray3);
|
||||
this.u8Nodes[index].Write((Stream) memoryStream);
|
||||
}
|
||||
byte[] numArray = memoryStream.ToArray();
|
||||
memoryStream.Dispose();
|
||||
if (this.lz77)
|
||||
{
|
||||
this.fireDebug(" Lz77 Compressing U8 File...");
|
||||
numArray = new Lz77().Compress(numArray);
|
||||
}
|
||||
if (this.headerType == Headers.HeaderType.IMD5)
|
||||
{
|
||||
this.fireDebug(" Adding IMD5 Header...");
|
||||
writeStream.Seek(0L, SeekOrigin.Begin);
|
||||
Headers.IMD5.Create(numArray).Write(writeStream);
|
||||
}
|
||||
else if (this.headerType == Headers.HeaderType.IMET || this.headerType == Headers.HeaderType.ShortIMET)
|
||||
{
|
||||
this.fireDebug(" Adding IMET Header...");
|
||||
((Headers.IMET) this.header).IconSize = (uint) this.iconSize;
|
||||
((Headers.IMET) this.header).BannerSize = (uint) this.bannerSize;
|
||||
((Headers.IMET) this.header).SoundSize = (uint) this.soundSize;
|
||||
writeStream.Seek(0L, SeekOrigin.Begin);
|
||||
((Headers.IMET) this.header).Write(writeStream);
|
||||
}
|
||||
writeStream.Write(numArray, 0, numArray.Length);
|
||||
this.fireDebug("Writing U8 File Finished...");
|
||||
}
|
||||
|
||||
private void unpackToDir(string saveDir)
|
||||
{
|
||||
this.fireDebug("Unpacking U8 File to: {0}", (object) saveDir);
|
||||
if (!Directory.Exists(saveDir))
|
||||
Directory.CreateDirectory(saveDir);
|
||||
string[] strArray = new string[this.u8Nodes.Count];
|
||||
strArray[0] = saveDir;
|
||||
int[] numArray = new int[this.u8Nodes.Count];
|
||||
int index1 = 0;
|
||||
for (int index2 = 0; index2 < this.u8Nodes.Count; ++index2)
|
||||
{
|
||||
this.fireDebug(" Unpacking Entry #{0} of {1}", (object) (index2 + 1), (object) this.u8Nodes.Count);
|
||||
this.fireProgress((index2 + 1) * 100 / this.u8Nodes.Count);
|
||||
if (this.u8Nodes[index2].Type == U8_NodeType.Directory)
|
||||
{
|
||||
this.fireDebug(" -> Directory: \"{0}\"", (object) this.stringTable[index2]);
|
||||
if ((int) strArray[index1][strArray[index1].Length - 1] != (int) Path.DirectorySeparatorChar)
|
||||
{
|
||||
// ISSUE: explicit reference operation
|
||||
strArray[index1] += Path.DirectorySeparatorChar.ToString();
|
||||
}
|
||||
Directory.CreateDirectory(strArray[index1] + this.stringTable[index2]);
|
||||
strArray[index1 + 1] = strArray[index1] + this.stringTable[index2];
|
||||
++index1;
|
||||
numArray[index1] = (int) this.u8Nodes[index2].SizeOfData;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.fireDebug(" -> File: \"{0}\"", (object) this.stringTable[index2]);
|
||||
this.fireDebug(" -> Size: {0} bytes", (object) this.data[index2].Length);
|
||||
using (FileStream fileStream = new FileStream(strArray[index1] + Path.DirectorySeparatorChar.ToString() + this.stringTable[index2], FileMode.Create))
|
||||
fileStream.Write(this.data[index2], 0, this.data[index2].Length);
|
||||
}
|
||||
while (index1 > 0 && numArray[index1] == index2 + 2)
|
||||
--index1;
|
||||
}
|
||||
this.fireDebug("Unpacking U8 File Finished");
|
||||
}
|
||||
|
||||
private void parseU8(Stream u8File)
|
||||
{
|
||||
this.fireDebug("Pasing U8 File...");
|
||||
this.u8Header = new U8_Header();
|
||||
this.rootNode = new U8_Node();
|
||||
this.u8Nodes = new List<U8_Node>();
|
||||
this.stringTable = new List<string>();
|
||||
this.data = new List<byte[]>();
|
||||
this.fireDebug(" Detecting Header...");
|
||||
this.headerType = Headers.DetectHeader(u8File);
|
||||
Headers.HeaderType headerType = this.headerType;
|
||||
this.fireDebug(" -> {0}", (object) this.headerType.ToString());
|
||||
if (this.headerType == Headers.HeaderType.IMD5)
|
||||
{
|
||||
this.fireDebug(" Reading IMD5 Header...");
|
||||
this.header = (object) Headers.IMD5.Load(u8File);
|
||||
byte[] buffer = new byte[u8File.Length];
|
||||
u8File.Read(buffer, 0, buffer.Length);
|
||||
MD5 md5 = MD5.Create();
|
||||
byte[] hash1 = md5.ComputeHash(buffer, (int) this.headerType, (int) ((int) u8File.Length - this.headerType));
|
||||
md5.Clear();
|
||||
byte[] hash2 = ((Headers.IMD5) this.header).Hash;
|
||||
if (!Shared.CompareByteArrays(hash1, hash2))
|
||||
{
|
||||
this.fireDebug("/!\\ /!\\ /!\\ Hashes do not match /!\\ /!\\ /!\\");
|
||||
this.fireWarning("Hashes of IMD5 header and file do not match! The content might be corrupted!");
|
||||
}
|
||||
}
|
||||
else if (this.headerType == Headers.HeaderType.IMET || this.headerType == Headers.HeaderType.ShortIMET)
|
||||
{
|
||||
this.fireDebug(" Reading IMET Header...");
|
||||
this.header = (object) Headers.IMET.Load(u8File);
|
||||
if (!((Headers.IMET) this.header).HashesMatch)
|
||||
{
|
||||
this.fireDebug("/!\\ /!\\ /!\\ Hashes do not match /!\\ /!\\ /!\\");
|
||||
this.fireWarning("The hash stored in the IMET header doesn't match the headers hash! The header and/or file might be corrupted!");
|
||||
}
|
||||
}
|
||||
this.fireDebug(" Checking for Lz77 Compression...");
|
||||
if (Lz77.IsLz77Compressed(u8File))
|
||||
{
|
||||
this.fireDebug(" -> Lz77 Compression Found...");
|
||||
this.fireDebug(" Decompressing U8 Data...");
|
||||
Stream file = new Lz77().Decompress(u8File);
|
||||
headerType = Headers.DetectHeader(file);
|
||||
u8File = file;
|
||||
this.lz77 = true;
|
||||
}
|
||||
u8File.Seek((long) headerType, SeekOrigin.Begin);
|
||||
byte[] buffer1 = new byte[4];
|
||||
this.fireDebug(" Reading U8 Header: Magic... (Offset: 0x{0})", (object) u8File.Position.ToString("x8").ToUpper());
|
||||
u8File.Read(buffer1, 0, 4);
|
||||
if ((int) Shared.Swap(BitConverter.ToUInt32(buffer1, 0)) != (int) this.u8Header.U8Magic)
|
||||
{
|
||||
this.fireDebug(" -> Invalid Magic!");
|
||||
throw new Exception("U8 Header: Invalid Magic!");
|
||||
}
|
||||
this.fireDebug(" Reading U8 Header: Offset to Rootnode... (Offset: 0x{0})", (object) u8File.Position.ToString("x8").ToUpper());
|
||||
u8File.Read(buffer1, 0, 4);
|
||||
if ((int) Shared.Swap(BitConverter.ToUInt32(buffer1, 0)) != (int) this.u8Header.OffsetToRootNode)
|
||||
{
|
||||
this.fireDebug(" -> Invalid Offset to Rootnode");
|
||||
throw new Exception("U8 Header: Invalid Offset to Rootnode!");
|
||||
}
|
||||
this.fireDebug(" Reading U8 Header: Header Size... (Offset: 0x{0})", (object) u8File.Position.ToString("x8").ToUpper());
|
||||
u8File.Read(buffer1, 0, 4);
|
||||
this.u8Header.HeaderSize = Shared.Swap(BitConverter.ToUInt32(buffer1, 0));
|
||||
this.fireDebug(" Reading U8 Header: Offset to Data... (Offset: 0x{0})", (object) u8File.Position.ToString("x8").ToUpper());
|
||||
u8File.Read(buffer1, 0, 4);
|
||||
this.u8Header.OffsetToData = Shared.Swap(BitConverter.ToUInt32(buffer1, 0));
|
||||
u8File.Seek(16L, SeekOrigin.Current);
|
||||
object[] objArray1 = new object[1];
|
||||
long position1 = u8File.Position;
|
||||
objArray1[0] = (object) position1.ToString("x8").ToUpper();
|
||||
this.fireDebug(" Reading Rootnode... (Offset: 0x{0})", objArray1);
|
||||
u8File.Read(buffer1, 0, 4);
|
||||
this.rootNode.Type = (U8_NodeType) Shared.Swap(BitConverter.ToUInt16(buffer1, 0));
|
||||
this.rootNode.OffsetToName = Shared.Swap(BitConverter.ToUInt16(buffer1, 2));
|
||||
u8File.Read(buffer1, 0, 4);
|
||||
this.rootNode.OffsetToData = Shared.Swap(BitConverter.ToUInt32(buffer1, 0));
|
||||
u8File.Read(buffer1, 0, 4);
|
||||
this.rootNode.SizeOfData = Shared.Swap(BitConverter.ToUInt32(buffer1, 0));
|
||||
int num = (int) ((long) headerType + (long) this.u8Header.OffsetToRootNode + (long) (this.rootNode.SizeOfData * 12U));
|
||||
int position2 = (int) u8File.Position;
|
||||
for (int index = 0; (long) index < (long) (this.rootNode.SizeOfData - 1U); ++index)
|
||||
{
|
||||
object[] objArray2 = new object[3];
|
||||
position1 = u8File.Position;
|
||||
objArray2[0] = (object) position1.ToString("x8").ToUpper();
|
||||
objArray2[1] = (object) (index + 1);
|
||||
objArray2[2] = (object) (uint) ((int) this.rootNode.SizeOfData - 1);
|
||||
this.fireDebug(" Reading Node #{1} of {2}... (Offset: 0x{0})", objArray2);
|
||||
this.fireProgress((int) ((long) ((index + 1) * 100) / (long) (this.rootNode.SizeOfData - 1U)));
|
||||
U8_Node u8Node = new U8_Node();
|
||||
string empty = string.Empty;
|
||||
byte[] numArray = new byte[0];
|
||||
u8File.Seek((long) position2, SeekOrigin.Begin);
|
||||
object[] objArray3 = new object[1];
|
||||
position1 = u8File.Position;
|
||||
objArray3[0] = (object) position1.ToString("x8").ToUpper();
|
||||
this.fireDebug(" -> Reading Node Entry... (Offset: 0x{0})", objArray3);
|
||||
u8File.Read(buffer1, 0, 4);
|
||||
u8Node.Type = (U8_NodeType) Shared.Swap(BitConverter.ToUInt16(buffer1, 0));
|
||||
u8Node.OffsetToName = Shared.Swap(BitConverter.ToUInt16(buffer1, 2));
|
||||
u8File.Read(buffer1, 0, 4);
|
||||
u8Node.OffsetToData = Shared.Swap(BitConverter.ToUInt32(buffer1, 0));
|
||||
u8File.Read(buffer1, 0, 4);
|
||||
u8Node.SizeOfData = Shared.Swap(BitConverter.ToUInt32(buffer1, 0));
|
||||
position2 = (int) u8File.Position;
|
||||
this.fireDebug(" -> {0}", (object) u8Node.Type.ToString());
|
||||
u8File.Seek((long) (num + (int) u8Node.OffsetToName), SeekOrigin.Begin);
|
||||
object[] objArray4 = new object[1];
|
||||
position1 = u8File.Position;
|
||||
objArray4[0] = (object) position1.ToString("x8").ToUpper();
|
||||
this.fireDebug(" -> Reading Node Name... (Offset: 0x{0})", objArray4);
|
||||
do
|
||||
{
|
||||
char ch = (char) u8File.ReadByte();
|
||||
if (ch != char.MinValue)
|
||||
empty += ch.ToString();
|
||||
else
|
||||
break;
|
||||
}
|
||||
while (empty.Length <= (int) byte.MaxValue);
|
||||
this.fireDebug(" -> {0}", (object) empty);
|
||||
if (u8Node.Type == U8_NodeType.File)
|
||||
{
|
||||
u8File.Seek((long) headerType + (long) u8Node.OffsetToData, SeekOrigin.Begin);
|
||||
object[] objArray5 = new object[1];
|
||||
position1 = u8File.Position;
|
||||
objArray5[0] = (object) position1.ToString("x8").ToUpper();
|
||||
this.fireDebug(" -> Reading Node Data (Offset: 0x{0})", objArray5);
|
||||
numArray = new byte[(int) u8Node.SizeOfData];
|
||||
u8File.Read(numArray, 0, numArray.Length);
|
||||
}
|
||||
if (empty.ToLower() == "icon.bin")
|
||||
this.iconSize = this.getRealSize(numArray);
|
||||
else if (empty.ToLower() == "banner.bin")
|
||||
this.bannerSize = this.getRealSize(numArray);
|
||||
else if (empty.ToLower() == "sound.bin")
|
||||
this.soundSize = this.getRealSize(numArray);
|
||||
this.u8Nodes.Add(u8Node);
|
||||
this.stringTable.Add(empty);
|
||||
this.data.Add(numArray);
|
||||
}
|
||||
this.fireDebug("Pasing U8 File Finished...");
|
||||
}
|
||||
|
||||
private void createFromDir(string path)
|
||||
{
|
||||
this.fireDebug("Creating U8 File from: {0}", (object) path);
|
||||
if ((int) path[path.Length - 1] != (int) Path.DirectorySeparatorChar)
|
||||
path += Path.DirectorySeparatorChar.ToString();
|
||||
this.fireDebug(" Collecting Content...");
|
||||
string[] dirContent = this.getDirContent(path, true);
|
||||
int num1 = 1;
|
||||
int num2 = 0;
|
||||
this.fireDebug(" Creating U8 Header...");
|
||||
this.u8Header = new U8_Header();
|
||||
this.rootNode = new U8_Node();
|
||||
this.u8Nodes = new List<U8_Node>();
|
||||
this.stringTable = new List<string>();
|
||||
this.data = new List<byte[]>();
|
||||
this.fireDebug(" Creating Rootnode...");
|
||||
this.rootNode.Type = U8_NodeType.Directory;
|
||||
this.rootNode.OffsetToName = (ushort) 0;
|
||||
this.rootNode.OffsetToData = 0U;
|
||||
this.rootNode.SizeOfData = (uint) (dirContent.Length + 1);
|
||||
for (int index1 = 0; index1 < dirContent.Length; ++index1)
|
||||
{
|
||||
this.fireDebug(" Creating Node #{0} of {1}", (object) (index1 + 1), (object) dirContent.Length);
|
||||
this.fireProgress((index1 + 1) * 100 / dirContent.Length);
|
||||
U8_Node u8Node = new U8_Node();
|
||||
byte[] data = new byte[0];
|
||||
string theString = dirContent[index1].Remove(0, path.Length - 1);
|
||||
if (Directory.Exists(dirContent[index1]))
|
||||
{
|
||||
this.fireDebug(" -> Directory");
|
||||
u8Node.Type = U8_NodeType.Directory;
|
||||
u8Node.OffsetToData = (uint) Shared.CountCharsInString(theString, Path.DirectorySeparatorChar);
|
||||
int num3 = this.u8Nodes.Count + 2;
|
||||
for (int index2 = 0; index2 < dirContent.Length; ++index2)
|
||||
{
|
||||
if (dirContent[index2].Contains(dirContent[index1] + "\\"))
|
||||
++num3;
|
||||
}
|
||||
u8Node.SizeOfData = (uint) num3;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.fireDebug(" -> File");
|
||||
this.fireDebug(" -> Reading File Data...");
|
||||
data = File.ReadAllBytes(dirContent[index1]);
|
||||
u8Node.Type = U8_NodeType.File;
|
||||
u8Node.OffsetToData = (uint) num2;
|
||||
u8Node.SizeOfData = (uint) data.Length;
|
||||
num2 += Shared.AddPadding(num2 + data.Length, 32);
|
||||
}
|
||||
u8Node.OffsetToName = (ushort) num1;
|
||||
num1 += Path.GetFileName(dirContent[index1]).Length + 1;
|
||||
this.fireDebug(" -> Reading Name...");
|
||||
string fileName = Path.GetFileName(dirContent[index1]);
|
||||
if (fileName.ToLower() == "icon.bin")
|
||||
this.iconSize = this.getRealSize(data);
|
||||
else if (fileName.ToLower() == "banner.bin")
|
||||
this.bannerSize = this.getRealSize(data);
|
||||
else if (fileName.ToLower() == "sound.bin")
|
||||
this.soundSize = this.getRealSize(data);
|
||||
this.u8Nodes.Add(u8Node);
|
||||
this.stringTable.Add(fileName);
|
||||
this.data.Add(data);
|
||||
}
|
||||
this.fireDebug(" Updating U8 Header...");
|
||||
this.u8Header.HeaderSize = (uint) ((this.u8Nodes.Count + 1) * 12 + num1);
|
||||
this.u8Header.OffsetToData = (uint) Shared.AddPadding((int) this.u8Header.OffsetToRootNode + (int) this.u8Header.HeaderSize, 32);
|
||||
this.fireDebug(" Calculating Data Offsets...");
|
||||
for (int index = 0; index < this.u8Nodes.Count; ++index)
|
||||
{
|
||||
this.fireDebug(" -> Node #{0} of {1}...", (object) (index + 1), (object) this.u8Nodes.Count);
|
||||
int offsetToData = (int) this.u8Nodes[index].OffsetToData;
|
||||
this.u8Nodes[index].OffsetToData = (uint) ((ulong) this.u8Header.OffsetToData + (ulong) offsetToData);
|
||||
}
|
||||
this.fireDebug("Creating U8 File Finished...");
|
||||
}
|
||||
|
||||
private string[] getDirContent(string dir, bool root)
|
||||
{
|
||||
string[] files = Directory.GetFiles(dir);
|
||||
string[] directories = Directory.GetDirectories(dir);
|
||||
string str1 = "";
|
||||
if (!root)
|
||||
str1 = str1 + dir + "\n";
|
||||
for (int index = 0; index < files.Length; ++index)
|
||||
str1 = str1 + files[index] + "\n";
|
||||
foreach (string dir1 in directories)
|
||||
{
|
||||
foreach (string str2 in this.getDirContent(dir1, false))
|
||||
str1 = str1 + str2 + "\n";
|
||||
}
|
||||
return str1.Split(new char[1]{ '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
private int getRealSize(byte[] data)
|
||||
{
|
||||
if (data[0] != (byte) 73 || data[1] != (byte) 77 || (data[2] != (byte) 68 || data[3] != (byte) 53))
|
||||
return data.Length;
|
||||
return data[32] == (byte) 76 && data[33] == (byte) 90 && (data[34] == (byte) 55 && data[35] == (byte) 55) ? BitConverter.ToInt32(data, 36) >> 8 : data.Length - 32;
|
||||
}
|
||||
|
||||
private void addEntry(string nodePath, byte[] fileData)
|
||||
{
|
||||
if (nodePath.StartsWith("/"))
|
||||
nodePath = nodePath.Remove(0, 1);
|
||||
string[] strArray = nodePath.Split('/');
|
||||
int index1 = -1;
|
||||
int num1 = this.u8Nodes.Count > 0 ? this.u8Nodes.Count - 1 : 0;
|
||||
int num2 = 0;
|
||||
List<int> intList = new List<int>();
|
||||
for (int index2 = 0; index2 < strArray.Length - 1; ++index2)
|
||||
{
|
||||
for (int index3 = num2; index3 <= num1; ++index3)
|
||||
{
|
||||
if (!(this.stringTable[index3].ToLower() == strArray[index2].ToLower()))
|
||||
{
|
||||
if (index3 == num1 - 1)
|
||||
throw new Exception("Path wasn't found!");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index2 == strArray.Length - 2)
|
||||
index1 = index3;
|
||||
num1 = (int) this.u8Nodes[index3].SizeOfData - 1;
|
||||
num2 = index3 + 1;
|
||||
intList.Add(index3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
int num3 = index1 > -1 ? (int) this.u8Nodes[index1].SizeOfData - 2 : (this.rootNode.SizeOfData > 1U ? (int) this.rootNode.SizeOfData - 2 : -1);
|
||||
U8_Node u8Node = new U8_Node();
|
||||
u8Node.Type = fileData.Length == 0 ? U8_NodeType.Directory : U8_NodeType.File;
|
||||
u8Node.SizeOfData = fileData.Length == 0 ? (uint) (num3 + 2) : (uint) fileData.Length;
|
||||
u8Node.OffsetToData = fileData.Length == 0 ? (uint) Shared.CountCharsInString(nodePath, '/') : 0U;
|
||||
this.stringTable.Insert(num3 + 1, strArray[strArray.Length - 1]);
|
||||
this.u8Nodes.Insert(num3 + 1, u8Node);
|
||||
this.data.Insert(num3 + 1, fileData);
|
||||
++this.rootNode.SizeOfData;
|
||||
foreach (int index2 in intList)
|
||||
{
|
||||
if (this.u8Nodes[index2].Type == U8_NodeType.Directory)
|
||||
++this.u8Nodes[index2].SizeOfData;
|
||||
}
|
||||
for (int index2 = num3 + 1; index2 < this.u8Nodes.Count; ++index2)
|
||||
{
|
||||
if (this.u8Nodes[index2].Type == U8_NodeType.Directory)
|
||||
++this.u8Nodes[index2].SizeOfData;
|
||||
}
|
||||
}
|
||||
|
||||
private void removeEntry(string nodePath)
|
||||
{
|
||||
if (nodePath.StartsWith("/"))
|
||||
nodePath = nodePath.Remove(0, 1);
|
||||
string[] strArray = nodePath.Split('/');
|
||||
int index1 = -1;
|
||||
int num1 = this.u8Nodes.Count - 1;
|
||||
int num2 = 0;
|
||||
List<int> intList = new List<int>();
|
||||
for (int index2 = 0; index2 < strArray.Length; ++index2)
|
||||
{
|
||||
for (int index3 = num2; index3 < num1; ++index3)
|
||||
{
|
||||
if (!(this.stringTable[index3].ToLower() == strArray[index2].ToLower()))
|
||||
{
|
||||
if (index3 == num1 - 1)
|
||||
throw new Exception("Path wasn't found!");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index2 == strArray.Length - 1)
|
||||
index1 = index3;
|
||||
else
|
||||
intList.Add(index3);
|
||||
num1 = (int) this.u8Nodes[index3].SizeOfData - 1;
|
||||
num2 = index3 + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
int num3 = 0;
|
||||
if (this.u8Nodes[index1].Type == U8_NodeType.Directory)
|
||||
{
|
||||
for (int index2 = (int) this.u8Nodes[index1].SizeOfData - 2; index2 >= index1; --index2)
|
||||
{
|
||||
this.stringTable.RemoveAt(index2);
|
||||
this.u8Nodes.RemoveAt(index2);
|
||||
this.data.RemoveAt(index2);
|
||||
++num3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.stringTable.RemoveAt(index1);
|
||||
this.u8Nodes.RemoveAt(index1);
|
||||
this.data.RemoveAt(index1);
|
||||
++num3;
|
||||
}
|
||||
this.rootNode.SizeOfData -= (uint) num3;
|
||||
foreach (int index2 in intList)
|
||||
{
|
||||
if (this.u8Nodes[index2].Type == U8_NodeType.Directory)
|
||||
this.u8Nodes[index2].SizeOfData -= (uint) num3;
|
||||
}
|
||||
for (int index2 = index1 + 1; index2 < this.u8Nodes.Count; ++index2)
|
||||
{
|
||||
if (this.u8Nodes[index2].Type == U8_NodeType.Directory)
|
||||
this.u8Nodes[index2].SizeOfData -= (uint) num3;
|
||||
}
|
||||
}
|
||||
|
||||
private void fireWarning(string warningMessage)
|
||||
{
|
||||
EventHandler<MessageEventArgs> warning = this.Warning;
|
||||
if (warning == null)
|
||||
return;
|
||||
warning(new object(), new MessageEventArgs(warningMessage));
|
||||
}
|
||||
|
||||
private void fireDebug(string debugMessage, params object[] args)
|
||||
{
|
||||
EventHandler<MessageEventArgs> debug = this.Debug;
|
||||
if (debug == null)
|
||||
return;
|
||||
debug(new object(), new MessageEventArgs(string.Format(debugMessage, args)));
|
||||
}
|
||||
|
||||
private void fireProgress(int progressPercentage)
|
||||
{
|
||||
EventHandler<ProgressChangedEventArgs> progress = this.Progress;
|
||||
if (progress == null)
|
||||
return;
|
||||
progress(new object(), new ProgressChangedEventArgs(progressPercentage, (object) string.Empty));
|
||||
}
|
||||
}
|
||||
}
|
47
U8_Header.cs
Normal file
47
U8_Header.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.U8_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 U8_Header
|
||||
{
|
||||
private uint u8Magic = 1437218861;
|
||||
private uint offsetToRootNode = 32;
|
||||
private uint headerSize;
|
||||
private uint offsetToData;
|
||||
private byte[] padding = new byte[16];
|
||||
|
||||
public uint U8Magic => this.u8Magic;
|
||||
|
||||
public uint OffsetToRootNode => this.offsetToRootNode;
|
||||
|
||||
public uint HeaderSize
|
||||
{
|
||||
get => this.headerSize;
|
||||
set => this.headerSize = value;
|
||||
}
|
||||
|
||||
public uint OffsetToData
|
||||
{
|
||||
get => this.offsetToData;
|
||||
set => this.offsetToData = value;
|
||||
}
|
||||
|
||||
public byte[] Padding => this.padding;
|
||||
|
||||
public void Write(Stream writeStream)
|
||||
{
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.u8Magic)), 0, 4);
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.offsetToRootNode)), 0, 4);
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.headerSize)), 0, 4);
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.offsetToData)), 0, 4);
|
||||
writeStream.Write(this.padding, 0, 16);
|
||||
}
|
||||
}
|
||||
}
|
51
U8_Node.cs
Normal file
51
U8_Node.cs
Normal file
|
@ -0,0 +1,51 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.U8_Node
|
||||
// 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 U8_Node
|
||||
{
|
||||
private ushort type;
|
||||
private ushort offsetToName;
|
||||
private uint offsetToData;
|
||||
private uint sizeOfData;
|
||||
|
||||
public U8_NodeType Type
|
||||
{
|
||||
get => (U8_NodeType) this.type;
|
||||
set => this.type = (ushort) value;
|
||||
}
|
||||
|
||||
public ushort OffsetToName
|
||||
{
|
||||
get => this.offsetToName;
|
||||
set => this.offsetToName = value;
|
||||
}
|
||||
|
||||
public uint OffsetToData
|
||||
{
|
||||
get => this.offsetToData;
|
||||
set => this.offsetToData = value;
|
||||
}
|
||||
|
||||
public uint SizeOfData
|
||||
{
|
||||
get => this.sizeOfData;
|
||||
set => this.sizeOfData = value;
|
||||
}
|
||||
|
||||
public void Write(Stream writeStream)
|
||||
{
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.type)), 0, 2);
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.offsetToName)), 0, 2);
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.offsetToData)), 0, 4);
|
||||
writeStream.Write(BitConverter.GetBytes(Shared.Swap(this.sizeOfData)), 0, 4);
|
||||
}
|
||||
}
|
||||
}
|
14
U8_NodeType.cs
Normal file
14
U8_NodeType.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.U8_NodeType
|
||||
// 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 U8_NodeType : ushort
|
||||
{
|
||||
File = 0,
|
||||
Directory = 256, // 0x0100
|
||||
}
|
||||
}
|
68
WAD_Header.cs
Normal file
68
WAD_Header.cs
Normal file
|
@ -0,0 +1,68 @@
|
|||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
208
Wave.cs
Normal file
208
Wave.cs
Normal file
|
@ -0,0 +1,208 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.Wave
|
||||
// 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 Wave : IDisposable
|
||||
{
|
||||
private WaveHeader header = new WaveHeader();
|
||||
private WaveFmtChunk fmt = new WaveFmtChunk();
|
||||
private WaveDataChunk data = new WaveDataChunk();
|
||||
private WaveSmplChunk smpl = new WaveSmplChunk();
|
||||
private bool hasSmpl;
|
||||
private bool isDisposed;
|
||||
|
||||
public int SampleRate => (int) this.fmt.SampleRate;
|
||||
|
||||
public int BitDepth => (int) this.fmt.BitsPerSample;
|
||||
|
||||
public int NumChannels => (int) this.fmt.NumChannels;
|
||||
|
||||
public int NumLoops => !this.hasSmpl ? 0 : (int) this.smpl.NumLoops;
|
||||
|
||||
public int LoopStart => this.NumLoops == 0 ? 0 : (int) this.smpl.Loops[0].LoopStart;
|
||||
|
||||
public int NumSamples => (int) ((long) this.data.DataSize / (long) ((int) this.fmt.BitsPerSample / 8) / (long) this.fmt.NumChannels);
|
||||
|
||||
public int DataFormat => (int) this.fmt.AudioFormat;
|
||||
|
||||
public byte[] SampleData => this.data.Data;
|
||||
|
||||
public int PlayLength => (int) ((long) (this.data.DataSize / (uint) this.fmt.NumChannels) / (long) ((int) this.fmt.BitsPerSample / 8) / (long) this.fmt.SampleRate);
|
||||
|
||||
public Wave(string pathToFile)
|
||||
{
|
||||
using (FileStream fileStream = new FileStream(pathToFile, FileMode.Open))
|
||||
{
|
||||
using (BinaryReader reader = new BinaryReader((Stream) fileStream))
|
||||
this.parseWave(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public Wave(Stream wave) => this.parseWave(new BinaryReader(wave));
|
||||
|
||||
public Wave(byte[] waveFile)
|
||||
{
|
||||
using (MemoryStream memoryStream = new MemoryStream(waveFile))
|
||||
{
|
||||
using (BinaryReader reader = new BinaryReader((Stream) memoryStream))
|
||||
this.parseWave(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public Wave(int numChannels, int bitsPerSample, int sampleRate, byte[] samples)
|
||||
{
|
||||
this.fmt.SampleRate = (uint) sampleRate;
|
||||
this.fmt.NumChannels = (ushort) numChannels;
|
||||
this.fmt.BitsPerSample = (ushort) bitsPerSample;
|
||||
this.data.Data = samples;
|
||||
}
|
||||
|
||||
~Wave() => this.Dispose(false);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize((object) this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && !this.isDisposed)
|
||||
{
|
||||
this.header = (WaveHeader) null;
|
||||
this.fmt = (WaveFmtChunk) null;
|
||||
this.data = (WaveDataChunk) null;
|
||||
this.smpl = (WaveSmplChunk) null;
|
||||
}
|
||||
this.isDisposed = true;
|
||||
}
|
||||
|
||||
public void Write(Stream writeStream) => this.writeToStream(new BinaryWriter(writeStream));
|
||||
|
||||
public MemoryStream ToMemoryStream()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
this.writeToStream(new BinaryWriter((Stream) memoryStream));
|
||||
return memoryStream;
|
||||
}
|
||||
|
||||
public byte[] ToByteArray() => this.ToMemoryStream().ToArray();
|
||||
|
||||
public void Save(string savePath)
|
||||
{
|
||||
using (FileStream fileStream = new FileStream(savePath, FileMode.Create))
|
||||
{
|
||||
using (BinaryWriter writer = new BinaryWriter((Stream) fileStream))
|
||||
this.writeToStream(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddLoop(int loopStartSample)
|
||||
{
|
||||
this.smpl.AddLoop(loopStartSample, this.NumSamples);
|
||||
this.hasSmpl = true;
|
||||
}
|
||||
|
||||
public void RemoveLoop() => this.hasSmpl = false;
|
||||
|
||||
public void TrimStart(int newStartSample)
|
||||
{
|
||||
int offset = (int) this.fmt.NumChannels * ((int) this.fmt.BitsPerSample / 8) * newStartSample;
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
memoryStream.Write(this.data.Data, offset, this.data.Data.Length - offset);
|
||||
this.data.Data = memoryStream.ToArray();
|
||||
memoryStream.Dispose();
|
||||
}
|
||||
|
||||
private void writeToStream(BinaryWriter writer)
|
||||
{
|
||||
this.header.FileSize = (uint) (4 + (int) this.fmt.FmtSize + 8 + (int) this.data.DataSize + 8 + (this.hasSmpl ? (int) this.smpl.SmplSize + 8 : 0));
|
||||
this.header.Write(writer);
|
||||
this.fmt.Write(writer);
|
||||
this.data.Write(writer);
|
||||
if (!this.hasSmpl)
|
||||
return;
|
||||
this.smpl.Write(writer);
|
||||
}
|
||||
|
||||
private void parseWave(BinaryReader reader)
|
||||
{
|
||||
bool[] flagArray = new bool[3];
|
||||
while (reader.BaseStream.Position < reader.BaseStream.Length - 4L)
|
||||
{
|
||||
uint num1 = Shared.Swap(reader.ReadUInt32());
|
||||
uint num2 = reader.ReadUInt32();
|
||||
long offset = reader.BaseStream.Position + (long) num2;
|
||||
switch (num1)
|
||||
{
|
||||
case 1380533830:
|
||||
try
|
||||
{
|
||||
reader.BaseStream.Seek(-8L, SeekOrigin.Current);
|
||||
this.header.Read(reader);
|
||||
flagArray[0] = true;
|
||||
break;
|
||||
}
|
||||
catch
|
||||
{
|
||||
reader.BaseStream.Seek(offset, SeekOrigin.Begin);
|
||||
break;
|
||||
}
|
||||
case 1684108385:
|
||||
try
|
||||
{
|
||||
reader.BaseStream.Seek(-8L, SeekOrigin.Current);
|
||||
this.data.Read(reader);
|
||||
flagArray[2] = true;
|
||||
break;
|
||||
}
|
||||
catch
|
||||
{
|
||||
reader.BaseStream.Seek(offset, SeekOrigin.Begin);
|
||||
break;
|
||||
}
|
||||
case 1718449184:
|
||||
try
|
||||
{
|
||||
reader.BaseStream.Seek(-8L, SeekOrigin.Current);
|
||||
this.fmt.Read(reader);
|
||||
flagArray[1] = true;
|
||||
break;
|
||||
}
|
||||
catch
|
||||
{
|
||||
reader.BaseStream.Seek(offset, SeekOrigin.Begin);
|
||||
break;
|
||||
}
|
||||
case 1936552044:
|
||||
try
|
||||
{
|
||||
reader.BaseStream.Seek(-8L, SeekOrigin.Current);
|
||||
this.smpl.Read(reader);
|
||||
this.hasSmpl = true;
|
||||
break;
|
||||
}
|
||||
catch
|
||||
{
|
||||
reader.BaseStream.Seek(offset, SeekOrigin.Begin);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
reader.BaseStream.Seek((long) num2, SeekOrigin.Current);
|
||||
break;
|
||||
}
|
||||
if (flagArray[0] && flagArray[1] && (flagArray[2] && this.hasSmpl))
|
||||
break;
|
||||
}
|
||||
if (!flagArray[0] || !flagArray[1] || !flagArray[2])
|
||||
throw new Exception("Couldn't parse Wave file...");
|
||||
}
|
||||
}
|
||||
}
|
43
WaveDataChunk.cs
Normal file
43
WaveDataChunk.cs
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.WaveDataChunk
|
||||
// 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
|
||||
{
|
||||
internal class WaveDataChunk
|
||||
{
|
||||
private uint dataId = 1684108385;
|
||||
private uint dataSize = 8;
|
||||
private byte[] data;
|
||||
|
||||
public uint DataSize => this.dataSize;
|
||||
|
||||
public byte[] Data
|
||||
{
|
||||
get => this.data;
|
||||
set
|
||||
{
|
||||
this.data = value;
|
||||
this.dataSize = (uint) this.data.Length;
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(Shared.Swap(this.dataId));
|
||||
writer.Write(this.dataSize);
|
||||
writer.Write(this.data, 0, this.data.Length);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader reader)
|
||||
{
|
||||
this.dataSize = (int) Shared.Swap(reader.ReadUInt32()) == (int) this.dataId ? reader.ReadUInt32() : throw new Exception("Wrong chunk ID!");
|
||||
this.data = reader.ReadBytes((int) this.dataSize);
|
||||
}
|
||||
}
|
||||
}
|
70
WaveFmtChunk.cs
Normal file
70
WaveFmtChunk.cs
Normal file
|
@ -0,0 +1,70 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.WaveFmtChunk
|
||||
// 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
|
||||
{
|
||||
internal class WaveFmtChunk
|
||||
{
|
||||
private uint fmtId = 1718449184;
|
||||
private uint fmtSize = 16;
|
||||
private ushort audioFormat = 1;
|
||||
private ushort numChannels = 2;
|
||||
private uint sampleRate = 44100;
|
||||
private uint byteRate;
|
||||
private ushort blockAlign;
|
||||
private ushort bitsPerSample = 16;
|
||||
|
||||
public uint FmtSize => this.fmtSize;
|
||||
|
||||
public ushort NumChannels
|
||||
{
|
||||
get => this.numChannels;
|
||||
set => this.numChannels = value;
|
||||
}
|
||||
|
||||
public uint SampleRate
|
||||
{
|
||||
get => this.sampleRate;
|
||||
set => this.sampleRate = value;
|
||||
}
|
||||
|
||||
public ushort BitsPerSample
|
||||
{
|
||||
get => this.bitsPerSample;
|
||||
set => this.bitsPerSample = value;
|
||||
}
|
||||
|
||||
public uint AudioFormat => (uint) this.audioFormat;
|
||||
|
||||
public void Write(BinaryWriter writer)
|
||||
{
|
||||
this.byteRate = this.sampleRate * (uint) this.numChannels * (uint) this.bitsPerSample / 8U;
|
||||
this.blockAlign = (ushort) ((int) this.numChannels * (int) this.bitsPerSample / 8);
|
||||
writer.Write(Shared.Swap(this.fmtId));
|
||||
writer.Write(this.fmtSize);
|
||||
writer.Write(this.audioFormat);
|
||||
writer.Write(this.numChannels);
|
||||
writer.Write(this.sampleRate);
|
||||
writer.Write(this.byteRate);
|
||||
writer.Write(this.blockAlign);
|
||||
writer.Write(this.bitsPerSample);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader reader)
|
||||
{
|
||||
this.fmtSize = (int) Shared.Swap(reader.ReadUInt32()) == (int) this.fmtId ? reader.ReadUInt32() : throw new Exception("Wrong chunk ID!");
|
||||
this.audioFormat = reader.ReadUInt16();
|
||||
this.numChannels = reader.ReadUInt16();
|
||||
this.sampleRate = reader.ReadUInt32();
|
||||
this.byteRate = reader.ReadUInt32();
|
||||
this.blockAlign = reader.ReadUInt16();
|
||||
this.bitsPerSample = reader.ReadUInt16();
|
||||
}
|
||||
}
|
||||
}
|
38
WaveHeader.cs
Normal file
38
WaveHeader.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.WaveHeader
|
||||
// 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
|
||||
{
|
||||
internal class WaveHeader
|
||||
{
|
||||
private uint headerId = 1380533830;
|
||||
private uint fileSize = 12;
|
||||
private uint format = 1463899717;
|
||||
|
||||
public uint FileSize
|
||||
{
|
||||
get => this.fileSize;
|
||||
set => this.fileSize = value;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(Shared.Swap(this.headerId));
|
||||
writer.Write(this.fileSize);
|
||||
writer.Write(Shared.Swap(this.format));
|
||||
}
|
||||
|
||||
public void Read(BinaryReader reader)
|
||||
{
|
||||
this.fileSize = (int) Shared.Swap(reader.ReadUInt32()) == (int) this.headerId ? reader.ReadUInt32() : throw new Exception("Not a valid RIFF Wave file!");
|
||||
if ((int) Shared.Swap(reader.ReadUInt32()) != (int) this.format)
|
||||
throw new Exception("Not a valid RIFF Wave file!");
|
||||
}
|
||||
}
|
||||
}
|
88
WaveSmplChunk.cs
Normal file
88
WaveSmplChunk.cs
Normal file
|
@ -0,0 +1,88 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.WaveSmplChunk
|
||||
// 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.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace libWiiSharp
|
||||
{
|
||||
internal class WaveSmplChunk
|
||||
{
|
||||
private uint smplId = 1936552044;
|
||||
private uint smplSize = 36;
|
||||
private uint manufacturer;
|
||||
private uint product;
|
||||
private uint samplePeriod;
|
||||
private uint unityNote = 60;
|
||||
private uint pitchFraction;
|
||||
private uint smpteFormat;
|
||||
private uint smpteOffset;
|
||||
private uint numLoops;
|
||||
private uint samplerData;
|
||||
private List<WaveSmplLoop> smplLoops = new List<WaveSmplLoop>();
|
||||
|
||||
public uint SmplSize => this.smplSize;
|
||||
|
||||
public uint NumLoops => this.numLoops;
|
||||
|
||||
public WaveSmplLoop[] Loops => this.smplLoops.ToArray();
|
||||
|
||||
public void AddLoop(int loopStartSample, int loopEndSample)
|
||||
{
|
||||
this.RemoveAllLoops();
|
||||
++this.numLoops;
|
||||
this.smplLoops.Add(new WaveSmplLoop()
|
||||
{
|
||||
LoopStart = (uint) loopStartSample,
|
||||
LoopEnd = (uint) loopEndSample
|
||||
});
|
||||
}
|
||||
|
||||
public void RemoveAllLoops()
|
||||
{
|
||||
this.smplLoops.Clear();
|
||||
this.numLoops = 0U;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(Shared.Swap(this.smplId));
|
||||
writer.Write(this.smplSize);
|
||||
writer.Write(this.manufacturer);
|
||||
writer.Write(this.product);
|
||||
writer.Write(this.samplePeriod);
|
||||
writer.Write(this.unityNote);
|
||||
writer.Write(this.pitchFraction);
|
||||
writer.Write(this.smpteFormat);
|
||||
writer.Write(this.smpteOffset);
|
||||
writer.Write(this.numLoops);
|
||||
writer.Write(this.samplerData);
|
||||
for (int index = 0; (long) index < (long) this.numLoops; ++index)
|
||||
this.smplLoops[index].Write(writer);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader reader)
|
||||
{
|
||||
this.smplSize = (int) Shared.Swap(reader.ReadUInt32()) == (int) this.smplId ? reader.ReadUInt32() : throw new Exception("Wrong chunk ID!");
|
||||
this.manufacturer = reader.ReadUInt32();
|
||||
this.product = reader.ReadUInt32();
|
||||
this.samplePeriod = reader.ReadUInt32();
|
||||
this.unityNote = reader.ReadUInt32();
|
||||
this.pitchFraction = reader.ReadUInt32();
|
||||
this.smpteFormat = reader.ReadUInt32();
|
||||
this.smpteOffset = reader.ReadUInt32();
|
||||
this.numLoops = reader.ReadUInt32();
|
||||
this.samplerData = reader.ReadUInt32();
|
||||
for (int index = 0; (long) index < (long) this.numLoops; ++index)
|
||||
{
|
||||
WaveSmplLoop waveSmplLoop = new WaveSmplLoop();
|
||||
waveSmplLoop.Read(reader);
|
||||
this.smplLoops.Add(waveSmplLoop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
52
WaveSmplLoop.cs
Normal file
52
WaveSmplLoop.cs
Normal file
|
@ -0,0 +1,52 @@
|
|||
// Decompiled with JetBrains decompiler
|
||||
// Type: libWiiSharp.WaveSmplLoop
|
||||
// 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.IO;
|
||||
|
||||
namespace libWiiSharp
|
||||
{
|
||||
internal class WaveSmplLoop
|
||||
{
|
||||
private uint cuePointId;
|
||||
private uint type;
|
||||
private uint start;
|
||||
private uint end;
|
||||
private uint fraction;
|
||||
private uint playCount;
|
||||
|
||||
public uint LoopStart
|
||||
{
|
||||
get => this.start;
|
||||
set => this.start = value;
|
||||
}
|
||||
|
||||
public uint LoopEnd
|
||||
{
|
||||
get => this.end;
|
||||
set => this.end = value;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(this.cuePointId);
|
||||
writer.Write(this.type);
|
||||
writer.Write(this.start);
|
||||
writer.Write(this.end);
|
||||
writer.Write(this.fraction);
|
||||
writer.Write(this.playCount);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader reader)
|
||||
{
|
||||
this.cuePointId = reader.ReadUInt32();
|
||||
this.type = reader.ReadUInt32();
|
||||
this.start = reader.ReadUInt32();
|
||||
this.end = reader.ReadUInt32();
|
||||
this.fraction = reader.ReadUInt32();
|
||||
this.playCount = reader.ReadUInt32();
|
||||
}
|
||||
}
|
||||
}
|
97
libWiiSharp.csproj
Normal file
97
libWiiSharp.csproj
Normal file
|
@ -0,0 +1,97 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<!--Project was exported from assembly: C:\Users\theso\Downloads\NCPatcher\pack\libWiiSharp.dll-->
|
||||
<PropertyGroup>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{DA1DDE59-7F59-4EBA-91E9-B06729E8E131}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AssemblyName>libWiiSharp</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile />
|
||||
<ApplicationVersion>0.4.0.0</ApplicationVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<RootNamespace>libWiiSharp</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BNS.cs" />
|
||||
<Compile Include="BNS_Data.cs" />
|
||||
<Compile Include="BNS_Header.cs" />
|
||||
<Compile Include="BNS_Info.cs" />
|
||||
<Compile Include="Brlan.cs" />
|
||||
<Compile Include="Brlyt.cs" />
|
||||
<Compile Include="CertificateChain.cs" />
|
||||
<Compile Include="ColorIndexConverter.cs" />
|
||||
<Compile Include="CommonKey.cs" />
|
||||
<Compile Include="CommonKeyType.cs" />
|
||||
<Compile Include="ContentIndices.cs" />
|
||||
<Compile Include="ContentType.cs" />
|
||||
<Compile Include="HbcTransmitter.cs" />
|
||||
<Compile Include="Headers.cs" />
|
||||
<Compile Include="HexView.cs" />
|
||||
<Compile Include="IosPatcher.cs" />
|
||||
<Compile Include="LowerTitleID.cs" />
|
||||
<Compile Include="Lz77.cs" />
|
||||
<Compile Include="MessageEventArgs.cs" />
|
||||
<Compile Include="NusClient.cs" />
|
||||
<Compile Include="Protocol.cs" />
|
||||
<Compile Include="Region.cs" />
|
||||
<Compile Include="Shared.cs" />
|
||||
<Compile Include="StoreType.cs" />
|
||||
<Compile Include="Ticket.cs" />
|
||||
<Compile Include="TMD.cs" />
|
||||
<Compile Include="TMD_Content.cs" />
|
||||
<Compile Include="TPL.cs" />
|
||||
<Compile Include="TPL_Header.cs" />
|
||||
<Compile Include="TPL_PaletteFormat.cs" />
|
||||
<Compile Include="TPL_PaletteHeader.cs" />
|
||||
<Compile Include="TPL_TextureEntry.cs" />
|
||||
<Compile Include="TPL_TextureFormat.cs" />
|
||||
<Compile Include="TPL_TextureHeader.cs" />
|
||||
<Compile Include="U8.cs" />
|
||||
<Compile Include="U8_Header.cs" />
|
||||
<Compile Include="U8_Node.cs" />
|
||||
<Compile Include="U8_NodeType.cs" />
|
||||
<Compile Include="WAD.cs" />
|
||||
<Compile Include="WAD_Header.cs" />
|
||||
<Compile Include="Wave.cs" />
|
||||
<Compile Include="WaveDataChunk.cs" />
|
||||
<Compile Include="WaveFmtChunk.cs" />
|
||||
<Compile Include="WaveHeader.cs" />
|
||||
<Compile Include="WaveSmplChunk.cs" />
|
||||
<Compile Include="WaveSmplLoop.cs" />
|
||||
<Compile Include="zlibWrapper.cs" />
|
||||
<Compile Include="AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
BIN
libWiiSharp.pdb
Normal file
BIN
libWiiSharp.pdb
Normal file
Binary file not shown.
20
libWiiSharp.sln
Normal file
20
libWiiSharp.sln
Normal file
|
@ -0,0 +1,20 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "libWiiSharp", "libWiiSharp.csproj", "{DA1DDE59-7F59-4EBA-91E9-B06729E8E131}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{DA1DDE59-7F59-4EBA-91E9-B06729E8E131}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DA1DDE59-7F59-4EBA-91E9-B06729E8E131}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DA1DDE59-7F59-4EBA-91E9-B06729E8E131}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DA1DDE59-7F59-4EBA-91E9-B06729E8E131}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
46
zlibWrapper.cs
Normal file
46
zlibWrapper.cs
Normal file
|
@ -0,0 +1,46 @@
|
|||
// 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<byte>(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,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue