using System; using System.IO; using System.IO.Compression; using System.Linq; using System.Threading.Tasks; namespace DiscordBotCore.Others; public static class ArchiveManager { public static void CreateFromFile(string file, string folder) { if (!Directory.Exists(folder)) Directory.CreateDirectory(folder); var archiveName = folder + Path.GetFileNameWithoutExtension(file) + ".zip"; if (File.Exists(archiveName)) File.Delete(archiveName); using(ZipArchive archive = ZipFile.Open(archiveName, ZipArchiveMode.Create)) { archive.CreateEntryFromFile(file, Path.GetFileName(file)); } } /// /// Read a file from a zip archive. The output is a byte array /// /// The file name in the archive /// The archive location on the disk /// An array of bytes that represents the Stream value from the file that was read inside the archive public static async Task ReadAllBytes(string fileName, string archName) { archName = Path.Combine(Application.CurrentApplication.ApplicationEnvironmentVariables["ArchiveFolder"], archName); if (!File.Exists(archName)) throw new Exception("Failed to load file !"); using var zip = ZipFile.OpenRead(archName); var entry = zip.Entries.FirstOrDefault(entry => entry.FullName == fileName || entry.Name == fileName); if (entry is null) throw new Exception("File not found in archive"); await using var memoryStream = new MemoryStream(); var stream = entry.Open(); await stream.CopyToAsync(memoryStream); var data = memoryStream.ToArray(); stream.Close(); memoryStream.Close(); Console.WriteLine("Read file from archive: " + fileName); Console.WriteLine("Size: " + data.Length); return data; } /// /// Read data from a file that is inside an archive (ZIP format) /// /// The file name that is inside the archive or its full path /// The archive location from the PAKs folder /// A string that represents the content of the file or null if the file does not exists or it has no content public static async Task ReadFromPakAsync(string fileName, string archFile) { archFile = Application.CurrentApplication.ApplicationEnvironmentVariables["ArchiveFolder"] + archFile; if (!File.Exists(archFile)) throw new Exception("Failed to load file !"); try { string? textValue = null; using (var fs = new FileStream(archFile, FileMode.Open)) using (var zip = new ZipArchive(fs, ZipArchiveMode.Read)) { foreach (var entry in zip.Entries) if (entry.Name == fileName || entry.FullName == fileName) using (var s = entry.Open()) using (var reader = new StreamReader(s)) { textValue = await reader.ReadToEndAsync(); reader.Close(); s.Close(); fs.Close(); } } return textValue; } catch (Exception ex) { Application.CurrentApplication.Logger.Log(ex.Message, typeof(ArchiveManager), LogType.Error); // Write the error to a file await Task.Delay(100); return await ReadFromPakAsync(fileName, archFile); } } /// /// Extract zip to location /// /// The zip location /// The target location /// The progress that is updated as a file is processed /// The type of progress /// public static async Task ExtractArchive( string zip, string folder, IProgress progress, UnzipProgressType type) { Directory.CreateDirectory(folder); using var archive = ZipFile.OpenRead(zip); var totalZipFiles = archive.Entries.Count(); if (type == UnzipProgressType.PERCENTAGE_FROM_NUMBER_OF_FILES) { var currentZipFile = 0; foreach (var entry in archive.Entries) { if (entry.FullName.EndsWith("/")) // it is a folder Directory.CreateDirectory(Path.Combine(folder, entry.FullName)); else try { entry.ExtractToFile(Path.Combine(folder, entry.FullName), true); } catch (Exception ex) { Application.CurrentApplication.Logger.Log(ex.Message, typeof(ArchiveManager), LogType.Error); } currentZipFile++; await Task.Delay(10); if (progress != null) progress.Report((float)currentZipFile / totalZipFiles * 100); } } else if (type == UnzipProgressType.PERCENTAGE_FROM_TOTAL_SIZE) { ulong zipSize = 0; foreach (var entry in archive.Entries) zipSize += (ulong)entry.CompressedLength; ulong currentSize = 0; foreach (var entry in archive.Entries) { if (entry.FullName.EndsWith("/")) { Directory.CreateDirectory(Path.Combine(folder, entry.FullName)); continue; } try { string path = Path.Combine(folder, entry.FullName); Directory.CreateDirectory(Path.GetDirectoryName(path)); entry.ExtractToFile(path, true); currentSize += (ulong)entry.CompressedLength; } catch (Exception ex) { Application.CurrentApplication.Logger.Log(ex.Message, typeof(ArchiveManager), LogType.Error); } await Task.Delay(10); if (progress != null) progress.Report((float)currentSize / zipSize * 100); } } } }