mirror of
https://github.com/WB3000/nusdownloader.git
synced 2024-11-17 07:09:21 +01:00
Added NusClient.cs for more OOP style NusDownloading. This will obviously require more testing.
This commit is contained in:
parent
06dc9af02d
commit
1738d8fab5
@ -48,7 +48,7 @@ namespace NUS_Downloader
|
|||||||
|
|
||||||
// TODO: Always remember to change version!
|
// TODO: Always remember to change version!
|
||||||
private string version = "v2.0 Beta";
|
private string version = "v2.0 Beta";
|
||||||
private WebClient generalWC = new WebClient();
|
|
||||||
private static RijndaelManaged rijndaelCipher;
|
private static RijndaelManaged rijndaelCipher;
|
||||||
private static bool dsidecrypt = false;
|
private static bool dsidecrypt = false;
|
||||||
|
|
||||||
@ -409,7 +409,7 @@ namespace NUS_Downloader
|
|||||||
if (opentmd.ShowDialog() != DialogResult.Cancel)
|
if (opentmd.ShowDialog() != DialogResult.Cancel)
|
||||||
{
|
{
|
||||||
// Read the tmd as a stream...
|
// Read the tmd as a stream...
|
||||||
byte[] tmd = FileLocationToByteArray(opentmd.FileName);
|
byte[] tmd = File.ReadAllBytes(opentmd.FileName);
|
||||||
WriteStatus("TMD Loaded (" + tmd.Length + " bytes)");
|
WriteStatus("TMD Loaded (" + tmd.Length + " bytes)");
|
||||||
|
|
||||||
// Read ID...
|
// Read ID...
|
||||||
@ -813,7 +813,8 @@ namespace NUS_Downloader
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void button3_Click(object sender, EventArgs e)
|
private void button3_Click(object sender, EventArgs e)
|
||||||
{ if (titleidbox.Text == String.Empty)
|
{
|
||||||
|
if (titleidbox.Text == String.Empty)
|
||||||
{
|
{
|
||||||
// Prevent mass deletion and fail
|
// Prevent mass deletion and fail
|
||||||
WriteStatus("Please enter a Title ID!");
|
WriteStatus("Please enter a Title ID!");
|
||||||
@ -864,7 +865,6 @@ namespace NUS_Downloader
|
|||||||
if (!(script_mode))
|
if (!(script_mode))
|
||||||
WriteStatus("Starting NUS Download. Please be patient!");
|
WriteStatus("Starting NUS Download. Please be patient!");
|
||||||
SetEnableforDownload(false);
|
SetEnableforDownload(false);
|
||||||
|
|
||||||
downloadstartbtn.Text = "Starting NUS Download!";
|
downloadstartbtn.Text = "Starting NUS Download!";
|
||||||
|
|
||||||
// Creates the directory
|
// Creates the directory
|
||||||
@ -873,41 +873,51 @@ namespace NUS_Downloader
|
|||||||
|
|
||||||
// Wii / DSi
|
// Wii / DSi
|
||||||
bool wiimode = (consoleCBox.SelectedIndex == 0);
|
bool wiimode = (consoleCBox.SelectedIndex == 0);
|
||||||
|
string activeNusUrl;
|
||||||
|
if (wiimode)
|
||||||
|
activeNusUrl = WII_NUS_URL;
|
||||||
|
else
|
||||||
|
activeNusUrl = DSI_NUS_URL;
|
||||||
|
|
||||||
string titleid = titleidbox.Text;
|
string titleid = titleidbox.Text;
|
||||||
|
string title_v = titleversion.Text;
|
||||||
|
|
||||||
// Set UserAgent to Wii value
|
// WebClient configuration
|
||||||
generalWC.Headers.Add("User-Agent", "wii libnup/1.0");
|
WebClient nusWC = new WebClient();
|
||||||
|
nusWC = ConfigureWithProxy(nusWC);
|
||||||
// Proxy
|
nusWC.Headers.Add("User-Agent", "wii libnup/1.0"); // Set UserAgent to Wii value
|
||||||
generalWC = ConfigureWithProxy(generalWC);
|
|
||||||
|
|
||||||
|
// Create\Configure NusClient
|
||||||
|
libWiiSharp.NusClient nusClient = new libWiiSharp.NusClient();
|
||||||
|
nusClient.ConfigureNusClient(nusWC);
|
||||||
|
nusClient.UseLocalFiles = localuse.Checked;
|
||||||
|
|
||||||
// Get placement directory early...
|
// Get placement directory early...
|
||||||
string titledirectory;
|
string titledirectory;
|
||||||
if (titleversion.Text == "")
|
if (titleversion.Text == "")
|
||||||
titledirectory = Path.Combine(CURRENT_DIR, titleid);
|
titledirectory = Path.Combine(CURRENT_DIR, titleid);
|
||||||
else
|
else
|
||||||
titledirectory = Path.Combine(CURRENT_DIR, (titleid + "v" + titleversion.Text));
|
titledirectory = Path.Combine(CURRENT_DIR, (titleid + "v" + title_v));
|
||||||
|
|
||||||
if (script_mode)
|
if (script_mode)
|
||||||
titledirectory = Path.Combine(CURRENT_DIR, "output_" + Path.GetFileNameWithoutExtension(script_filename));
|
titledirectory = Path.Combine(CURRENT_DIR, "output_" + Path.GetFileNameWithoutExtension(script_filename));
|
||||||
|
|
||||||
downloadstartbtn.Text = "Prerequisites: (0/2)";
|
downloadstartbtn.Text = "Prerequisites: (0/2)";
|
||||||
|
|
||||||
// Windows 7?
|
// Windows 7? Windows 7 Taskbar progress can be used.
|
||||||
if (IsWin7())
|
if (IsWin7())
|
||||||
{
|
|
||||||
// Windows 7 Taskbar progress can be used.
|
|
||||||
dlprogress.ShowInTaskbar = true;
|
dlprogress.ShowInTaskbar = true;
|
||||||
}
|
|
||||||
|
|
||||||
// Download TMD before the rest...
|
// Download TMD before the rest...
|
||||||
string tmdfull = "tmd";
|
string tmdfull = "tmd";
|
||||||
if (titleversion.Text != "")
|
if (String.IsNullOrEmpty(title_v) == false)
|
||||||
tmdfull += "." + titleversion.Text;
|
tmdfull += "." + title_v;
|
||||||
|
|
||||||
|
byte[] tmd;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
DownloadNUSFile(titleid, tmdfull, titledirectory, 0, wiimode);
|
tmd = nusClient.DownloadTMD(titleid, title_v, activeNusUrl);
|
||||||
|
//DownloadNUSFile(titleid, tmdfull, titledirectory, 0, wiimode);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -930,11 +940,13 @@ namespace NUS_Downloader
|
|||||||
wadnamebox.Enabled = false;
|
wadnamebox.Enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Download CETK after tmd...
|
// Download cetk (ticket) after tmd...
|
||||||
bool ticket_exists = true;
|
//bool ticket_exists = true;
|
||||||
|
byte[] cetkbuf = new byte[0];
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
DownloadNUSFile(titleid, "cetk", titledirectory, 0, wiimode);
|
cetkbuf = nusClient.DownloadTicket(titleid, activeNusUrl);
|
||||||
|
//DownloadNUSFile(titleid, "cetk", titledirectory, 0, wiimode);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -953,17 +965,18 @@ namespace NUS_Downloader
|
|||||||
packbox.Checked = false;
|
packbox.Checked = false;
|
||||||
decryptbox.Checked = false;
|
decryptbox.Checked = false;
|
||||||
WAD_Saveas_Filename = String.Empty;
|
WAD_Saveas_Filename = String.Empty;
|
||||||
ticket_exists = false;
|
//ticket_exists = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadstartbtn.Text = "Prerequisites: (2/2)";
|
downloadstartbtn.Text = "Prerequisites: (2/2)";
|
||||||
dlprogress.Value = 100;
|
dlprogress.Value = 100;
|
||||||
|
|
||||||
byte[] cetkbuf = new byte[0];
|
//byte[] cetkbuf = new byte[0];
|
||||||
byte[] titlekey = new byte[0];
|
byte[] titlekey = new byte[0];
|
||||||
if (ticket_exists)
|
if ((cetkbuf.Length > 0) == true)
|
||||||
{
|
{
|
||||||
// Create ticket file holder
|
// Create ticket file holder
|
||||||
cetkbuf = FileLocationToByteArray(Path.Combine(titledirectory, "cetk"));
|
//cetkbuf = FileLocationToByteArray(Path.Combine(titledirectory, "cetk"));
|
||||||
|
|
||||||
// Obtain TitleKey
|
// Obtain TitleKey
|
||||||
titlekey = new byte[16];
|
titlekey = new byte[16];
|
||||||
@ -1011,9 +1024,9 @@ namespace NUS_Downloader
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read the tmd as a stream...
|
// Read the tmd as a stream...
|
||||||
byte[] tmd = FileLocationToByteArray(Path.Combine(titledirectory, tmdfull));
|
//byte[] tmd = FileLocationToByteArray(Path.Combine(titledirectory, tmdfull));
|
||||||
|
|
||||||
if (ticket_exists == true)
|
if ((cetkbuf.Length > 0) == true)
|
||||||
{
|
{
|
||||||
// Locate Certs **************************************
|
// Locate Certs **************************************
|
||||||
if (!(CertsValid()))
|
if (!(CertsValid()))
|
||||||
@ -1028,25 +1041,22 @@ namespace NUS_Downloader
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read Title Version...
|
// Read Title Version...
|
||||||
string tmdversion = "";
|
if (String.IsNullOrEmpty(title_v))
|
||||||
for (int x = 476; x < 478; x++)
|
|
||||||
{
|
{
|
||||||
tmdversion += MakeProperLength(ConvertToHex(Convert.ToString(tmd[x])));
|
string tmdversion = "";
|
||||||
|
for (int x = 476; x < 478; x++)
|
||||||
|
{
|
||||||
|
tmdversion += MakeProperLength(ConvertToHex(Convert.ToString(tmd[x])));
|
||||||
|
}
|
||||||
|
titleversion.Text = Convert.ToString(int.Parse(tmdversion, System.Globalization.NumberStyles.HexNumber));
|
||||||
|
title_v = tmdversion;
|
||||||
}
|
}
|
||||||
titleversion.Text = Convert.ToString(int.Parse(tmdversion, System.Globalization.NumberStyles.HexNumber));
|
|
||||||
|
|
||||||
//Read System Version (Needed IOS)
|
//Read System Version (Needed IOS)
|
||||||
string sysversion = IOSNeededFromTMD(tmd);
|
string sysversion = IOSNeededFromTMD(tmd);
|
||||||
if (sysversion != "0")
|
if (sysversion != "0")
|
||||||
WriteStatus("Requires: IOS" + sysversion);
|
WriteStatus("Requires: IOS" + sysversion);
|
||||||
|
|
||||||
// Renaming would be ideal, but gives too many permission errors...
|
|
||||||
/*if ((CURRENT_DIR + titleid + "v" + titleversion.Text + Path.DirectorySeparatorChar.ToString()) != titledirectory)
|
|
||||||
{
|
|
||||||
Directory.Move(titledirectory, CURRENT_DIR + titleid + "v" + titleversion.Text + Path.DirectorySeparatorChar.ToString());
|
|
||||||
titledirectory = CURRENT_DIR + titleid + "v" + titleversion.Text + Path.DirectorySeparatorChar.ToString();
|
|
||||||
} */
|
|
||||||
|
|
||||||
// Read Content #...
|
// Read Content #...
|
||||||
string contentstrnum = "";
|
string contentstrnum = "";
|
||||||
for (int x = 478; x < 480; x++)
|
for (int x = 478; x < 480; x++)
|
||||||
@ -1054,7 +1064,7 @@ namespace NUS_Downloader
|
|||||||
contentstrnum += TrimLeadingZeros(Convert.ToString(tmd[x]));
|
contentstrnum += TrimLeadingZeros(Convert.ToString(tmd[x]));
|
||||||
}
|
}
|
||||||
WriteStatus("Content #: " + contentstrnum);
|
WriteStatus("Content #: " + contentstrnum);
|
||||||
downloadstartbtn.Text = "Content: (0/" + contentstrnum + ")";
|
downloadstartbtn.Text = String.Format("Content: (0/{0})", contentstrnum);
|
||||||
dlprogress.Value = 0;
|
dlprogress.Value = 0;
|
||||||
|
|
||||||
// Gather information...
|
// Gather information...
|
||||||
@ -1070,21 +1080,29 @@ namespace NUS_Downloader
|
|||||||
{
|
{
|
||||||
totalcontentsize += int.Parse(tmdsizes[i], System.Globalization.NumberStyles.HexNumber);
|
totalcontentsize += int.Parse(tmdsizes[i], System.Globalization.NumberStyles.HexNumber);
|
||||||
}
|
}
|
||||||
WriteStatus("Total Size: " + (long) totalcontentsize + " bytes");
|
WriteStatus("Total Size: " + (long)totalcontentsize + " bytes");
|
||||||
|
|
||||||
|
// Write files from NUS out...
|
||||||
|
File.WriteAllBytes(Path.Combine(titledirectory, tmdfull), tmd);
|
||||||
|
File.WriteAllBytes(Path.Combine(titledirectory, "cetk"), cetkbuf);
|
||||||
|
|
||||||
|
// Download each content
|
||||||
for (int i = 0; i < tmdcontents.Length; i++)
|
for (int i = 0; i < tmdcontents.Length; i++)
|
||||||
{
|
{
|
||||||
|
byte[] contbuf;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// If it exists we leave it...
|
// If it exists we leave it...
|
||||||
if ((localuse.Checked) && (File.Exists(Path.Combine(titledirectory, tmdcontents[i]))))
|
if ((nusClient.UseLocalFiles) && (File.Exists(Path.Combine(titledirectory, tmdcontents[i]))))
|
||||||
{
|
{
|
||||||
WriteStatus("Leaving local " + tmdcontents[i] + ".");
|
WriteStatus("Leaving local " + tmdcontents[i] + ".");
|
||||||
|
contbuf = File.ReadAllBytes(Path.Combine(titledirectory, tmdcontents[i]));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DownloadNUSFile(titleid, tmdcontents[i], titledirectory,
|
contbuf = nusClient.DownloadSingleContent(titleid, title_v, tmdcontents[i], activeNusUrl);
|
||||||
int.Parse(tmdsizes[i], System.Globalization.NumberStyles.HexNumber), wiimode);
|
//DownloadNUSFile(titleid, tmdcontents[i], titledirectory,
|
||||||
|
//int.Parse(tmdsizes[i], System.Globalization.NumberStyles.HexNumber), wiimode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -1099,6 +1117,9 @@ namespace NUS_Downloader
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (File.Exists(Path.Combine(titledirectory, tmdcontents[i])) == false)
|
||||||
|
File.WriteAllBytes(Path.Combine(titledirectory, tmdcontents[i]), contbuf);
|
||||||
|
|
||||||
// Progress reporting advances...
|
// Progress reporting advances...
|
||||||
downloadstartbtn.Text = String.Format("Content: ({0} / {1})", (i + 1), contentstrnum);
|
downloadstartbtn.Text = String.Format("Content: ({0} / {1})", (i + 1), contentstrnum);
|
||||||
currentcontentlocation += int.Parse(tmdsizes[i], System.Globalization.NumberStyles.HexNumber);
|
currentcontentlocation += int.Parse(tmdsizes[i], System.Globalization.NumberStyles.HexNumber);
|
||||||
@ -1107,8 +1128,8 @@ namespace NUS_Downloader
|
|||||||
if (decryptbox.Checked == true)
|
if (decryptbox.Checked == true)
|
||||||
{
|
{
|
||||||
// Create content file holder
|
// Create content file holder
|
||||||
byte[] contbuf =
|
//byte[] contbuf =
|
||||||
FileLocationToByteArray(Path.Combine(titledirectory, tmdcontents[i]));
|
//FileLocationToByteArray(Path.Combine(titledirectory, tmdcontents[i]));
|
||||||
|
|
||||||
// IV (00+IDX+more000)
|
// IV (00+IDX+more000)
|
||||||
byte[] iv = new byte[16];
|
byte[] iv = new byte[16];
|
||||||
@ -1164,6 +1185,11 @@ namespace NUS_Downloader
|
|||||||
{
|
{
|
||||||
PackWAD(titleid, tmdfull, titledirectory);
|
PackWAD(titleid, tmdfull, titledirectory);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NUSDownloader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
||||||
|
{
|
||||||
|
WAD_Saveas_Filename = String.Empty;
|
||||||
|
|
||||||
SetEnableforDownload(true);
|
SetEnableforDownload(true);
|
||||||
downloadstartbtn.Text = "Start NUS Download!";
|
downloadstartbtn.Text = "Start NUS Download!";
|
||||||
@ -1174,11 +1200,6 @@ namespace NUS_Downloader
|
|||||||
|
|
||||||
if (script_mode)
|
if (script_mode)
|
||||||
statusbox.Text = "";
|
statusbox.Text = "";
|
||||||
}
|
|
||||||
|
|
||||||
private void NUSDownloader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
|
||||||
{
|
|
||||||
WAD_Saveas_Filename = String.Empty;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1225,6 +1246,7 @@ namespace NUS_Downloader
|
|||||||
Directory.Delete(titledirectory, true);
|
Directory.Delete(titledirectory, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Downloads the NUS file.
|
/// Downloads the NUS file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -1252,7 +1274,7 @@ namespace NUS_Downloader
|
|||||||
// Download NUS file...
|
// Download NUS file...
|
||||||
generalWC.DownloadFile(nusfileurl, Path.Combine(placementdir, filename));
|
generalWC.DownloadFile(nusfileurl, Path.Combine(placementdir, filename));
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
private void StatusChange(string status)
|
private void StatusChange(string status)
|
||||||
{
|
{
|
||||||
WriteStatus(status);
|
WriteStatus(status);
|
||||||
@ -1293,8 +1315,8 @@ namespace NUS_Downloader
|
|||||||
packer.Certs = certsbuf;
|
packer.Certs = certsbuf;
|
||||||
|
|
||||||
// Read TMD/TIK into Packer.
|
// Read TMD/TIK into Packer.
|
||||||
packer.Ticket = FileLocationToByteArray(Path.Combine(totaldirectory, "cetk"));
|
packer.Ticket = File.ReadAllBytes(Path.Combine(totaldirectory, "cetk"));
|
||||||
packer.TMD = FileLocationToByteArray(Path.Combine(totaldirectory, tmdfilename));
|
packer.TMD = File.ReadAllBytes(Path.Combine(totaldirectory, tmdfilename));
|
||||||
|
|
||||||
// Get the TMD variables in here instead...
|
// Get the TMD variables in here instead...
|
||||||
int contentcount = ContentCount(packer.TMD);
|
int contentcount = ContentCount(packer.TMD);
|
||||||
@ -1325,7 +1347,7 @@ namespace NUS_Downloader
|
|||||||
byte[][] contents_array = new byte[contentcount][];
|
byte[][] contents_array = new byte[contentcount][];
|
||||||
for (int a = 0; a < contentcount; a++)
|
for (int a = 0; a < contentcount; a++)
|
||||||
{
|
{
|
||||||
contents_array[a] = FileLocationToByteArray(Path.Combine(totaldirectory, contentnames[a]));
|
contents_array[a] = File.ReadAllBytes(Path.Combine(totaldirectory, contentnames[a]));
|
||||||
}
|
}
|
||||||
packer.Contents = contents_array;
|
packer.Contents = contents_array;
|
||||||
|
|
||||||
@ -1512,7 +1534,7 @@ namespace NUS_Downloader
|
|||||||
if (File.Exists(Path.Combine(CURRENT_DIR, keyfile)) == true)
|
if (File.Exists(Path.Combine(CURRENT_DIR, keyfile)) == true)
|
||||||
{
|
{
|
||||||
// Read common key byte[]
|
// Read common key byte[]
|
||||||
return FileLocationToByteArray(Path.Combine(CURRENT_DIR, keyfile));
|
return File.ReadAllBytes(Path.Combine(CURRENT_DIR, keyfile));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return null;
|
return null;
|
||||||
@ -2188,7 +2210,8 @@ namespace NUS_Downloader
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads a file into a byte[]
|
/// Loads a file into a byte[]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -2200,7 +2223,7 @@ namespace NUS_Downloader
|
|||||||
byte[] filebytearray = ReadFully(fs, 460);
|
byte[] filebytearray = ReadFully(fs, 460);
|
||||||
fs.Close();
|
fs.Close();
|
||||||
return filebytearray;
|
return filebytearray;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the name of the packed WAD in the textbox.
|
/// Updates the name of the packed WAD in the textbox.
|
||||||
@ -3234,12 +3257,13 @@ namespace NUS_Downloader
|
|||||||
WriteStatus("Special thanks to:");
|
WriteStatus("Special thanks to:");
|
||||||
WriteStatus(" * Crediar for his wadmaker tool + source, and for the advice!");
|
WriteStatus(" * Crediar for his wadmaker tool + source, and for the advice!");
|
||||||
WriteStatus(" * SquidMan/Galaxy/comex/Xuzz for advice/sources.");
|
WriteStatus(" * SquidMan/Galaxy/comex/Xuzz for advice/sources.");
|
||||||
|
WriteStatus(" * Leathl for portions of libWiiSharp.");
|
||||||
WriteStatus(" * Pasta for database compilation assistance.");
|
WriteStatus(" * Pasta for database compilation assistance.");
|
||||||
WriteStatus(" * #WiiDev for answering the tough questions.");
|
|
||||||
WriteStatus(" * Anyone who helped beta test on GBATemp!");
|
|
||||||
WriteStatus(" * Famfamfam for the Silk Icon Set.");
|
|
||||||
WriteStatus(" * Wyatt O'Day for the Windows7ProgressBar Control.");
|
|
||||||
WriteStatus(" * Napo7 for testing proxy usage.");
|
WriteStatus(" * Napo7 for testing proxy usage.");
|
||||||
|
WriteStatus(" * Wyatt O'Day for the Windows7ProgressBar Control.");
|
||||||
|
WriteStatus(" * Famfamfam for the Silk Icon Set.");
|
||||||
|
WriteStatus(" * #WiiDev for answering the tough questions.");
|
||||||
|
WriteStatus(" * Anyone who helped beta test!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkBox1_CheckedChanged(object sender, EventArgs e)
|
private void checkBox1_CheckedChanged(object sender, EventArgs e)
|
||||||
|
@ -77,6 +77,7 @@
|
|||||||
<DependentUpon>Form1.cs</DependentUpon>
|
<DependentUpon>Form1.cs</DependentUpon>
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="NusClient.cs" />
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<EmbeddedResource Include="Form1.resx">
|
<EmbeddedResource Include="Form1.resx">
|
||||||
|
473
NUS Downloader/NusClient.cs
Normal file
473
NUS Downloader/NusClient.cs
Normal file
@ -0,0 +1,473 @@
|
|||||||
|
/* This file is part of libWiiSharp
|
||||||
|
* Copyright (C) 2009 Leathl
|
||||||
|
*
|
||||||
|
* libWiiSharp is free software: you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as published
|
||||||
|
* by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* libWiiSharp is distributed in the hope that it will be
|
||||||
|
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||||
|
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
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 = false;
|
||||||
|
//private bool continueWithoutTicket = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If true, existing local files will be used.
|
||||||
|
/// </summary>
|
||||||
|
public bool UseLocalFiles { get { return useLocalFiles; } set { useLocalFiles = value; } }
|
||||||
|
/// <summary>
|
||||||
|
/// If true, the download will be continued even if no ticket for the title is avaiable (WAD packaging and decryption are disabled).
|
||||||
|
/// </summary>
|
||||||
|
//public bool ContinueWithoutTicket { get { return continueWithoutTicket; } set { continueWithoutTicket = value; } }
|
||||||
|
|
||||||
|
#region IDisposable Members
|
||||||
|
private bool isDisposed = false;
|
||||||
|
|
||||||
|
~NusClient()
|
||||||
|
{
|
||||||
|
Dispose(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && !isDisposed)
|
||||||
|
{
|
||||||
|
wcNus.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
isDisposed = true;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Functions
|
||||||
|
|
||||||
|
public void ConfigureNusClient(WebClient wcReady)
|
||||||
|
{
|
||||||
|
wcNus = wcReady;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Grabs a TMD from NUS.
|
||||||
|
/// Leave the title version empty for the latest.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="titleId"></param>
|
||||||
|
/// <param name="titleVersion"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public byte[] DownloadTMD(string titleId, string titleVersion, string nusUrl)
|
||||||
|
{
|
||||||
|
if (titleId.Length != 16) throw new Exception("Title ID must be 16 characters long!");
|
||||||
|
return downloadTmd(titleId, titleVersion, nusUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Grabs a Ticket from NUS.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="titleId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public byte[] DownloadTicket(string titleId, string nusUrl)
|
||||||
|
{
|
||||||
|
if (titleId.Length != 16) throw new Exception("Title ID must be 16 characters long!");
|
||||||
|
return downloadTicket(titleId, nusUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Grabs a single content file and decrypts it.
|
||||||
|
/// Leave the title version empty for the latest.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="titleId"></param>
|
||||||
|
/// <param name="titleVersion"></param>
|
||||||
|
/// <param name="contentId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public byte[] DownloadSingleContent(string titleId, string titleVersion, string contentId, string nusUrl)
|
||||||
|
{
|
||||||
|
if (titleId.Length != 16) throw new Exception("Title ID must be 16 characters long!");
|
||||||
|
return downloadSingleContent(titleId, titleVersion, contentId, nusUrl);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Private Functions
|
||||||
|
private byte[] downloadSingleContent(string titleId, string titleVersion, string contentId, string nusUrl)
|
||||||
|
{
|
||||||
|
uint cId = uint.Parse(contentId, System.Globalization.NumberStyles.HexNumber);
|
||||||
|
contentId = cId.ToString("x8");
|
||||||
|
|
||||||
|
fireDebug("Downloading Content (Content ID: {0}) of Title {1} v{2}...", contentId, titleId, (string.IsNullOrEmpty(titleVersion)) ? "[Latest]" : titleVersion);
|
||||||
|
|
||||||
|
fireDebug(" Checking for Internet connection...");
|
||||||
|
if (!CheckInet())
|
||||||
|
{ fireDebug(" Connection not found..."); throw new Exception("You're not connected to the internet!"); }
|
||||||
|
|
||||||
|
fireProgress(0);
|
||||||
|
|
||||||
|
//string tmdFile = "tmd" + (string.IsNullOrEmpty(titleVersion) ? string.Empty : string.Format(".{0}", titleVersion));
|
||||||
|
string titleUrl = string.Format("{0}{1}/", nusUrl, titleId);
|
||||||
|
string contentIdString = contentId;
|
||||||
|
//int cIndex = 0;
|
||||||
|
|
||||||
|
/*Download TMD
|
||||||
|
fireDebug(" Downloading TMD...");
|
||||||
|
byte[] tmdArray = wcNus.DownloadData(titleUrl + tmdFile);
|
||||||
|
fireDebug(" Parsing TMD...");
|
||||||
|
TMD tmd = TMD.Load(tmdArray);*/
|
||||||
|
|
||||||
|
//fireProgress(20);
|
||||||
|
|
||||||
|
/*Search for Content ID in TMD
|
||||||
|
fireDebug(" Looking for Content ID {0} in TMD...", contentId);
|
||||||
|
bool foundContentId = false;
|
||||||
|
for (int i = 0; i < tmd.Contents.Length; i++)
|
||||||
|
if (tmd.Contents[i].ContentID == cId)
|
||||||
|
{
|
||||||
|
fireDebug(" Content ID {0} found in TMD...", contentId);
|
||||||
|
foundContentId = true;
|
||||||
|
contentIdString = tmd.Contents[i].ContentID.ToString("x8");
|
||||||
|
cIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundContentId)
|
||||||
|
{ fireDebug(" Content ID {0} wasn't found in TMD...", contentId); throw new Exception("Content ID wasn't found in the TMD!"); }
|
||||||
|
|
||||||
|
//Download Ticket
|
||||||
|
fireDebug(" Downloading Ticket...");
|
||||||
|
byte[] tikArray = wcNus.DownloadData(titleUrl + "cetk");
|
||||||
|
fireDebug(" Parsing Ticket...");
|
||||||
|
Ticket tik = Ticket.Load(tikArray);
|
||||||
|
|
||||||
|
fireProgress(40);
|
||||||
|
|
||||||
|
fireDebug(" Downloading Content... ({0} bytes)", tmd.Contents[cIndex].Size); */
|
||||||
|
|
||||||
|
byte[] encryptedContent = wcNus.DownloadData(titleUrl + contentIdString);
|
||||||
|
|
||||||
|
fireProgress(80);
|
||||||
|
|
||||||
|
/*
|
||||||
|
fireDebug(" Decrypting Content...");
|
||||||
|
byte[] decryptedContent = decryptContent(encryptedContent, cIndex, tik, tmd);
|
||||||
|
Array.Resize(ref decryptedContent, (int)tmd.Contents[cIndex].Size);
|
||||||
|
|
||||||
|
//Check SHA1
|
||||||
|
SHA1 s = SHA1.Create();
|
||||||
|
byte[] newSha = s.ComputeHash(decryptedContent);
|
||||||
|
|
||||||
|
if (!Shared.CompareByteArrays(newSha, tmd.Contents[cIndex].Hash))
|
||||||
|
{ fireDebug(@"/!\ /!\ /!\ Hashes do not match /!\ /!\ /!\"); throw new Exception("Hashes do not match!"); }
|
||||||
|
|
||||||
|
fireProgress(100);
|
||||||
|
|
||||||
|
fireDebug("Downloading Content (Content ID: {0}) of Title {1} v{2} Finished...", contentId, titleId, (string.IsNullOrEmpty(titleVersion)) ? "[Latest]" : titleVersion);
|
||||||
|
return decryptedContent;*/
|
||||||
|
return encryptedContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] downloadTicket(string titleId, string nusUrl)
|
||||||
|
{
|
||||||
|
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 tikArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] downloadTmd(string titleId, string titleVersion, string nusUrl)
|
||||||
|
{
|
||||||
|
if (!CheckInet())
|
||||||
|
throw new Exception("You're not connected to the internet!");
|
||||||
|
|
||||||
|
string titleUrl = string.Format("{0}{1}/", nusUrl, titleId);
|
||||||
|
string tmdFile = "tmd" + (string.IsNullOrEmpty(titleVersion) ? string.Empty : string.Format(".{0}", titleVersion));
|
||||||
|
|
||||||
|
byte[] tmdArray = wcNus.DownloadData(titleUrl + tmdFile);
|
||||||
|
|
||||||
|
return tmdArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*private void downloadTitle(string titleId, string titleVersion, string outputDir, StoreType[] storeTypes)
|
||||||
|
{
|
||||||
|
fireDebug("Downloading Title {0} v{1}...", titleId, (string.IsNullOrEmpty(titleVersion)) ? "[Latest]" : titleVersion);
|
||||||
|
|
||||||
|
if (storeTypes.Length < 1)
|
||||||
|
{ fireDebug(" No store types were defined..."); throw new Exception("You must at least define one store type!"); }
|
||||||
|
|
||||||
|
string titleUrl = string.Format("{0}{1}/", nusUrl, titleId);
|
||||||
|
bool storeEncrypted = false;
|
||||||
|
bool storeDecrypted = false;
|
||||||
|
bool storeWad = false;
|
||||||
|
|
||||||
|
fireProgress(0);
|
||||||
|
|
||||||
|
foreach (StoreType st in storeTypes)
|
||||||
|
{
|
||||||
|
switch (st)
|
||||||
|
{
|
||||||
|
case StoreType.DecryptedContent:
|
||||||
|
fireDebug(" -> Storing Decrypted Content...");
|
||||||
|
storeDecrypted = true;
|
||||||
|
break;
|
||||||
|
case StoreType.EncryptedContent:
|
||||||
|
fireDebug(" -> Storing Encrypted Content...");
|
||||||
|
storeEncrypted = true;
|
||||||
|
break;
|
||||||
|
case StoreType.WAD:
|
||||||
|
fireDebug(" -> Storing WAD...");
|
||||||
|
storeWad = true;
|
||||||
|
break;
|
||||||
|
case StoreType.All:
|
||||||
|
fireDebug(" -> Storing Decrypted Content...");
|
||||||
|
fireDebug(" -> Storing Encrypted Content...");
|
||||||
|
fireDebug(" -> Storing WAD...");
|
||||||
|
storeDecrypted = true;
|
||||||
|
storeEncrypted = true;
|
||||||
|
storeWad = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fireDebug(" Checking for Internet connection...");
|
||||||
|
if (!CheckInet())
|
||||||
|
{ fireDebug(" Connection not found..."); throw new Exception("You're not connected to the internet!"); }
|
||||||
|
|
||||||
|
if (outputDir[outputDir.Length - 1] != Path.DirectorySeparatorChar) outputDir += Path.DirectorySeparatorChar;
|
||||||
|
if (!Directory.Exists(outputDir)) Directory.CreateDirectory(outputDir);
|
||||||
|
|
||||||
|
string tmdFile = "tmd" + (string.IsNullOrEmpty(titleVersion) ? string.Empty : string.Format(".{0}", titleVersion));
|
||||||
|
|
||||||
|
//Download TMD
|
||||||
|
fireDebug(" Downloading TMD...");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
wcNus.DownloadFile(titleUrl + tmdFile, outputDir + tmdFile);
|
||||||
|
}
|
||||||
|
catch (Exception ex) { fireDebug(" Downloading TMD Failed..."); throw new Exception("Downloading TMD Failed:\n" + ex.Message); }
|
||||||
|
|
||||||
|
fireProgress(5);
|
||||||
|
|
||||||
|
//Download cetk
|
||||||
|
fireDebug(" Downloading Ticket...");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
wcNus.DownloadFile(titleUrl + "cetk", outputDir + "cetk");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (!continueWithoutTicket || !storeEncrypted)
|
||||||
|
{
|
||||||
|
fireDebug(" Downloading Ticket Failed...");
|
||||||
|
throw new Exception("Downloading Ticket Failed:\n" + ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
storeDecrypted = false;
|
||||||
|
storeWad = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fireProgress(10);
|
||||||
|
|
||||||
|
//Parse TMD and Ticket
|
||||||
|
fireDebug(" Parsing TMD...");
|
||||||
|
TMD tmd = TMD.Load(outputDir + tmdFile);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(titleVersion)) { fireDebug(" -> Title Version: {0}", tmd.TitleVersion); }
|
||||||
|
fireDebug(" -> {0} Contents", tmd.NumOfContents);
|
||||||
|
|
||||||
|
fireDebug(" Parsing Ticket...");
|
||||||
|
Ticket tik = Ticket.Load(outputDir + "cetk");
|
||||||
|
|
||||||
|
string[] encryptedContents = new string[tmd.NumOfContents];
|
||||||
|
|
||||||
|
//Download Content
|
||||||
|
for (int i = 0; i < tmd.NumOfContents; i++)
|
||||||
|
{
|
||||||
|
fireDebug(" Downloading Content #{0} of {1}... ({2} bytes)", i + 1, tmd.NumOfContents, tmd.Contents[i].Size);
|
||||||
|
fireProgress(((i + 1) * 60 / tmd.NumOfContents) + 10);
|
||||||
|
|
||||||
|
if (useLocalFiles && File.Exists(outputDir + tmd.Contents[i].ContentID.ToString("x8")))
|
||||||
|
{ fireDebug(" Using Local File, Skipping..."); continue; }
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
wcNus.DownloadFile(titleUrl + tmd.Contents[i].ContentID.ToString("x8"),
|
||||||
|
outputDir + tmd.Contents[i].ContentID.ToString("x8"));
|
||||||
|
|
||||||
|
encryptedContents[i] = tmd.Contents[i].ContentID.ToString("x8");
|
||||||
|
}
|
||||||
|
catch (Exception ex) { fireDebug(" Downloading Content #{0} of {1} failed...", i + 1, tmd.NumOfContents); throw new Exception("Downloading Content Failed:\n" + ex.Message); }
|
||||||
|
}
|
||||||
|
|
||||||
|
//Decrypt Content
|
||||||
|
if (storeDecrypted || storeWad)
|
||||||
|
{
|
||||||
|
SHA1 s = SHA1.Create();
|
||||||
|
|
||||||
|
for (int i = 0; i < tmd.NumOfContents; i++)
|
||||||
|
{
|
||||||
|
fireDebug(" Decrypting Content #{0} of {1}...", i + 1, tmd.NumOfContents);
|
||||||
|
fireProgress(((i + 1) * 20 / tmd.NumOfContents) + 75);
|
||||||
|
|
||||||
|
//Decrypt Content
|
||||||
|
byte[] decryptedContent =
|
||||||
|
decryptContent(File.ReadAllBytes(outputDir + tmd.Contents[i].ContentID.ToString("x8")), i, tik, tmd);
|
||||||
|
Array.Resize(ref decryptedContent, (int)tmd.Contents[i].Size);
|
||||||
|
|
||||||
|
//Check SHA1
|
||||||
|
byte[] newSha = s.ComputeHash(decryptedContent);
|
||||||
|
if (!Shared.CompareByteArrays(newSha, tmd.Contents[i].Hash))
|
||||||
|
{ fireDebug(@"/!\ /!\ /!\ Hashes do not match /!\ /!\ /!\"); throw new Exception(string.Format("Content #{0}: Hashes do not match!", i)); }
|
||||||
|
|
||||||
|
//Write Decrypted Content
|
||||||
|
File.WriteAllBytes(outputDir + tmd.Contents[i].ContentID.ToString("x8") + ".app", decryptedContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Pack Wad
|
||||||
|
if (storeWad)
|
||||||
|
{
|
||||||
|
fireDebug(" Building Certificate Chain...");
|
||||||
|
CertificateChain cert = CertificateChain.FromTikTmd(outputDir + "cetk", outputDir + tmdFile);
|
||||||
|
|
||||||
|
byte[][] contents = new byte[tmd.NumOfContents][];
|
||||||
|
|
||||||
|
for (int i = 0; i < tmd.NumOfContents; i++)
|
||||||
|
contents[i] = File.ReadAllBytes(outputDir + tmd.Contents[i].ContentID.ToString("x8") + ".app");
|
||||||
|
|
||||||
|
fireDebug(" Creating WAD...");
|
||||||
|
WAD wad = WAD.Create(cert, tik, tmd, contents);
|
||||||
|
wad.Save(outputDir + tmd.TitleID.ToString("x16") + "v" + tmd.TitleVersion.ToString() + ".wad");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Delete not wanted files
|
||||||
|
if (!storeEncrypted)
|
||||||
|
{
|
||||||
|
fireDebug(" Deleting Encrypted Contents...");
|
||||||
|
for (int i = 0; i < encryptedContents.Length; i++)
|
||||||
|
if (File.Exists(outputDir + encryptedContents[i])) File.Delete(outputDir + encryptedContents[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (storeWad && !storeDecrypted)
|
||||||
|
{
|
||||||
|
fireDebug(" Deleting Decrypted Contents...");
|
||||||
|
for (int i = 0; i < encryptedContents.Length; i++)
|
||||||
|
if (File.Exists(outputDir + encryptedContents[i] + ".app")) File.Delete(outputDir + encryptedContents[i] + ".app");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!storeDecrypted && !storeEncrypted)
|
||||||
|
{
|
||||||
|
fireDebug(" Deleting TMD and Ticket...");
|
||||||
|
File.Delete(outputDir + tmdFile);
|
||||||
|
File.Delete(outputDir + "cetk");
|
||||||
|
}
|
||||||
|
|
||||||
|
fireDebug("Downloading Title {0} v{1} Finished...", titleId, (string.IsNullOrEmpty(titleVersion)) ? "[Latest]" : titleVersion);
|
||||||
|
fireProgress(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*private byte[] decryptContent(byte[] content, int contentIndex, Ticket tik, TMD tmd)
|
||||||
|
{
|
||||||
|
Array.Resize(ref content, Shared.AddPadding(content.Length, 16));
|
||||||
|
byte[] titleKey = tik.TitleKey;
|
||||||
|
byte[] iv = new byte[16];
|
||||||
|
|
||||||
|
byte[] tmp = BitConverter.GetBytes(tmd.Contents[contentIndex].Index);
|
||||||
|
iv[0] = tmp[1];
|
||||||
|
iv[1] = tmp[0];
|
||||||
|
|
||||||
|
RijndaelManaged rm = new RijndaelManaged();
|
||||||
|
rm.Mode = CipherMode.CBC;
|
||||||
|
rm.Padding = PaddingMode.None;
|
||||||
|
rm.KeySize = 128;
|
||||||
|
rm.BlockSize = 128;
|
||||||
|
rm.Key = titleKey;
|
||||||
|
rm.IV = iv;
|
||||||
|
|
||||||
|
ICryptoTransform decryptor = rm.CreateDecryptor();
|
||||||
|
|
||||||
|
MemoryStream ms = new MemoryStream(content);
|
||||||
|
CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);
|
||||||
|
|
||||||
|
byte[] decCont = new byte[content.Length];
|
||||||
|
cs.Read(decCont, 0, decCont.Length);
|
||||||
|
|
||||||
|
cs.Dispose();
|
||||||
|
ms.Dispose();
|
||||||
|
|
||||||
|
return decCont;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
private bool CheckInet()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
System.Net.IPHostEntry ipHost = System.Net.Dns.GetHostEntry("www.google.com");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch { return false; }
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
/// <summary>
|
||||||
|
/// Fires the Progress of various operations
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<ProgressChangedEventArgs> Progress;
|
||||||
|
/// <summary>
|
||||||
|
/// Fires debugging messages. You may write them into a log file or log textbox.
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<MessageEventArgs> Debug;
|
||||||
|
|
||||||
|
private void fireDebug(string debugMessage, params object[] args)
|
||||||
|
{
|
||||||
|
EventHandler<MessageEventArgs> debug = Debug;
|
||||||
|
if (debug != null)
|
||||||
|
debug(new object(), new MessageEventArgs(string.Format(debugMessage, args)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fireProgress(int progressPercentage)
|
||||||
|
{
|
||||||
|
EventHandler<ProgressChangedEventArgs> progress = Progress;
|
||||||
|
if (progress != null)
|
||||||
|
progress(new object(), new ProgressChangedEventArgs(progressPercentage, string.Empty));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace libWiiSharp
|
||||||
|
{
|
||||||
|
public class MessageEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
private string message;
|
||||||
|
public string Message { get { return message; } }
|
||||||
|
|
||||||
|
public MessageEventArgs(string message) { this.message = message; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user