Multipurpose utility for managing Games for Windows - LIVE installs and content. (Mirrored from https://github.com/InvoxiPlayGames/GfWLUtility)
1using System;
2using System.Collections.Generic;
3using System.ComponentModel;
4using System.Data;
5using System.Drawing;
6using System.IO;
7using System.Linq;
8using System.Net;
9using System.Reflection.Emit;
10using System.Security.Cryptography;
11using System.Text;
12using System.Threading;
13using System.Windows.Forms;
14
15namespace GfWLUtility
16{
17 internal enum DownloadFormResult
18 {
19 DownloadCancelled,
20 DownloadSuccess,
21 DownloadFailure,
22 FileAlreadyExists
23 }
24
25 public partial class DownloadForm : Form
26 {
27 private DownloadFormResult result = DownloadFormResult.DownloadCancelled;
28 private FileInformation fileInformation;
29 private string downloadOutput;
30 private string downloadUrl;
31 private int downloadAttempt;
32
33 public DownloadForm()
34 {
35 InitializeComponent();
36 }
37
38 // https://stackoverflow.com/a/9459441
39 private void StartDownload()
40 {
41 Thread thread = new Thread(() => {
42 WebClient client = new WebClient();
43 client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressChanged);
44 client.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadFileCompleted);
45 client.DownloadFileAsync(new Uri(downloadUrl), downloadOutput);
46 });
47 thread.Start();
48 progressBar1.Style = ProgressBarStyle.Blocks;
49 }
50 void DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
51 {
52 this.BeginInvoke((MethodInvoker)delegate {
53 double bytesIn = double.Parse(e.BytesReceived.ToString());
54 double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
55 double percentage = bytesIn / totalBytes * 100;
56 statusLabel.Text = "Downloaded " + UtilityFuncs.BytesToString(e.BytesReceived) + " of " + UtilityFuncs.BytesToString(e.TotalBytesToReceive);
57 progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
58 });
59 }
60 void DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
61 {
62 this.BeginInvoke((MethodInvoker)delegate {
63 result = e.Error == null ? DownloadFormResult.DownloadSuccess : DownloadFormResult.DownloadFailure;
64 Close();
65 });
66 }
67
68 internal static byte[] GetFileHash(string filename)
69 {
70 FileStream fs = new FileStream(filename, FileMode.Open);
71 byte[] hash = null;
72 using (BufferedStream bs = new BufferedStream(fs))
73 {
74 using (SHA1Managed sha1 = new SHA1Managed())
75 {
76 hash = sha1.ComputeHash(bs);
77 }
78 bs.Close();
79 }
80 fs.Close();
81 return hash;
82 }
83
84 internal static string FileAlreadyExists(FileInformation fi)
85 {
86 // check if the file exists in the downloads folder with its default filename
87 string filename = UtilityFuncs.GetLocalDirectory("Downloads") + fi.Filename;
88 // TODO: check filesize as well as hash
89 if (File.Exists(filename) && GetFileHash(filename).SequenceEqual(fi.Hash))
90 {
91 return filename;
92 }
93 // check alternative filenames
94 if (fi.AltFilenames != null && fi.AltFilenames.Length >= 1)
95 {
96 foreach(string file in fi.AltFilenames)
97 {
98 filename = UtilityFuncs.GetLocalDirectory("Downloads") + file;
99 if (File.Exists(filename) && GetFileHash(filename).SequenceEqual(fi.Hash))
100 {
101 return filename;
102 }
103 }
104 }
105 // null = file doesn't already exist
106 return null;
107 }
108
109 internal DownloadFormResult StartFileDownload(FileInformation fi, IWin32Window owner)
110 {
111 if (!Directory.Exists(UtilityFuncs.GetLocalDirectory("Downloads")))
112 Directory.CreateDirectory(UtilityFuncs.GetLocalDirectory("Downloads"));
113 downloadOutput = UtilityFuncs.GetLocalDirectory("Downloads") + fi.Filename;
114 if (File.Exists(downloadOutput))
115 {
116 // verify the checksum of the existing file
117 if (!GetFileHash(downloadOutput).SequenceEqual(fi.Hash))
118 {
119 // if the hash isn't the same, delete it and redownload
120 File.Delete(downloadOutput);
121 }
122 else
123 {
124 // if it is the same, we don't need to redownload
125 return DownloadFormResult.FileAlreadyExists;
126 }
127 }
128
129 fileInformation = fi;
130
131 // if there is no download URLs, the download should immediately fail
132 if (fi.DownloadURLs == null || fi.DownloadURLs.Length < 1)
133 return DownloadFormResult.DownloadFailure;
134
135 // TODO: If a download fails on one URL, try another
136 downloadUrl = fi.DownloadURLs.FirstOrDefault();
137 currentDownloadURL.Text = downloadUrl;
138 statusLabel.Text = "Preparing download...";
139 progressBar1.Style = ProgressBarStyle.Marquee;
140 StartDownload();
141 ShowDialog(owner);
142 return result;
143 }
144
145 internal string GetOutputFilePath()
146 {
147 return downloadOutput;
148 }
149
150 private void cancelButton_Click(object sender, EventArgs e)
151 {
152 Close();
153 }
154 }
155}