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);
}
}
}
}