using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace pkNX.Containers { public class FolderContainer : IFileContainer { private readonly List Paths = new List(); private readonly List Data = new List(); private readonly List TrackModify = new List(); public FolderContainer() { } public FolderContainer(IEnumerable files) => AddFiles(files); public FolderContainer(string path) => FilePath = path; public FolderContainer(string path, Func filter) : this(path) => Initialize(filter); public void Initialize(Func filter = null) { if (Paths.Count > 0) return; // already initialized IEnumerable files = Directory.GetFiles(FilePath, "*", SearchOption.AllDirectories); if (filter != null) files = files.Where(filter); files = files.OrderBy(z => Path.GetFileName(z).Length); // alphabetical sorting doesn't play nice with 100 & 1000 AddFiles(files); } public void AddFile(string file, byte[] data = null) { Paths.Add(file); Data.Add(data); TrackModify.Add(false); } public void AddFiles(IEnumerable files) { foreach (var f in files) AddFile(f); } public byte[] GetFileData(string file) { var index = Paths.FindIndex(z => Path.GetFileName(z) == file); if (index < 0) return null; string path = Paths[index]; var data = Data[index] ?? (Data[index] = FileMitm.ReadAllBytes(path)); return (byte[])data.Clone(); } public byte[] GetFileData(int index) { if (index < 0 || (uint)index >= Data.Count) return null; var data = Data[index] ?? (Data[index] = FileMitm.ReadAllBytes(Paths[index])); return (byte[])data.Clone(); } public byte[] this[int index] { get => GetFileData(index); set { if (value != null) { var current = Data[index] ?? (Data[index] = GetFileData(index)); TrackModify[index] = !value.SequenceEqual(current); } Data[index] = value; } } public string GetFileName(int index) => Paths[index]; public string FilePath { get; set; } public bool Modified { get => TrackModify.Count(z => z) != 0; set => CancelEdits(); } public int Count => Paths.Count; public Task GetFiles() => Task.FromResult(Paths.Select(FileMitm.ReadAllBytes).ToArray()); public Task GetFile(int file, int subFile = 0) => Task.FromResult(this[file]); public Task SetFile(int file, byte[] value, int subFile = 0) => Task.FromResult(this[file] = value); public Task SaveAs(string path, ContainerHandler handler, CancellationToken token) => new Task(SaveAll, token); private void SaveAll() { for (int i = 0; i < Paths.Count; i++) { if (!TrackModify[i]) continue; var data = Data[i]; if (data == null) continue; FileMitm.WriteAllBytes(Paths[i], data); } } public void CancelEdits() { for (int i = 0; i < TrackModify.Count; i++) { TrackModify[i] = false; Data[i] = null; } } public void Dump(string path, ContainerHandler handler) { SaveAll(); // there's really nothing to dump, just save any modified } } }