-
-
Save snovvcrash/c39a46f67fc987c94c227817b6155ab9 to your computer and use it in GitHub Desktop.
Self-contained 7-Zip wrapper using SevenZipSharp & Costura.Fody
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
using System.Linq; | |
using System.Collections.Generic; | |
using SevenZip; | |
using CommandLine; | |
using CommandLine.Text; | |
namespace Sharp7Zip | |
{ | |
public enum OutputFormat | |
{ | |
Auto, | |
SevenZip, | |
Zip, | |
GZip, | |
BZip2, | |
Tar, | |
XZ | |
} | |
public class Compress7Zip | |
{ | |
public string ArchiveFileName { get; set; } | |
public string Path { get; set; } | |
public string Filter { get; set; } | |
public string OutputPath { get; set; } | |
public OutputFormat Format { get; set; } = OutputFormat.Auto; | |
public CompressionLevel CompressionLevel { get; set; } = CompressionLevel.Normal; | |
public CompressionMethod CompressionMethod { get; set; } = CompressionMethod.Default; | |
public string Password { get; set; } | |
public Action<SevenZipCompressor> CustomInitialization { get; set; } | |
public string TempFolder { get; set; } | |
public bool EncryptFilenames { get; set; } | |
public bool FlattenDirectoryStructure { get; set; } | |
public int VolumeSize { get; set; } | |
public bool SkipEmptyDirectories { get; set; } | |
public bool PreserveDirectoryRoot { get; set; } | |
public bool DisableRecursion { get; set; } | |
public bool Append { get; set; } | |
private List<string> _directoryOrFilesFromPipeline; | |
private OutArchiveFormat _inferredOutArchiveFormat; | |
public void Compress() | |
{ | |
_inferredOutArchiveFormat = GetInferredOutArchiveFormat(); | |
if (EncryptFilenames) | |
{ | |
if (_inferredOutArchiveFormat != OutArchiveFormat.SevenZip) | |
{ | |
throw new ArgumentException("Encrypting filenames is supported for 7z format only."); | |
} | |
if (string.IsNullOrEmpty(Password)) | |
{ | |
throw new ArgumentException("Encrypting filenames is supported only when using a password."); | |
} | |
} | |
if (_directoryOrFilesFromPipeline == null) | |
{ | |
_directoryOrFilesFromPipeline = new List<string>(); | |
} | |
_directoryOrFilesFromPipeline.Add(Path); | |
var compressor = new SevenZipCompressor | |
{ | |
ArchiveFormat = _inferredOutArchiveFormat, | |
CompressionLevel = CompressionLevel, | |
CompressionMethod = CompressionMethod, | |
VolumeSize = VolumeSize, | |
EncryptHeaders = EncryptFilenames, | |
DirectoryStructure = !FlattenDirectoryStructure, | |
IncludeEmptyDirectories = !SkipEmptyDirectories, | |
PreserveDirectoryRoot = PreserveDirectoryRoot, | |
CompressionMode = Append ? CompressionMode.Append : CompressionMode.Create | |
}; | |
if (!string.IsNullOrEmpty(TempFolder)) | |
{ | |
compressor.TempFolderPath = TempFolder; | |
} | |
CustomInitialization?.Invoke(compressor); | |
if (_directoryOrFilesFromPipeline == null) | |
{ | |
_directoryOrFilesFromPipeline = new List<string> { Path }; | |
} | |
var outputPathIsNotEmptyOrNull = !string.IsNullOrEmpty(OutputPath); | |
var outputPath = outputPathIsNotEmptyOrNull | |
? OutputPath | |
: Environment.CurrentDirectory; | |
var archiveDirectory = System.IO.Path.GetDirectoryName(ArchiveFileName); | |
if (!string.IsNullOrEmpty(archiveDirectory) && !outputPathIsNotEmptyOrNull) | |
{ | |
if (System.IO.Path.IsPathRooted(archiveDirectory)) | |
outputPath = archiveDirectory; | |
else | |
outputPath = System.IO.Path.Combine(outputPath, archiveDirectory); | |
} | |
if (File.Exists(outputPath)) | |
{ | |
throw new ArgumentException("The output path is a file, not a directory"); | |
} | |
if (!Directory.Exists(outputPath)) | |
{ | |
Directory.CreateDirectory(outputPath); | |
} | |
var directoryOrFiles = _directoryOrFilesFromPipeline | |
.Select(System.IO.Path.GetFullPath).ToArray(); | |
var archiveFileName = System.IO.Path.GetFullPath(System.IO.Path.Combine(outputPath, System.IO.Path.GetFileName(ArchiveFileName))); | |
if (directoryOrFiles.Any(path => new FileInfo(path).Exists)) | |
{ | |
var notFoundFiles = directoryOrFiles.Where(path => !new FileInfo(path).Exists).ToArray(); | |
if (notFoundFiles.Any()) | |
{ | |
throw new FileNotFoundException("File(s) not found: " + string.Join(", ", notFoundFiles)); | |
} | |
if (!string.IsNullOrEmpty(Password)) | |
{ | |
compressor.CompressFilesEncrypted(archiveFileName, Password, directoryOrFiles); | |
} | |
else | |
{ | |
compressor.CompressFiles(archiveFileName, directoryOrFiles); | |
} | |
} | |
else if (directoryOrFiles.Any(path => new DirectoryInfo(path).Exists)) | |
{ | |
if (directoryOrFiles.Length > 1) | |
{ | |
throw new ArgumentException("Only one directory allowed as input"); | |
} | |
var recursion = !DisableRecursion; | |
var filter = string.IsNullOrWhiteSpace(Filter) ? "*" : Filter; | |
if (!string.IsNullOrEmpty(Password)) | |
{ | |
compressor.CompressDirectory(directoryOrFiles[0], archiveFileName, Password, filter, recursion); | |
} | |
else | |
{ | |
compressor.CompressDirectory(directoryOrFiles[0], archiveFileName, null, filter, recursion); | |
} | |
} | |
Console.WriteLine("[+] Compression completed successfully!"); | |
} | |
private OutArchiveFormat GetInferredOutArchiveFormat() | |
{ | |
switch (Format) | |
{ | |
case OutputFormat.Auto: | |
switch (System.IO.Path.GetExtension(ArchiveFileName).ToLowerInvariant()) | |
{ | |
case ".zip": | |
return OutArchiveFormat.Zip; | |
case ".gz": | |
return OutArchiveFormat.GZip; | |
case ".bz2": | |
return OutArchiveFormat.BZip2; | |
case ".tar": | |
return OutArchiveFormat.Tar; | |
case ".xz": | |
return OutArchiveFormat.XZ; | |
default: | |
return OutArchiveFormat.SevenZip; | |
} | |
case OutputFormat.SevenZip: | |
return OutArchiveFormat.SevenZip; | |
case OutputFormat.Zip: | |
return OutArchiveFormat.Zip; | |
case OutputFormat.GZip: | |
return OutArchiveFormat.GZip; | |
case OutputFormat.BZip2: | |
return OutArchiveFormat.BZip2; | |
case OutputFormat.Tar: | |
return OutArchiveFormat.Tar; | |
case OutputFormat.XZ: | |
return OutArchiveFormat.XZ; | |
default: | |
throw new ArgumentOutOfRangeException(); | |
} | |
} | |
} | |
public class Options | |
{ | |
[Option('a', "archive", Required = true, HelpText = "The full file name of the archive")] | |
public string ArchiveFileName { get; set; } | |
[Option('p', "path", Required = true, HelpText = "The source folder or file")] | |
public string Path { get; set; } | |
[Option('f', "filter", HelpText = "The filter to be applied if Path points to a directory")] | |
public string Filter { get; set; } | |
[Option('o', "output", HelpText = "Output path for a compressed archive")] | |
public string OutputPath { get; set; } | |
[Option('m', "method", Default = OutputFormat.Auto, HelpText = "The compression method (Auto, SevenZip, Zip, GZip, BZip2, Tar, XZ)")] | |
public OutputFormat Format { get; set; } | |
[Option('l', "level", Default = CompressionLevel.Normal, HelpText = "The compression level")] | |
public CompressionLevel CompressionLevel { get; set; } | |
[Option('e', "encrypt", HelpText = "Enables encrypting filenames when using the 7z format")] | |
public bool EncryptFilenames { get; set; } | |
[Option('s', "skip-empty", HelpText = "Disables preservation of empty directories")] | |
public bool SkipEmptyDirectories { get; set; } | |
[Option('r', "preserve-root", HelpText = "Preserves directory root")] | |
public bool PreserveDirectoryRoot { get; set; } | |
[Option('d', "disable-recursion", HelpText = "Disables recursive files search")] | |
public bool DisableRecursion { get; set; } | |
[Option('u', "append", HelpText = "Append files to existing archive")] | |
public bool Append { get; set; } | |
[Option('t', "temp", HelpText = "The temporary folder path; if not specified, %TEMP% will be used")] | |
public string TempFolder { get; set; } | |
[Option('v', "volume-size", Default = 0, HelpText = "Specifies the volume sizes in bytes, 0 for no volumes")] | |
public int VolumeSize { get; set; } | |
[Option('w', "password", HelpText = "The password to use for encryption")] | |
public string Password { get; set; } | |
[Option('h', "help", HelpText = "Display this help screen")] | |
public bool ShowHelp { get; set; } | |
} | |
internal static class Program | |
{ | |
static void DisplayHelp<T>(ParserResult<T> result, IEnumerable<Error> errors) | |
{ | |
var helpText = HelpText.AutoBuild( | |
result, | |
h => | |
{ | |
h.AdditionalNewLineAfterOption = false; | |
h.Heading = ""; | |
h.AutoVersion = false; | |
h.MaximumDisplayWidth = 120; | |
h.Copyright = ""; | |
return HelpText.DefaultParsingErrorsHandler(result, h); | |
}, | |
e => e); | |
Console.WriteLine(helpText); | |
} | |
private static void Main(string[] args) | |
{ | |
// workaround for issue #75: https://github.com/Fody/Costura/issues/75 | |
var dllName = typeof(ArchiveFileInfo).Assembly.GetFile("sevenzipsharp.dll").Name; | |
var cosuraPath = Path.GetDirectoryName(dllName); | |
Console.WriteLine($"[!] Temporary assemblies path: {cosuraPath}"); | |
SevenZipBase.SetLibraryPath(Path.Combine(cosuraPath, @"64\7za.dll")); | |
var parser = new Parser(with => with.HelpWriter = null); | |
var parserResult = parser.ParseArguments<Options>(args); | |
try | |
{ | |
parserResult | |
.WithParsed(options => | |
new Compress7Zip | |
{ | |
ArchiveFileName = options.ArchiveFileName, | |
Path = options.Path, | |
Filter = options.Filter, | |
OutputPath = options.OutputPath, | |
Format = options.Format, | |
CompressionLevel = options.CompressionLevel, | |
EncryptFilenames = options.EncryptFilenames, | |
SkipEmptyDirectories = options.SkipEmptyDirectories, | |
PreserveDirectoryRoot = options.PreserveDirectoryRoot, | |
DisableRecursion = options.DisableRecursion, | |
Append = options.Append, | |
TempFolder = options.TempFolder, | |
VolumeSize = options.VolumeSize, | |
Password = options.Password | |
}.Compress()) | |
.WithNotParsed(errs => DisplayHelp(parserResult, errs)); | |
} | |
catch (Exception e) | |
{ | |
Console.WriteLine($"[-] {e.Message}"); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment