mirror of
https://github.com/WiiDatabase/nusdownloader.git
synced 2024-11-23 18:59:16 +01:00
590 lines
20 KiB
C#
590 lines
20 KiB
C#
|
// Decompiled with JetBrains decompiler
|
|||
|
// Type: libWiiSharp.Headers
|
|||
|
// Assembly: NUS Downloader, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
|
|||
|
// MVID: DDAF9FEC-76DE-4BD8-8A6D-D7CAD5827AC6
|
|||
|
// Assembly location: C:\dotpeek\NUS Downloader.exe
|
|||
|
|
|||
|
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 headerStream = new MemoryStream(fileOrHeader);
|
|||
|
try
|
|||
|
{
|
|||
|
imet.parseHeader((Stream) headerStream);
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
headerStream.Dispose();
|
|||
|
throw;
|
|||
|
}
|
|||
|
headerStream.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 sourceIndex = Headers.DetectHeader(file);
|
|||
|
switch (sourceIndex)
|
|||
|
{
|
|||
|
case Headers.HeaderType.ShortIMET:
|
|||
|
case Headers.HeaderType.IMET:
|
|||
|
byte[] destinationArray = new byte[(int) (file.Length - sourceIndex)];
|
|||
|
Array.Copy((Array) file, (int) sourceIndex, (Array) destinationArray, 0, destinationArray.Length);
|
|||
|
return destinationArray;
|
|||
|
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 writeStream = new MemoryStream();
|
|||
|
try
|
|||
|
{
|
|||
|
this.writeToStream((Stream) writeStream);
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
writeStream.Dispose();
|
|||
|
throw;
|
|||
|
}
|
|||
|
return writeStream;
|
|||
|
}
|
|||
|
|
|||
|
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 ? 0 : 64);
|
|||
|
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 ? 0 : 64, 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 += (string) (object) ch;
|
|||
|
}
|
|||
|
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 headerStream = new MemoryStream(fileOrHeader);
|
|||
|
try
|
|||
|
{
|
|||
|
imD5.parseHeader((Stream) headerStream);
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
headerStream.Dispose();
|
|||
|
throw;
|
|||
|
}
|
|||
|
headerStream.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 writeStream = new MemoryStream();
|
|||
|
imD5.writeToStream((Stream) writeStream);
|
|||
|
writeStream.Write(file, 0, file.Length);
|
|||
|
byte[] array = writeStream.ToArray();
|
|||
|
writeStream.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 writeStream = new MemoryStream();
|
|||
|
try
|
|||
|
{
|
|||
|
this.writeToStream((Stream) writeStream);
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
writeStream.Dispose();
|
|||
|
throw;
|
|||
|
}
|
|||
|
return writeStream;
|
|||
|
}
|
|||
|
|
|||
|
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);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|