diff --git a/Patcher/PatchClient/MainWindow.xaml.cs b/Patcher/PatchClient/MainWindow.xaml.cs index 1c1d8af..8c8cebc 100644 --- a/Patcher/PatchClient/MainWindow.xaml.cs +++ b/Patcher/PatchClient/MainWindow.xaml.cs @@ -21,24 +21,15 @@ namespace PatchClient { Task.Run(() => { - FilePatcher bp = new FilePatcher() - { - TargetBase = Environment.CurrentDirectory, - PatchBase = LazyOperations.PatchFolder.FromCwd() - }; + PatchHelper patcher = new PatchHelper(Environment.CurrentDirectory, null, LazyOperations.PatchFolder.FromCwd()); - bp.ProgressChanged += Bp_ProgressChanged; + patcher.ProgressChanged += patcher_ProgressChanged; try { - if (bp.Run()) - { - MessageBox.Show("Patch completed without issues", "Patching Successful"); - } - else - { - MessageBox.Show("Failed to patch client.", "Patching Failed", MessageBoxButton.OK, MessageBoxImage.Error); - } + string message = patcher.ApplyPatches(); + + MessageBox.Show(message, "Patcher"); } catch(Exception ex) { @@ -54,7 +45,7 @@ namespace PatchClient }); } - private void Bp_ProgressChanged(object Sender, int Progress, int Total, int Percent, string Message = "", params LineItem[] AdditionalLineItems) + private void patcher_ProgressChanged(object Sender, int Progress, int Total, int Percent, string Message = "", params LineItem[] AdditionalLineItems) { string additionalInfo = ""; foreach (LineItem item in AdditionalLineItems) diff --git a/Patcher/PatchGenerator/MainWindow.xaml.cs b/Patcher/PatchGenerator/MainWindow.xaml.cs index 47eb5dc..90ffea5 100644 --- a/Patcher/PatchGenerator/MainWindow.xaml.cs +++ b/Patcher/PatchGenerator/MainWindow.xaml.cs @@ -120,13 +120,14 @@ namespace PatchGenerator GenProgressBar.DispatcherSetIndetermination(false); //generate patches - FileCompare bc = new FileCompare(targetFolder, compareFolder, patchBase); + //TODO - fix these weird variable names (why did I do this?) + PatchHelper patcher = new PatchHelper(compareFolder, targetFolder, patchBase); - bc.ProgressChanged += Bc_ProgressChanged; + patcher.ProgressChanged += patcher_ProgressChanged; - if (!bc.CompareAll()) + if (!patcher.GeneratePatches()) { - MessageBox.Show("Failed to generate diffs.", ":(", MessageBoxButton.OK, MessageBoxImage.Error); + MessageBox.Show("One of the provided folder paths doesn't exist.", "Oops :(", MessageBoxButton.OK, MessageBoxImage.Error); } //Copy patch client to output folder @@ -142,7 +143,7 @@ namespace PatchGenerator GenProgressMessageLabel.DispaatcherSetContent("Done"); } - private void Bc_ProgressChanged(object Sender, int Progress, int Total, int Percent, string Message = "", params LineItem[] AdditionalLineItems) + private void patcher_ProgressChanged(object Sender, int Progress, int Total, int Percent, string Message = "", params LineItem[] AdditionalLineItems) { string additionalInfo = ""; foreach (LineItem item in AdditionalLineItems) diff --git a/Patcher/PatcherUtils/FileCompare.cs b/Patcher/PatcherUtils/FileCompare.cs index 63aa4a2..b5341a9 100644 --- a/Patcher/PatcherUtils/FileCompare.cs +++ b/Patcher/PatcherUtils/FileCompare.cs @@ -12,174 +12,174 @@ using System.Linq; namespace PatcherUtils { - public class FileCompare - { - public string PatchBase; - public string TargetBase; - public string CompareBase; - private int fileCount; - private int fileIt; + //public class FileCompare + //{ + // public string PatchBase; + // public string TargetBase; + // public string CompareBase; + // private int fileCount; + // private int fileIt; - private int diffCount = 0; - private int newCount = 0; - private int delCount = 0; - private int matchCount = 0; + // private int diffCount = 0; + // private int newCount = 0; + // private int delCount = 0; + // private int matchCount = 0; - private List TargetPaths; - private List ComparePaths; - private List AdditionalInfo = new List(); + // private List TargetPaths; + // private List ComparePaths; + // private List AdditionalInfo = new List(); - /// - /// Provides patch generation progress changes - /// - public event ProgressChangedHandler ProgressChanged; - protected virtual void RaiseProgressChanged(int progress, int total, string Message = "", params LineItem[] AdditionalLineItems) - { - int percent = (int)Math.Floor((double)progress / total * 100); + // /// + // /// Provides patch generation progress changes + // /// + // public event ProgressChangedHandler ProgressChanged; + // protected virtual void RaiseProgressChanged(int progress, int total, string Message = "", params LineItem[] AdditionalLineItems) + // { + // int percent = (int)Math.Floor((double)progress / total * 100); - ProgressChanged?.Invoke(this, progress, total, percent, Message, AdditionalLineItems); - } + // ProgressChanged?.Invoke(this, progress, total, percent, Message, AdditionalLineItems); + // } - /// - /// Compare a target file to an assumed compareable file. - /// - /// The known target path - /// The assumed comparable file path - /// True if a comparison was made | False if a comparison could not be made - private bool Compare(string targetFile, string assumedCompareFile) - { - string patchFilePath = targetFile.Replace(TargetBase, PatchBase); - //we know our target file exists - byte[] targetData = VFS.ReadFile(targetFile); + // /// + // /// Compare a target file to an assumed compareable file. + // /// + // /// The known target path + // /// The assumed comparable file path + // /// True if a comparison was made | False if a comparison could not be made + // private bool Compare(string targetFile, string assumedCompareFile) + // { + // string patchFilePath = targetFile.Replace(TargetBase, PatchBase); + // //we know our target file exists + // byte[] targetData = VFS.ReadFile(targetFile); - if(!File.Exists(assumedCompareFile)) - { - //save the data we won't have in our target as new - VFS.WriteFile($"{patchFilePath}.new", Zlib.Compress(targetData, ZlibCompression.Maximum)); - newCount++; - return true; - } + // if(!File.Exists(assumedCompareFile)) + // { + // //save the data we won't have in our target as new + // VFS.WriteFile($"{patchFilePath}.new", Zlib.Compress(targetData, ZlibCompression.Maximum)); + // newCount++; + // return true; + // } - //now our compare file is known to exist - byte[] compareData = VFS.ReadFile(assumedCompareFile); + // //now our compare file is known to exist + // byte[] compareData = VFS.ReadFile(assumedCompareFile); - // get diffs - DiffResult result = PatchUtil.Diff(compareData, targetData); + // // get diffs + // DiffResult result = PatchUtil.Diff(compareData, targetData); - switch (result.Result) - { - case DiffResultType.Success: - VFS.WriteFile($"{patchFilePath}.bpf", result.PatchInfo.ToBytes()); - diffCount++; - return true; + // switch (result.Result) + // { + // case DiffResultType.Success: + // VFS.WriteFile($"{patchFilePath}.bpf", result.PatchInfo.ToBytes()); + // diffCount++; + // return true; - case DiffResultType.FilesMatch: - matchCount++; - return true; + // case DiffResultType.FilesMatch: + // matchCount++; + // return true; - default: - return false; - } - } + // default: + // return false; + // } + // } - /// - /// Compares the base folders and generates patch files. - /// - /// True if patches were generated successfully | False if patch generation failed - public bool CompareAll() - { - DirectoryInfo targetDirInfo = new DirectoryInfo(TargetBase); - DirectoryInfo compareDirInfo = new DirectoryInfo(CompareBase); + // /// + // /// Compares the base folders and generates patch files. + // /// + // /// True if patches were generated successfully | False if patch generation failed + // public bool CompareAll() + // { + // DirectoryInfo targetDirInfo = new DirectoryInfo(TargetBase); + // DirectoryInfo compareDirInfo = new DirectoryInfo(CompareBase); - AdditionalInfo.Add(new LineItem("Diff Patch", "0")); - AdditionalInfo.Add(new LineItem("New Patch", "0")); - AdditionalInfo.Add(new LineItem("Del Patch", "0")); - AdditionalInfo.Add(new LineItem("Files Match", "0")); + // AdditionalInfo.Add(new LineItem("Diff Patch", "0")); + // AdditionalInfo.Add(new LineItem("New Patch", "0")); + // AdditionalInfo.Add(new LineItem("Del Patch", "0")); + // AdditionalInfo.Add(new LineItem("Files Match", "0")); - if (!targetDirInfo.Exists || !compareDirInfo.Exists) - { - Console.WriteLine("Target or Compare folder does not exist"); - return false; - } + // if (!targetDirInfo.Exists || !compareDirInfo.Exists) + // { + // Console.WriteLine("Target or Compare folder does not exist"); + // return false; + // } - //Get all the files recursively - TargetPaths = new List(targetDirInfo.GetFiles("*.*", SearchOption.AllDirectories)); - ComparePaths = new List(compareDirInfo.GetFiles("*.*", SearchOption.AllDirectories)); + // //Get all the files recursively + // TargetPaths = new List(targetDirInfo.GetFiles("*.*", SearchOption.AllDirectories)); + // ComparePaths = new List(compareDirInfo.GetFiles("*.*", SearchOption.AllDirectories)); - RaiseProgressChanged(0, fileCount, "Generating diffs..."); + // RaiseProgressChanged(0, fileCount, "Generating diffs..."); - /* Comparing Target files -> Compare files - * - Exists = Diff (.bfd file) - * - Doesn't Exist = New (.new file) - * - * Once everything has been compared from one side, any remaining paths in our ComparePaths - * are things that don't exist in our target and can be deleted (.del file) - */ + // /* Comparing Target files -> Compare files + // * - Exists = Diff (.bfd file) + // * - Doesn't Exist = New (.new file) + // * + // * Once everything has been compared from one side, any remaining paths in our ComparePaths + // * are things that don't exist in our target and can be deleted (.del file) + // */ - for (int x = 0; x < TargetPaths.Count; x++) - { - FileInfo file = TargetPaths[x]; + // for (int x = 0; x < TargetPaths.Count; x++) + // { + // FileInfo file = TargetPaths[x]; - string assumedComparePath = file.DirectoryName.Replace(TargetBase, CompareBase); + // string assumedComparePath = file.DirectoryName.Replace(TargetBase, CompareBase); - if (!Compare(file.FullName, VFS.Combine(assumedComparePath, file.Name))) - { - return false; - } + // if (!Compare(file.FullName, VFS.Combine(assumedComparePath, file.Name))) + // { + // return false; + // } - //remove any existing files from our ComparePaths - FileInfo assumedFile = new FileInfo(VFS.Combine(assumedComparePath, file.Name)); - if (assumedFile.Exists && ComparePaths.Exists(x => x.FullName == assumedFile.FullName)) - { - ComparePaths.Remove(ComparePaths.Where(x => x.FullName == assumedFile.FullName).FirstOrDefault()); - } + // //remove any existing files from our ComparePaths + // FileInfo assumedFile = new FileInfo(VFS.Combine(assumedComparePath, file.Name)); + // if (assumedFile.Exists && ComparePaths.Exists(x => x.FullName == assumedFile.FullName)) + // { + // ComparePaths.Remove(ComparePaths.Where(x => x.FullName == assumedFile.FullName).FirstOrDefault()); + // } - AdditionalInfo[0].ItemValue = diffCount.ToString(); - AdditionalInfo[1].ItemValue = newCount.ToString(); - AdditionalInfo[3].ItemValue = matchCount.ToString(); + // AdditionalInfo[0].ItemValue = diffCount.ToString(); + // AdditionalInfo[1].ItemValue = newCount.ToString(); + // AdditionalInfo[3].ItemValue = matchCount.ToString(); - fileIt++; - RaiseProgressChanged(fileIt, fileCount, file.Name, AdditionalInfo.ToArray()); - } + // fileIt++; + // RaiseProgressChanged(fileIt, fileCount, file.Name, AdditionalInfo.ToArray()); + // } - if (ComparePaths.Count == 0) - { - //if there are no files to delete, just return true - return true; - } + // if (ComparePaths.Count == 0) + // { + // //if there are no files to delete, just return true + // return true; + // } - //progress reset for files that need to be deleted - RaiseProgressChanged(0, ComparePaths.Count, "Processing .del files..."); - fileIt = 0; - fileCount = ComparePaths.Count; + // //progress reset for files that need to be deleted + // RaiseProgressChanged(0, ComparePaths.Count, "Processing .del files..."); + // fileIt = 0; + // fileCount = ComparePaths.Count; - //the paths remaining in ComparePaths don't exist in our target and need to be removed during patching. - foreach (FileInfo file in ComparePaths) - { - //add del files replace root dir with patch base - string patchFilePath = file.FullName.Replace(CompareBase, PatchBase); - VFS.WriteFile($"{patchFilePath}.del", new byte[0]); + // //the paths remaining in ComparePaths don't exist in our target and need to be removed during patching. + // foreach (FileInfo file in ComparePaths) + // { + // //add del files replace root dir with patch base + // string patchFilePath = file.FullName.Replace(CompareBase, PatchBase); + // VFS.WriteFile($"{patchFilePath}.del", new byte[0]); - delCount++; - AdditionalInfo[2].ItemValue = delCount.ToString(); + // delCount++; + // AdditionalInfo[2].ItemValue = delCount.ToString(); - fileIt++; - RaiseProgressChanged(fileIt, fileCount, "", AdditionalInfo.ToArray()); - } + // fileIt++; + // RaiseProgressChanged(fileIt, fileCount, "", AdditionalInfo.ToArray()); + // } - return true; - } + // return true; + // } - public FileCompare(string TargetBase, string CompareBase, string PatchBase) - { - this.TargetBase = TargetBase; - this.CompareBase = CompareBase; - this.PatchBase = PatchBase; + // public FileCompare(string TargetBase, string CompareBase, string PatchBase) + // { + // this.TargetBase = TargetBase; + // this.CompareBase = CompareBase; + // this.PatchBase = PatchBase; - fileCount = VFS.GetFilesCount(TargetBase); - fileIt = 0; - } - } + // fileCount = VFS.GetFilesCount(TargetBase); + // fileIt = 0; + // } + //} } diff --git a/Patcher/PatcherUtils/FilePatcher.cs b/Patcher/PatcherUtils/FilePatcher.cs index f3ec4db..d75aed8 100644 --- a/Patcher/PatcherUtils/FilePatcher.cs +++ b/Patcher/PatcherUtils/FilePatcher.cs @@ -7,141 +7,141 @@ using System.Linq; namespace PatcherUtils { - public class FilePatcher - { - public string TargetBase; - public string PatchBase; - private int fileCount; - private int fileIt; + //public class FilePatcher + //{ + // public string TargetBase; + // public string PatchBase; + // private int fileCount; + // private int fileIt; - private int diffCount; - private int newCount; - private int delCount; + // private int diffCount; + // private int newCount; + // private int delCount; - private List AdditionalInfo; + // private List AdditionalInfo; - public event ProgressChangedHandler ProgressChanged; + // public event ProgressChangedHandler ProgressChanged; - protected virtual void RaiseProgressChanged(int progress, int total, string Message = "", params LineItem[] AdditionalLineItems) - { - int percent = (int)Math.Floor((double)progress / total * 100); + // protected virtual void RaiseProgressChanged(int progress, int total, string Message = "", params LineItem[] AdditionalLineItems) + // { + // int percent = (int)Math.Floor((double)progress / total * 100); - ProgressChanged?.Invoke(this, progress, total, percent, Message, AdditionalLineItems); - } + // ProgressChanged?.Invoke(this, progress, total, percent, Message, AdditionalLineItems); + // } - public bool Patch(string targetfile, string patchfile) - { - byte[] target = VFS.ReadFile(targetfile); - byte[] patch = VFS.ReadFile(patchfile); + // public bool Patch(string targetfile, string patchfile) + // { + // byte[] target = VFS.ReadFile(targetfile); + // byte[] patch = VFS.ReadFile(patchfile); - PatchResult result = PatchUtil.Patch(target, PatchInfo.FromBytes(patch)); + // PatchResult result = PatchUtil.Patch(target, PatchInfo.FromBytes(patch)); - switch (result.Result) - { - case PatchResultType.Success: - VFS.WriteFile(targetfile, result.PatchedData); - return true; + // switch (result.Result) + // { + // case PatchResultType.Success: + // VFS.WriteFile(targetfile, result.PatchedData); + // return true; - case PatchResultType.AlreadyPatched: - case PatchResultType.InputChecksumMismatch: - case PatchResultType.InputLengthMismatch: - return true; + // case PatchResultType.AlreadyPatched: + // case PatchResultType.InputChecksumMismatch: + // case PatchResultType.InputLengthMismatch: + // return true; - case PatchResultType.OutputChecksumMismatch: - default: - return false; - } - } + // case PatchResultType.OutputChecksumMismatch: + // default: + // return false; + // } + // } - private bool PatchAll(string targetpath, string patchpath) - { - DirectoryInfo di = new DirectoryInfo(patchpath); + // private bool PatchAll(string targetpath, string patchpath) + // { + // DirectoryInfo di = new DirectoryInfo(patchpath); - foreach (FileInfo file in di.GetFiles()) - { - FileInfo target = null; + // foreach (FileInfo file in di.GetFiles()) + // { + // FileInfo target = null; - switch (file.Extension) - { - // patch - case ".bpf": - { - target = new FileInfo(VFS.Combine(targetpath, file.Name.Replace(".bpf", ""))); + // switch (file.Extension) + // { + // // patch + // case ".bpf": + // { + // target = new FileInfo(VFS.Combine(targetpath, file.Name.Replace(".bpf", ""))); - if (!Patch(target.FullName, file.FullName)) - { - // patch failed - return false; - } + // if (!Patch(target.FullName, file.FullName)) + // { + // // patch failed + // return false; + // } - diffCount--; - } - break; + // diffCount--; + // } + // break; - // add new files - case ".new": - { - target = new FileInfo(VFS.Combine(targetpath, file.Name.Replace(".new", ""))); - VFS.WriteFile(target.FullName, Zlib.Decompress(VFS.ReadFile(file.FullName))); - newCount--; - } - break; + // // add new files + // case ".new": + // { + // target = new FileInfo(VFS.Combine(targetpath, file.Name.Replace(".new", ""))); + // VFS.WriteFile(target.FullName, Zlib.Decompress(VFS.ReadFile(file.FullName))); + // newCount--; + // } + // break; - // delete old files - case ".del": - { - target = new FileInfo(VFS.Combine(targetpath, file.Name.Replace(".del", ""))); - target.IsReadOnly = false; - target.Delete(); - delCount--; - } - break; - } + // // delete old files + // case ".del": + // { + // target = new FileInfo(VFS.Combine(targetpath, file.Name.Replace(".del", ""))); + // target.IsReadOnly = false; + // target.Delete(); + // delCount--; + // } + // break; + // } - AdditionalInfo[0].ItemValue = diffCount.ToString(); - AdditionalInfo[1].ItemValue = newCount.ToString(); - AdditionalInfo[2].ItemValue = delCount.ToString(); + // AdditionalInfo[0].ItemValue = diffCount.ToString(); + // AdditionalInfo[1].ItemValue = newCount.ToString(); + // AdditionalInfo[2].ItemValue = delCount.ToString(); - ++fileIt; - RaiseProgressChanged(fileIt, fileCount, target.Name, AdditionalInfo.ToArray()); - } + // ++fileIt; + // RaiseProgressChanged(fileIt, fileCount, target.Name, AdditionalInfo.ToArray()); + // } - foreach (DirectoryInfo directory in di.GetDirectories()) - { - PatchAll(VFS.Combine(targetpath, directory.Name), directory.FullName); - } + // foreach (DirectoryInfo directory in di.GetDirectories()) + // { + // PatchAll(VFS.Combine(targetpath, directory.Name), directory.FullName); + // } - di.Refresh(); + // di.Refresh(); - if (di.GetFiles().Length == 0 && di.GetDirectories().Length == 0) - { - // remove empty folders - di.Delete(); - } + // if (di.GetFiles().Length == 0 && di.GetDirectories().Length == 0) + // { + // // remove empty folders + // di.Delete(); + // } - return true; - } + // return true; + // } - public bool Run() - { - fileCount = VFS.GetFilesCount(PatchBase); + // public bool Run() + // { + // fileCount = VFS.GetFilesCount(PatchBase); - FileInfo[] files = new DirectoryInfo(PatchBase).GetFiles("*.*", SearchOption.AllDirectories); + // FileInfo[] files = new DirectoryInfo(PatchBase).GetFiles("*.*", SearchOption.AllDirectories); - diffCount = files.Where(x => x.Extension == ".bpf").Count(); - newCount = files.Where(x => x.Extension == ".new").Count(); - delCount = files.Where(x => x.Extension == ".del").Count(); + // diffCount = files.Where(x => x.Extension == ".bpf").Count(); + // newCount = files.Where(x => x.Extension == ".new").Count(); + // delCount = files.Where(x => x.Extension == ".del").Count(); - AdditionalInfo = new List() - { - new LineItem("Patches Remaining", diffCount.ToString()), - new LineItem("New Files to Inflate", newCount.ToString()), - new LineItem("Files to Delete", delCount.ToString()) - }; + // AdditionalInfo = new List() + // { + // new LineItem("Patches Remaining", diffCount.ToString()), + // new LineItem("New Files to Inflate", newCount.ToString()), + // new LineItem("Files to Delete", delCount.ToString()) + // }; - fileIt = 0; - return PatchAll(TargetBase, PatchBase); - } - } + // fileIt = 0; + // return PatchAll(TargetBase, PatchBase); + // } + //} } diff --git a/Patcher/PatcherUtils/LazyOperations.cs b/Patcher/PatcherUtils/LazyOperations.cs index d38d6aa..06d4098 100644 --- a/Patcher/PatcherUtils/LazyOperations.cs +++ b/Patcher/PatcherUtils/LazyOperations.cs @@ -12,12 +12,13 @@ namespace PatcherUtils /// public static string TempDir = "PATCHER_TEMP".FromCwd(); - private static string SevenZExe = "7za.exe"; /// /// The folder that the patches will be stored in /// - public static string PatchFolder = "Aki_Data\\Patcher"; + public static string PatchFolder = "Aki_Patches"; + + private static string SevenZExe = "7za.exe"; /// /// The path to the 7za.exe file in the @@ -30,6 +31,13 @@ namespace PatcherUtils /// public static string PatcherClientPath = $"{TempDir}\\{PatcherClient}"; + private static string XDelta3EXE = "xdelta3.exe"; + + /// + /// The path to the xdelta3.exe flie in the + /// + public static string XDelta3Path = $"{TempDir}\\{XDelta3EXE}"; + /// /// Streams embedded resources out of the assembly /// @@ -73,6 +81,11 @@ namespace PatcherUtils StreamResourceOut(resource, PatcherClientPath); break; } + case string a when a.EndsWith(XDelta3EXE): + { + StreamResourceOut(resource, XDelta3Path); + break; + } } } } diff --git a/Patcher/PatcherUtils/PatchHelper.cs b/Patcher/PatcherUtils/PatchHelper.cs new file mode 100644 index 0000000..16d55a3 --- /dev/null +++ b/Patcher/PatcherUtils/PatchHelper.cs @@ -0,0 +1,267 @@ +using Aki.Common.Utils; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; + +namespace PatcherUtils +{ + public class PatchHelper + { + private string SourceFolder = ""; + private string TargetFolder = ""; + private string DeltaFolder = ""; + + private int fileCountTotal; + private int filesProcessed; + + private int deltaCount; + private int newCount; + private int delCount; + + private List AdditionalInfo; + + public event ProgressChangedHandler ProgressChanged; + + protected virtual void RaiseProgressChanged(int progress, int total, string Message = "", params LineItem[] AdditionalLineItems) + { + int percent = (int)Math.Floor((double)progress / total * 100); + + ProgressChanged?.Invoke(this, progress, total, percent, Message, AdditionalLineItems); + } + + public PatchHelper(string SourceFolder, string TargetFolder, string DeltaFolder) + { + this.SourceFolder = SourceFolder; + this.TargetFolder = TargetFolder; + this.DeltaFolder = DeltaFolder; + } + + private string GetDeltaPath(string sourceFile, string sourceFolder, string extension) + { + return Path.Join(DeltaFolder, $"{sourceFile.Replace(sourceFolder, "")}.{extension}"); + } + + private void ApplyDelta(string SourceFilePath, string DeltaFilePath) + { + string decodedPath = SourceFilePath + ".decoded"; + + Process.Start(new ProcessStartInfo + { + FileName = LazyOperations.XDelta3Path, + Arguments = $"-d -f -s \"{SourceFilePath}\" \"{DeltaFilePath}\" \"{decodedPath}\"" + }) + .WaitForExit(); + + if(File.Exists(decodedPath)) + { + File.Delete(SourceFilePath); + File.Move(decodedPath, SourceFilePath); + } + } + + private void CreateDelta(string SourceFilePath, string TargetFilePath) + { + FileInfo sourceFileInfo = new FileInfo(SourceFilePath); + + string deltaPath = GetDeltaPath(SourceFilePath, SourceFolder, "delta"); + + Directory.CreateDirectory(deltaPath.Replace(sourceFileInfo.Name, "")); + + //TODO - don't hardcode FileName + + Process.Start(new ProcessStartInfo + { + FileName = LazyOperations.XDelta3Path, + Arguments = $"-0 -e -f -s \"{SourceFilePath}\" \"{TargetFilePath}\" \"{deltaPath}\"" + }) + .WaitForExit(); + } + + private void CreateDelFile(string SourceFile) + { + FileInfo sourceFileInfo = new FileInfo(SourceFile); + + string deltaPath = GetDeltaPath(SourceFile, SourceFolder, "del"); + + Directory.CreateDirectory(deltaPath.Replace(sourceFileInfo.Name, "")); + + File.Create(deltaPath); + } + + private void CreateNewFile(string TargetFile) + { + FileInfo targetSourceInfo = new FileInfo(TargetFile); + + string deltaPath = GetDeltaPath(TargetFile, TargetFolder, "new"); + + Directory.CreateDirectory(deltaPath.Replace(targetSourceInfo.Name, "")); + + targetSourceInfo.CopyTo(deltaPath, true); + } + + public bool GeneratePatches() + { + //get all directory information needed + DirectoryInfo sourceDir = new DirectoryInfo(SourceFolder); + DirectoryInfo targetDir = new DirectoryInfo(TargetFolder); + DirectoryInfo deltaDir = Directory.CreateDirectory(DeltaFolder); + + //make sure all directories exist + if (!sourceDir.Exists || !targetDir.Exists || !deltaDir.Exists) + { + //One of the directories doesn't exist + return false; + } + + List SourceFiles = sourceDir.GetFiles("*", SearchOption.AllDirectories).ToList(); + + fileCountTotal = SourceFiles.Count; + + AdditionalInfo.Clear(); + AdditionalInfo.Add(new LineItem("Delta Patch", "0")); + AdditionalInfo.Add(new LineItem("New Patch", "0")); + AdditionalInfo.Add(new LineItem("Del Patch", "0")); + + filesProcessed = 0; + + RaiseProgressChanged(0, fileCountTotal, "Generating deltas..."); + + foreach (FileInfo targetFile in targetDir.GetFiles("*", SearchOption.AllDirectories)) + { + //find a matching source file based on the relative path of the file + FileInfo sourceFile = SourceFiles.Find(f => f.FullName.Replace(sourceDir.FullName, "") == targetFile.FullName.Replace(targetDir.FullName, "")); + + //if the target file doesn't exist in the source files, the target file needs to be added. + if (sourceFile == null) + { + CreateNewFile(targetFile.FullName); + + newCount++; + + RaiseProgressChanged(filesProcessed, fileCountTotal, targetFile.Name, AdditionalInfo.ToArray()); + + continue; + } + + //if a matching source file was found, get the delta for it. + CreateDelta(sourceFile.FullName, targetFile.FullName); + + SourceFiles.Remove(sourceFile); + + deltaCount++; + + RaiseProgressChanged(filesProcessed, fileCountTotal, targetFile.Name, AdditionalInfo.ToArray()); + } + + //Any remaining source files do not exist in the target folder and can be removed. + //reset progress info + RaiseProgressChanged(0, SourceFiles.Count, "Processing .del files..."); + filesProcessed = 0; + fileCountTotal = SourceFiles.Count; + + foreach (FileInfo delFile in SourceFiles) + { + CreateDelFile(delFile.FullName); + + delCount++; + + AdditionalInfo[2].ItemValue = delCount.ToString(); + + filesProcessed++; + RaiseProgressChanged(filesProcessed, fileCountTotal, "", AdditionalInfo.ToArray()); + } + + return true; + } + + public string ApplyPatches() + { + //get needed directory information + DirectoryInfo sourceDir = new DirectoryInfo(SourceFolder); + DirectoryInfo deltaDir = new DirectoryInfo(DeltaFolder); + + //check directories exist + if (!sourceDir.Exists || !deltaDir.Exists) + { + return "One of the supplied directories doesn't exist"; + } + + List SourceFiles = sourceDir.GetFiles("*", SearchOption.AllDirectories).ToList(); + + List deltaFiles = deltaDir.GetFiles("*", SearchOption.AllDirectories).ToList(); + + deltaCount = deltaFiles.Where(x => x.Extension == ".delta").Count(); + newCount = deltaFiles.Where(x => x.Extension == ".new").Count(); + delCount = deltaFiles.Where(x => x.Extension == ".del").Count(); + + + AdditionalInfo = new List() + { + new LineItem("Patches Remaining", deltaCount.ToString()), + new LineItem("New Files to Add", newCount.ToString()), + new LineItem("Files to Delete", delCount.ToString()) + }; + + filesProcessed = 0; + + fileCountTotal = deltaFiles.Count; + + foreach (FileInfo deltaFile in deltaDir.GetFiles("*", SearchOption.AllDirectories)) + { + switch(deltaFile.Extension) + { + case ".delta": + { + //apply delta + FileInfo sourceFile = SourceFiles.Find(f => f.FullName.Replace(sourceDir.FullName, "") == deltaFile.FullName.Replace(deltaDir.FullName, "").Replace(".delta", "")); + + if(sourceFile == null) + { + return $"Failed to find matching source file for '{deltaFile.FullName}'"; + } + + ApplyDelta(sourceFile.FullName, deltaFile.FullName); + + deltaCount--; + + break; + } + case ".new": + { + //copy new file + string destination = Path.Join(sourceDir.FullName, deltaFile.FullName.Replace(deltaDir.FullName, "").Replace(".new", "")); + + File.Copy(deltaFile.FullName, destination); + + newCount--; + + break; + } + case ".del": + { + //remove unneeded file + string delFilePath = Path.Join(sourceDir.FullName, deltaFile.FullName.Replace(deltaDir.FullName, "").Replace(".del", "")); + + File.Delete(delFilePath); + + delCount--; + + break; + } + } + + AdditionalInfo[0].ItemValue = deltaCount.ToString(); + AdditionalInfo[1].ItemValue = newCount.ToString(); + AdditionalInfo[2].ItemValue = delCount.ToString(); + + ++filesProcessed; + RaiseProgressChanged(filesProcessed, fileCountTotal, deltaFile.Name, AdditionalInfo.ToArray()); + } + + return "Patching Complete"; + } + } +} diff --git a/Patcher/PatcherUtils/PatcherUtils.csproj b/Patcher/PatcherUtils/PatcherUtils.csproj index 2582ff1..b8786fe 100644 --- a/Patcher/PatcherUtils/PatcherUtils.csproj +++ b/Patcher/PatcherUtils/PatcherUtils.csproj @@ -7,11 +7,13 @@ + + diff --git a/Patcher/PatcherUtils/Resources/xdelta3.exe b/Patcher/PatcherUtils/Resources/xdelta3.exe new file mode 100644 index 0000000..1cce3c5 Binary files /dev/null and b/Patcher/PatcherUtils/Resources/xdelta3.exe differ