public static void Create(IrosArc original, IrosArc updated, System.IO.Stream patchOutput, CompressType compress, Action<double, string> onProgress) { string[] deleted = original.AllFileNames() .Except(updated.AllFileNames(), StringComparer.InvariantCultureIgnoreCase) .ToArray(); List<IrosArc.ArchiveCreateEntry> pentries = new List<IrosArc.ArchiveCreateEntry>(); if (deleted.Any()) { onProgress(0, "Adding deleted entries"); byte[] deldata = System.Text.Encoding.Unicode.GetBytes(String.Join("\n", deleted)); pentries.Add(new IrosArc.ArchiveCreateEntry() { Filename = "%IrosPatch:Deleted", GetData = () => deldata }); } foreach (string newFile in updated.AllFileNames().Except(original.AllFileNames(), StringComparer.InvariantCultureIgnoreCase)) { onProgress(0, "Adding new entries"); string fn = newFile; pentries.Add(new IrosArc.ArchiveCreateEntry() { Filename = fn, GetData = () => updated.GetBytes(fn) }); } foreach (string check in original.AllFileNames().Intersect(updated.AllFileNames())) { onProgress(0, "Checking " + check); if (!Same(original.GetBytes(check), updated.GetBytes(check))) { string fn = check; pentries.Add(new IrosArc.ArchiveCreateEntry() { Filename = fn, GetData = () => updated.GetBytes(fn) }); } } IrosArc.Create(patchOutput, pentries, ArchiveFlags.Patch, compress, onProgress); }
private IEnumerable <string> GetDlls(IEnumerable <string> dlls, bool loadaside) { if (_archive == null) { return(dlls.Select(s => System.IO.Path.Combine(BaseFolder, s))); } else { string appPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); string libpath = System.IO.Path.Combine(appPath, "7thWorkshop", "LoadLibTemp"); System.IO.Directory.CreateDirectory(libpath); List <string> saved = new List <string>(); if (loadaside) { foreach (string path in dlls.Select(s => System.IO.Path.GetDirectoryName(s)).Distinct(StringComparer.InvariantCultureIgnoreCase)) { foreach (string dll in _archive .AllFileNames() .Where(s => System.IO.Path.GetDirectoryName(s).Equals(path, StringComparison.InvariantCultureIgnoreCase)) .Where(s => s.EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase)) ) { string loc = System.IO.Path.Combine(libpath, dll); WriteIfNecessary(loc, _archive.GetBytes(dll)); if (dlls.Contains(dll, StringComparer.InvariantCultureIgnoreCase)) { saved.Add(loc); } } } } else { foreach (string LL in dlls) { string path = System.IO.Path.Combine(libpath, LL); WriteIfNecessary(path, _archive.GetBytes(LL)); saved.Add(path); } } return(saved); } }
public void ApplyPatch(IrosArc patch, Action <double, string> onProgress) { int currentDirSize = _entries.Sum(e => e.GetSize()); byte[] deldata = patch.GetBytes("%IrosPatch:Deleted"); if (deldata != null) { string[] delfile = System.Text.Encoding.Unicode.GetString(deldata).Split(new[] { "\n" }, StringSplitOptions.RemoveEmptyEntries); foreach (string del in delfile) { RuntimeLog.Write("Removing file {0} from archive", del); _entries.RemoveAll(e => e.Filename.Equals(del, StringComparison.InvariantCultureIgnoreCase)); } onProgress(0, "Removed " + delfile.Length + " deleted files"); } int count = 0; var files = patch.AllFileNames().Where(s => !s.StartsWith("%")).ToArray(); foreach (string file in files) { var patchEntry = patch._lookup[file]; byte[] data = new byte[patchEntry.Length]; patch._data.Position = patchEntry.Offset; patch._data.Read(data, 0, data.Length); if (HasFile(file)) //update existing { RuntimeLog.Write("File {0} is already in archive...", file); DirectoryEntry exist = _lookup[file]; if (exist.Length >= data.Length) //put data in same position, woo { RuntimeLog.Write("...updating in place"); _data.Position = exist.Offset; } else //stick at end of file { _data.Position = _data.Length; exist.Offset = _data.Position; RuntimeLog.Write("...size increase: writing to end of file"); } _data.Write(data, 0, data.Length); exist.Length = data.Length; exist.Flags = patchEntry.Flags; } else //new file, just append { RuntimeLog.Write("File {0} is new, appending", file); DirectoryEntry de = new DirectoryEntry() { Filename = file, Flags = patchEntry.Flags, Length = patchEntry.Length, Offset = _data.Length }; _data.Position = de.Offset; _data.Write(data, 0, data.Length); _entries.Add(de); _lookup[file] = de; } count++; onProgress(1.0 * count / files.Length, "Processed " + file); } int newDirSize = _entries.Sum(e => e.GetSize()); if (newDirSize <= currentDirSize) { RuntimeLog.Write("Directory will fit in existing location"); _data.Position = _header.Directory; } else { RuntimeLog.Write("Directory size increase, appending"); if (_data.Length >= int.MaxValue) //write forwarder { _data.Position = _header.Directory; _data.WriteInt(-1); _data.WriteLong(_data.Length); _data.Position = _data.Length; } else //write direct location { _header.Directory = (int)_data.Length; _data.Position = _header.Directory; } } _data.WriteInt(_entries.Count); foreach (var e in _entries) { e.Save(_data); } _header.Version = MAX_VERSION; _data.Position = 0; _header.Save(_data); onProgress(1.0, "Wrote directory"); } //TODO: track blank spaces in file and reuse where possible...