using System;
using System.IO;
using System.IO.Compression;
namespace Alkami.Ops.Common.FileSystem
{
public static class ZipHelpers
{
///
/// Unzip a path into a specific folder
///
/// Path of the file to unzip.
/// If null defaults to a new folder at current location with the Zip file's name.
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);
}
}
}
///
/// Unzips a single directory from inside a zip file.
///
/// Path of the file to unzip.
/// Directory inside of zip file to be extracted. If null or nonexistent nothing will be extracted.
/// If null defaults to a new folder at current location with the Zip subfolder's name.
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;
}
}
}
///
/// Recursively handle subfolders
///
/// Zip entry to extract
/// Desired destination directory. Is added to with each recursive loop as subdirectories are popped off of the entry
/// Current entry path. Shorter every loop as we pop off directories and add them to the destinationDirectory parameter.
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));
}
}
}
///
/// Cargo culted from https://stackoverflow.com/a/40124633/3691973
///
/// Path to examine
/// Top level folder.
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;
}
}
}