using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using MPQ.Updater; using MPQ.FileSystem; using System.IO; using System.Configuration; using CommonLang.IO; using CommonLang.Concurrent; using System.Net; using System.IO.Compression; using CommonLang.Xml; using System.Xml; using CommonLang; using MPQFileEntry = MPQ.FileSystem.MPQFileSystem.MPQFileEntry; using MPQStream = MPQ.FileSystem.MPQFileSystem.MPQStream; using CommonMPQ.SharpZipLib; namespace MPQFileSystemTest { public partial class FormUpdater : Form, MPQUpdaterListener { private SaveData save = new SaveData(); private MPQUpdater updater; private MPQFileSystem filesystem; public class SaveData { public string DEFAULT_URL; public string DEFAULT_SUFFIX; public string SAVE_PATH; public string ZIP_TYPE; public string MPQ_TYPE; } public FormUpdater() { InitializeComponent(); { string[] urls = ConfigurationManager.AppSettings["REMOTE_URLS"].Split(','); foreach (string e in urls) { string url = e.Trim(); if (!string.IsNullOrEmpty(url)) { comboBox_RemoteDir.Items.Add(url); comboBox_RemoteDir.Text = url; } } } { string[] suffixs = ConfigurationManager.AppSettings["REMOTE_SUFFIXS"].Split(','); foreach (string e in suffixs) { string suffix = e.Trim(); if (!string.IsNullOrEmpty(suffix)) { comboBox_RemoteSuffix.Items.Add(suffix); comboBox_RemoteSuffix.Text = suffix; } } } try { XmlDocument xml = XmlUtil.LoadXML(Application.StartupPath + "/save.xml"); save = (SaveData)XmlUtil.XmlToObject(xml); if (!string.IsNullOrEmpty(save.DEFAULT_URL)) { comboBox_RemoteDir.Text = save.DEFAULT_URL; } if (!string.IsNullOrEmpty(save.DEFAULT_SUFFIX)) { comboBox_RemoteSuffix.Text = save.DEFAULT_SUFFIX; } if (!string.IsNullOrEmpty(save.SAVE_PATH)) { textBox_SaveRoot.Text = save.SAVE_PATH; } if (!string.IsNullOrEmpty(save.ZIP_TYPE)) { comboBox_zipType.Text = save.ZIP_TYPE; } if (!string.IsNullOrEmpty(save.MPQ_TYPE)) { comboBox_mpqType.Text = save.MPQ_TYPE; } } catch (Exception err) { } } private void FormUpdater_FormClosing(object sender, FormClosingEventArgs e) { try { save.DEFAULT_URL = comboBox_RemoteDir.Text; save.DEFAULT_SUFFIX = comboBox_RemoteSuffix.Text; save.SAVE_PATH = textBox_SaveRoot.Text; save.ZIP_TYPE = comboBox_zipType.Text; save.MPQ_TYPE = comboBox_mpqType.Text; XmlDocument xml = XmlUtil.ObjectToXml(save); XmlUtil.SaveXML(Application.StartupPath + "/save.xml", xml); } catch (Exception err) { } if (filesystem != null) { filesystem.Dispose(); } if (updater != null) { updater.Dispose(); } } //-------------------------------------------------------------------------------------------- #region AUTO_UPDATER public void onEvent(MPQUpdater updater, MPQUpdaterEvent e) { if (e.EventType == MPQUpdaterEvent.TYPE_COMPLETE) { RefreshMPQ(); } else if (e.EventType == MPQUpdaterEvent.TYPE_ERROR || e.EventType == MPQUpdaterEvent.TYPE_NOT_ENOUGH_SPACE) { MessageBox.Show(e.ToString()); } } private void timer1_Tick(object sender, EventArgs e) { if (updater != null) { updater.Update(); try { progressBar_Download.Minimum = 0; progressBar_Download.Maximum = (int)updater.TotalDownloadBytes; progressBar_Download.Value = (int)updater.CurrentDownloadBytes; label_Download.Text = updater.CurrentDownloadFile + " (" + updater.CurrentDownloadBytes + "/" + updater.TotalDownloadBytes + ") " + " " + (updater.CurrentDownloadSpeed / 1024) + "KB/S"; progressBar_Decompress.Minimum = 0; progressBar_Decompress.Maximum = (int)updater.TotalUnzipBytes; progressBar_Decompress.Value = (int)updater.CurrentUnzipBytes; label_Unzip.Text = updater.CurrentUnzipFile + " (" + updater.CurrentUnzipBytes + "/" + updater.TotalUnzipBytes + ") " + " " + (updater.CurrentUnzipSpeed / 1024) + "KB/S"; } catch (Exception err) { } textBox_VersionText.Lines = updater.VersionText.Split(new char[] { '\n' }); progressBar_Running.Visible = updater.IsRunning; } else { progressBar_Download.Minimum = 0; progressBar_Download.Maximum = 1; progressBar_Download.Value = 0; label_Download.Text = ""; progressBar_Decompress.Minimum = 0; progressBar_Decompress.Maximum = 1; progressBar_Decompress.Value = 0; label_Unzip.Text = ""; textBox_VersionText.Text = ""; progressBar_Running.Visible = false; } } private void button_Start_Click(object sender, EventArgs e) { if (updater != null) { updater.Dispose(); } try { progressBar_Download.Minimum = 0; progressBar_Download.Maximum = 1; progressBar_Download.Value = 0; label_Download.Text = ""; Uri url = new Uri(comboBox_RemoteDir.Text); updater = new MPQUpdater(new SharpZipLibMPQDirver()); updater.Init( new string[] { comboBox_RemoteDir.Text }, comboBox_RemoteSuffix.Text, new DirectoryInfo(textBox_SaveRoot.Text + url.LocalPath), new DirectoryInfo(textBox_BundleDir.Text), true, this); MPQUpdater.MPQ_EXT = comboBox_mpqType.Text.Trim(); MPQUpdater.ZIP_EXT = comboBox_zipType.Text.Trim(); //updater.RedirectDownloadSingle = RunDownloadSingle; //updater.RedirectUnzipSingle = RunUnzipSingle; updater.Start(); } catch (Exception err) { MessageBox.Show(err.Message); } } private bool RunDownloadSingle(MPQUpdater updater, MPQ.Updater.MPQUpdater.RemoteFileInfo inf, long exist_size, long need_bytes, AtomicLong process) { Uri url = new Uri(updater.UrlRoots[0] + inf.key); var webRequest = (HttpWebRequest)HttpWebRequest.Create(url); webRequest.AddRange((int)exist_size, (int)(exist_size + need_bytes)); webRequest.Method = "GET"; WebResponse webResponse = webRequest.GetResponse(); try { if (webResponse.ContentLength == need_bytes) { byte[] io_buffer = new byte[1024 * 4]; using (FileStream fos = new FileStream(inf.file.FullName, FileMode.Append, FileAccess.Write)) { Stream input = webResponse.GetResponseStream(); try { long total_readed = 0; while (total_readed < need_bytes) { if (updater.IsDisposing) return false; int readed = input.Read(io_buffer, 0, (int)Math.Min(io_buffer.Length, need_bytes - total_readed)); total_readed += readed; process += readed; fos.Write(io_buffer, 0, readed); } fos.Flush(); } finally { fos.Close(); } } } else { throw new Exception("Bad response with ContentLength=" + webResponse.ContentLength); } return true; } finally { webResponse.Close(); } } private bool RunUnzipSingle(MPQUpdater updater, MPQ.Updater.MPQUpdater.RemoteFileInfo zip, MPQ.Updater.MPQUpdater.RemoteFileInfo mpq, AtomicLong process) { byte[] io_buffer = new byte[1024 * 4]; using (FileStream fis = new FileStream(zip.file.FullName, FileMode.Open, FileAccess.Read)) { using (FileStream fos = new FileStream(mpq.file.FullName, FileMode.Create, FileAccess.Write)) { GZipStream gstream = new GZipStream(fis, CompressionMode.Decompress); long total_readed = 0; long total_size = mpq.size; while (total_readed < total_size) { if (updater.IsDisposing) return false; int readed = gstream.Read(io_buffer, 0, (int)Math.Min(io_buffer.Length, total_size - total_readed)); total_readed += readed; process += readed; fos.Write(io_buffer, 0, readed); } fos.Flush(); gstream.Close(); fos.Close(); fis.Close(); } } return true; } private void button_Stop_Click(object sender, EventArgs e) { if (updater != null) { updater.Dispose(); updater = null; } UnloadMPQ(); } private void button_clear_Click(object sender, EventArgs e) { try { if (updater != null) { updater.Dispose(); updater = null; } UnloadMPQ(); DirectoryInfo local = new DirectoryInfo(textBox_SaveRoot.Text); if (local.Exists) { local.Delete(true); local.Create(); } } catch (Exception err) { MessageBox.Show(err.Message); } } #endregion //-------------------------------------------------------------------------------------------- #region MPQ_FILE_SYSTEM public class MPQFileSystemInfo { internal Dictionary files = new Dictionary(); [Description("文件容量")] public long FileSize { get { long ret = 0; foreach (MPQFileInfo f in files.Values) { ret += f.FileSize; } return ret; } set { } } [Description("文件个数")] public int EntryCount { get { int ret = 0; foreach (MPQFileInfo f in files.Values) { ret += f.EntryCount; } return ret; } set { } } [Description("冗余容量")] public long ReplacedSize { get { long ret = 0; foreach (MPQFileInfo f in files.Values) { ret += f.ReplacedSize; } return ret; } set { } } [Description("冗余文件数")] public int ReplacedFileCount { get { int ret = 0; foreach (MPQFileInfo f in files.Values) { ret += f.ReplacedFileCount; } return ret; } set { } } } public class MPQFileInfo { internal List entries = new List(); internal FileInfo fileinfo; internal int replaced_count; internal long replaced_size; public FileInfo File { get { return fileinfo; } set { } } [Description("文件容量")] public long FileSize { get { return fileinfo.Length; } set { } } [Description("文件个数")] public int EntryCount { get { return entries.Count; } set { } } [Description("冗余容量")] public long ReplacedSize { get { return replaced_size; } set { } } [Description("冗余文件数")] public int ReplacedFileCount { get { return replaced_count; } set { } } } private void UnloadMPQ() { if (this.filesystem != null) { TreeNode root = treeView_MPQ.Nodes[0]; root.Tag = null; root.Nodes.Clear(); this.filesystem.Dispose(); this.filesystem = null; } } private void RefreshMPQ() { this.Enabled = false; try { TreeNode root = treeView_MPQ.Nodes[0]; root.Tag = null; root.Nodes.Clear(); if (filesystem != null) { filesystem.Dispose(); } if (updater != null) { this.filesystem = new MPQFileSystem(); //this.filesystem.init(updater); MPQFileSystemInfo fsinfo = new MPQFileSystemInfo(); root.Tag = fsinfo; foreach (MPQ.Updater.MPQUpdater.RemoteFileInfo rmf in updater.GetAllRemoteFiles()) { if (rmf.key.EndsWith(MPQUpdater.MPQ_EXT)) { MPQFileInfo mpq_info = new MPQFileInfo(); mpq_info.fileinfo = rmf.file; MPQStream mpq_stream = filesystem.load(rmf.file.FullName); mpq_stream.loadEntrys(mpq_info.entries); foreach (MPQFileEntry e in mpq_info.entries) { MPQFileEntry exist_fe = filesystem.findEntry(e.Key); bool is_old = !e.Equals(exist_fe); if (is_old) { mpq_info.replaced_size += e.Size; mpq_info.replaced_count += 1; } } fsinfo.files[rmf] = mpq_info; } } } RefreshTreeNode(); } catch (Exception err) { MessageBox.Show(err.Message); } finally { this.Enabled = true; treeView_MPQ.Invalidate(true); } } private void RefreshTreeNode() { TreeNode root = treeView_MPQ.Nodes[0]; root.Nodes.Clear(); if (filesystem != null && root.Tag is MPQFileSystemInfo) { MPQFileSystemInfo fsinfo = (MPQFileSystemInfo)root.Tag; foreach (MPQ.Updater.MPQUpdater.RemoteFileInfo rmf in fsinfo.files.Keys) { MPQFileInfo mpq_info = fsinfo.files[rmf]; TreeNode mpq_file_node = new TreeNode(rmf.key); mpq_file_node.Tag = mpq_info; foreach (MPQFileEntry e in mpq_info.entries) { MPQFileEntry exist_fe = filesystem.findEntry(e.Key); bool is_old = !e.Equals(exist_fe); if (!toolStripButton_ViewReplaced.Checked || is_old) { TreeNode enode = new TreeNode(e.Key); enode.Tag = e; if (is_old) { enode.Text = "(old) " + e.Key; enode.ForeColor = Color.Gray; } enode.ContextMenuStrip = this.menu_EntryNode; mpq_file_node.Nodes.Add(enode); } } mpq_file_node.Text += " (" + (mpq_info.EntryCount - mpq_info.ReplacedFileCount) + "/" + mpq_info.EntryCount + ")"; root.Nodes.Add(mpq_file_node); } } } private void toolStripMenuItem_RefreshMPQ_Click(object sender, EventArgs e) { RefreshMPQ(); } private void 导出文件ToolStripMenuItem_Click(object sender, EventArgs e) { TreeNode sn = treeView_MPQ.SelectedNode; if (sn != null && sn.Tag is MPQFileEntry) { MPQFileEntry entry = (MPQFileEntry)sn.Tag; SaveFileDialog sfd = new SaveFileDialog(); string name = entry.Key.Replace('\\', '/'); int index = entry.Key.LastIndexOf('/'); if (index >= 0) { sfd.FileName = entry.Key.Substring(index+1); } else { sfd.FileName = entry.Key; } if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK) { byte[] data = filesystem.getEntryData(entry); using (Stream stream = sfd.OpenFile()) { stream.Write(data, 0, data.Length); } } } } private void treeView_MPQ_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) { if (e.Node.Tag is MPQFileSystemInfo) { MPQFileSystemInfo mpq = (MPQFileSystemInfo)e.Node.Tag; property_MPQInfo.SelectedObject = mpq; } else if (e.Node.Tag is MPQFileInfo) { MPQFileInfo mpq = (MPQFileInfo)e.Node.Tag; property_MPQInfo.SelectedObject = mpq; } else if (e.Node.Tag is MPQFileEntry) { MPQFileEntry mpq = (MPQFileEntry)e.Node.Tag; property_MPQInfo.SelectedObject = mpq; } } private void treeView_MPQ_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e) { if (e.Node.Tag is MPQFileEntry) { MPQFileSystem.MPQFileEntry mpq = (MPQFileSystem.MPQFileEntry)e.Node.Tag; try { new FormEntry(mpq, filesystem).ShowDialog(); } catch (Exception err) { MessageBox.Show(err.Message); } } } private void toolStripButton_ViewReplaced_Click(object sender, EventArgs e) { this.Enabled = false; try { RefreshTreeNode(); } finally { this.Enabled = true; treeView_MPQ.Refresh(); } } #endregion //-------------------------------------------------------------------------------------------- } }