ps/Modules/Alkami.Ops.Common/FileSystem/ZipHelpers.cs
2023-05-30 22:51:22 -07:00

147 lines
5.8 KiB
C#

using System;
using System.IO;
using System.IO.Compression;
namespace Alkami.Ops.Common.FileSystem
{
public static class ZipHelpers
{
/// <summary>
/// Unzip a path into a specific folder
/// </summary>
/// <param name="zipPath">Path of the file to unzip.</param>
/// <param name="destinationDirectory">If null defaults to a new folder at current location with the Zip file's name.</param>
public static void UnZip(string zipPath, string destinationDirectory = null)
{
if (!string.IsNullOrWhiteSpace(zipPath))
{
if (string.IsNullOrWhiteSpace(destinationDirectory))
{
destinationDirectory = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
destinationDirectory = Path.Combine(destinationDirectory, Path.GetFileNameWithoutExtension(zipPath));
}
Directory.CreateDirectory(destinationDirectory);
try
{
using (var archive = ZipFile.OpenRead(zipPath))
{
archive.ExtractToDirectory(destinationDirectory);
}
}
catch (IOException ex)
{
Console.Error.WriteLine("Exception occurred while extracting files.");
Console.Error.WriteLine(ex);
}
}
}
/// <summary>
/// Unzips a single directory from inside a zip file.
/// </summary>
/// <param name="zipPath">Path of the file to unzip.</param>
/// <param name="internalDirectory">Directory inside of zip file to be extracted. If null or nonexistent nothing will be extracted.</param>
/// <param name="destinationDirectory">If null defaults to a new folder at current location with the Zip subfolder's name.</param>
public static void UnZipSubDirectory(string internalDirectory, string zipPath, string destinationDirectory = null)
{
if (!string.IsNullOrWhiteSpace(zipPath))
{
if (string.IsNullOrWhiteSpace(destinationDirectory))
{
destinationDirectory = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
destinationDirectory = Path.Combine(destinationDirectory, Path.GetFileNameWithoutExtension(zipPath));
}
Directory.CreateDirectory(destinationDirectory);
try
{
using (var archive = ZipFile.OpenRead(zipPath))
{
foreach (var entry in archive.Entries)
{
if (GetRootFolder(entry.FullName).IndexOf(internalDirectory, StringComparison.OrdinalIgnoreCase) >= 0)
{
ExtractEntry(entry, destinationDirectory, entry.FullName);
}
}
}
}
catch (IOException ex)
{
Console.Error.WriteLine("Exception occurred while extracting files.");
Console.Error.WriteLine(ex);
}
catch (Exception ex)
{
Console.Error.WriteLine("Unknown exception occurred while extracting files");
Console.Error.WriteLine(ex);
throw;
}
}
}
/// <summary>
/// Recursively handle subfolders
/// </summary>
/// <param name="entry">Zip entry to extract</param>
/// <param name="destinationDirectory">Desired destination directory. Is added to with each recursive loop as subdirectories are popped off of the entry</param>
/// <param name="entryPath">Current entry path. Shorter every loop as we pop off directories and add them to the destinationDirectory parameter.</param>
private static void ExtractEntry(ZipArchiveEntry entry, string destinationDirectory, string entryPath)
{
var targetIsDirectory = false;
var topLevelDirectory = "";
if (!string.IsNullOrWhiteSpace(entryPath) && !entryPath.Equals('/'))
{
topLevelDirectory = Path.GetDirectoryName(entryPath);
}
else
{
targetIsDirectory = true;
}
if (!string.IsNullOrEmpty(topLevelDirectory))
{
Directory.CreateDirectory(Path.Combine(destinationDirectory, topLevelDirectory));
destinationDirectory = Path.Combine(destinationDirectory, topLevelDirectory);
ExtractEntry(entry, destinationDirectory, Path.GetFileName(entryPath));
}
else
{
if (targetIsDirectory)
{
Directory.CreateDirectory(destinationDirectory);
}
else
{
entry.ExtractToFile(Path.Combine(destinationDirectory, entry.Name));
}
}
}
/// <summary>
/// Cargo culted from https://stackoverflow.com/a/40124633/3691973
/// </summary>
/// <param name="path">Path to examine</param>
/// <returns>Top level folder.</returns>
private static string GetRootFolder(string path)
{
var root = Path.GetPathRoot(path);
while (true)
{
var temp = Path.GetDirectoryName(path);
if (temp != null && temp.Equals(root))
break;
path = temp;
}
return path;
}
}
}