using System; using System.Collections.Generic; using System.IO.Compression; using System.Linq; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Text; namespace PatcherShared { [Serializable] public class PatchFile { #region .ctor public PatchFile() { _actions = new List(); _files = new List(); } #endregion #region Methods public void Apply(string clientPath) { foreach (var action in (from a in this._actions orderby ((byte)a.Type) ascending select a)) { File file = null; if (action.FileId != -1) file = Files.Single(f => f.ID == action.FileId); string path = (new StringBuilder()).Append(clientPath) .Append("\\").Append(action.ClientPath).ToString(); switch (action.Type) { case Action.ActionType.AlterOrCreateFile: Apply_AlterOrCreateFile(file, path); break; case Action.ActionType.DeleteFile: Apply_DeleteFile(action, clientPath); break; case Action.ActionType.CreateFolder: Apply_CreateFolder(path); break; case Action.ActionType.DeleteFolder: Apply_DeleteFolder(path); break; case Action.ActionType.None: default: break; } } } #region Apply-Methods private void Apply_DeleteFolder(string path) { System.IO.Directory.Delete(path); } private void Apply_CreateFolder(string path) { System.IO.Directory.CreateDirectory(path); } private void Apply_DeleteFile(Action action, string clientPath) { System.IO.File.Delete(clientPath + action.ClientPath); } private void Apply_AlterOrCreateFile(File file, string path) { FileStream outStream = null; if (file == null) return; try { if (System.IO.File.Exists(path)) System.IO.File.Delete(path); outStream = new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite); outStream.Write(file.Data, 0, file.Data.Length); outStream.Close(); outStream = null; } catch (Exception) { return; } finally { if(outStream != null) outStream.Dispose(); } } #endregion public void Write(string filePath) { FileStream fs = null; try { foreach (var file in _files) { file.LoadData(); } fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite); GZipStream zipStream = new GZipStream(fs, CompressionMode.Compress); BinaryFormatter bf = new BinaryFormatter(); bf.Serialize(zipStream, this); zipStream.Close(); fs.Close(); fs = null; } catch { return; } finally { if(fs != null) fs.Dispose(); } } public static PatchFile Read(string filePath) { FileStream fs = null; // = new FileStream(filePath, FileMode.Open, FileAccess.Read); try { fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); GZipStream zipStream = new GZipStream(fs, CompressionMode.Decompress); BinaryFormatter bf = new BinaryFormatter(); PatchFile file = (PatchFile)bf.Deserialize(zipStream); zipStream.Close(); fs.Close(); fs = null; return file; } catch { return null; } finally { if(fs != null) fs.Dispose(); } } #endregion #region Properties public bool SelfPatch { get { return selfPatch; } set { selfPatch = value; }} public List Actions { get { return _actions; } set { _actions = value; } } public List Files { get { return _files; } set { _files = value; } } #endregion #region Variables private bool selfPatch; private List _actions; private List _files; #endregion #region Internal class: Action [Serializable] public class Action { public Action() { Type = ActionType.None; ID = -1; FileId = -1; ClientPath = ""; } public Action(PatchFile file) { Type = ActionType.None; ID = file.Actions.Count; file.Actions.Add(this); FileId = -1; ClientPath = ""; } public enum ActionType : byte { None = 0, DeleteFile, AlterOrCreateFile, DeleteFolder, CreateFolder, } public ActionType Type { get { return _type; } set { _type = value; } } public long ID { get { return _id; } set { _id = value; } } public long FileId { get { return _fileId; } set { _fileId = value; } } public string ClientPath { get { return _clientPath; } set { _clientPath = value; } } private long _id; private long _fileId; private string _clientPath; private ActionType _type; } #endregion #region Internal class: File [Serializable] public class File { public File() { ID = -1; Data = null; } public File(PatchFile file) { ID = file.Files.Count; file.Files.Add(this); Data = null; } public long ID { get { return _id; } private set { _id = value; } } public byte[] Data { get { return _data; } set { _data = value; } } [NonSerialized] public string FileName; private long _id; private byte[] _data; public void LoadData() { FileStream fs = null; try { fs = new FileStream(FileName, FileMode.Open, FileAccess.Read); BinaryReader reader = new BinaryReader(fs); _data = reader.ReadBytes((int)fs.Length); } catch (Exception) { return; } finally { if(fs != null) fs.Dispose(); } } } #endregion } }