using Newtonsoft.Json; using System.IO.Compression; namespace Pilz.IO; public class EmbeddedFilesContainer { [JsonProperty("CompressedFiles")] private readonly Dictionary compressedFiles = new Dictionary(); /// /// Returns the names of all embedded files. /// [JsonIgnore] public IEnumerable AllFileNames { get => compressedFiles.Keys; } /// /// Embeds a file to this container. /// /// The name how it should be called in this container. /// The file path to the file that should be embedded. /// Returns a that defines if the file as been embedded successfully. public Task AddFileAsync(string fileName, string filePath) { return Task.Run(() => AddFile(fileName, filePath)); } /// /// Embeds a file to this container. /// /// The name how it should be called in this container. /// The file path to the file that should be embedded. /// Returns a that defines if the file as been embedded successfully. public bool AddFile(string fileName, string filePath) { bool success; FileStream fs = null; MemoryStream compressed = null; #if !DEBUG try { #endif fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); compressed = new MemoryStream(); using (var compressor = new DeflateStream(compressed, CompressionLevel.Optimal, true)) fs.CopyTo(compressor); success = true; #if !DEBUG } catch (Exception) { success = false; } #endif if (success) { var compressedBytes = compressed.ToArray(); if (compressedFiles.ContainsKey(fileName)) compressedFiles[fileName] = compressedBytes; else compressedFiles.Add(fileName, compressedBytes); } compressed?.Close(); fs?.Close(); return success; } /// /// Removes a file from this container. /// /// The name how the file is called. public void RemoveFile(string fileName) { if (compressedFiles.ContainsKey(fileName)) compressedFiles.Remove(fileName); } /// /// Checks if the given file exists in this container. /// /// The name how the file is called. /// Returns if the given file exists in this container. public bool HasFile(string fileName) { return compressedFiles.ContainsKey(fileName); } /// /// Gets a file from this container as stream. /// /// The name how the file is called. /// Returns a stream of the file with the given name. public Task GetStreamAsync(string fileName) { return Task.Run(() => GetStream(fileName)); } /// /// Gets a file from this container as stream. /// /// The name how the file is called. /// Returns a stream of the file with the given name. public Stream GetStream(string fileName) { Stream decompressed = null; if (compressedFiles.ContainsKey(fileName)) { decompressed = new MemoryStream(); DecompressToStream(decompressed, compressedFiles[fileName]); } return decompressed; } /// /// Saves a given file to the users temp directory. /// /// The name how the file is called. /// Returns the file path to the temp file. public Task GetLocalFilePathAsync(string fileName) { return Task.Run(() => GetLocalFilePath(fileName)); } /// /// Saves a given file to the users temp directory. /// /// The name how the file is called. /// Returns the file path to the temp file. public string GetLocalFilePath(string fileName) { string filePath = string.Empty; if (compressedFiles.ContainsKey(fileName)) { filePath = Path.GetTempFileName(); if (Path.HasExtension(fileName)) filePath = Path.ChangeExtension(filePath, Path.GetExtension(fileName)); var decompressed = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite); DecompressToStream(decompressed, compressedFiles[fileName]); decompressed.Flush(); decompressed.Close(); } return filePath; } private void DecompressToStream(Stream decompressed, byte[] compressedData) { var compressed = new MemoryStream(compressedData); var decompressor = new DeflateStream(compressed, CompressionMode.Decompress, true); decompressor.CopyTo(decompressed); decompressor.Close(); compressed.Close(); } }