//------------------------------------------------------------------------------
//
// zf - A command line archiver using the ZipFile class from SharpZipLib
// for compression
//
// Copyright 2006, 2010 John Reilly
//
//------------------------------------------------------------------------------
// Version History
// 1 Initial version ported from sz sample. Some stuff is not used or commented still
// 2 Display files during extract. --env Now shows .NET version information.
// 3 Add usezip64 option as a testing aid.
// 4 Fix format bug in output, remove unused code and other minor refactoring
using System;
using System.IO;
using System.Collections;
using System.Text;
using System.Globalization;
using System.Reflection;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Core;
namespace ICSharpCode.SharpZipLib.Samples.CS.ZF
{
///
/// A command line archiver using the class from SharpZipLib compression library
///
public class ZipFileArchiver
{
#region Enumerations
///
/// Options for handling overwriting of files.
///
enum Overwrite
{
Prompt,
Never,
Always
}
///
/// Operations that can be performed
///
enum Operation
{
Create, // add files to new archive
Extract, // extract files from existing archive
List, // show contents of existing archive
Delete, // Delete from archive
Add, // Add to archive.
Test, // Test the archive for validity.
}
#endregion
#region Constructors
///
/// Initializes a new instance of the class.
///
public ZipFileArchiver()
{
// Do nothing.
}
#endregion
#region Argument Parsing
///
/// Parse command line arguments.
/// This is fairly flexible without using any custom classes. Arguments and options can appear
/// in any order and are case insensitive. Arguments for options are signalled with an '='
/// as in -demo=argument, sometimes the '=' can be omitted as well secretly.
/// Grouping of single character options is supported.
///
///
/// true if arguments are valid such that processing should continue
///
bool SetArgs(string[] args)
{
bool result = true;
int argIndex = 0;
while (argIndex < args.Length)
{
if (args[argIndex][0] == '-' || args[argIndex][0] == '/')
{
string option = args[argIndex].Substring(1).ToLower();
string optArg = "";
int parameterIndex = option.IndexOf('=');
if (parameterIndex >= 0)
{
if (parameterIndex < option.Length - 1)
{
optArg = option.Substring(parameterIndex + 1);
}
option = option.Substring(0, parameterIndex);
}
#if OPTIONTEST
Console.WriteLine("args index [{0}] option [{1}] argument [{2}]", argIndex, option, optArg);
#endif
if (option.Length == 0)
{
Console.Error.WriteLine("Invalid argument '{0}'", args[argIndex]);
result = false;
}
else
{
int optionIndex = 0;
while (optionIndex < option.Length)
{
#if OPTIONTEST
Console.WriteLine("optionIndex {0}", optionIndex);
#endif
switch(option[optionIndex])
{
case '-': // long option
optionIndex = option.Length;
switch (option)
{
case "-add":
operation_ = Operation.Add;
break;
case "-create":
operation_ = Operation.Create;
break;
case "-list":
operation_ = Operation.List;
break;
case "-extract":
operation_ = Operation.Extract;
if (optArg.Length > 0)
{
targetOutputDirectory_ = optArg;
}
break;
case "-delete":
operation_ = Operation.Delete;
break;
case "-test":
operation_ = Operation.Test;
break;
case "-env":
ShowEnvironment();
break;
case "-emptydirs":
addEmptyDirectoryEntries_ = true;
break;
case "-data":
testData_ = true;
break;
case "-zip64":
if ( optArg.Length > 0 )
{
switch ( optArg )
{
case "on":
useZip64_ = UseZip64.On;
break;
case "off":
useZip64_ = UseZip64.Off;
break;
case "auto":
useZip64_ = UseZip64.Dynamic;
break;
}
}
break;
case "-encoding":
if (optArg.Length > 0)
{
if (IsNumeric(optArg))
{
try
{
int enc = int.Parse(optArg);
if (Encoding.GetEncoding(enc) != null)
{
#if OPTIONTEST
Console.WriteLine("Encoding set to {0}", enc);
#endif
ZipConstants.DefaultCodePage = enc;
}
else
{
result = false;
Console.Error.WriteLine("Invalid encoding " + args[argIndex]);
}
}
catch (Exception)
{
result = false;
Console.Error.WriteLine("Invalid encoding " + args[argIndex]);
}
}
else
{
try
{
ZipConstants.DefaultCodePage = Encoding.GetEncoding(optArg).CodePage;
}
catch (Exception)
{
result = false;
Console.Error.WriteLine("Invalid encoding " + args[argIndex]);
}
}
}
else
{
result = false;
Console.Error.WriteLine("Missing encoding parameter");
}
break;
case "-version":
ShowVersion();
break;
case "-help":
ShowHelp();
break;
case "-restore-dates":
restoreDateTime_ = true;
break;
default:
Console.Error.WriteLine("Invalid long argument " + args[argIndex]);
result = false;
break;
}
break;
case '?':
ShowHelp();
break;
case 's':
if (optionIndex != 0)
{
result = false;
Console.Error.WriteLine("-s cannot be in a group");
}
else
{
if (optArg.Length > 0)
{
password_ = optArg;
}
else if (option.Length > 1)
{
password_ = option.Substring(1);
}
else
{
Console.Error.WriteLine("Missing argument to " + args[argIndex]);
}
}
optionIndex = option.Length;
break;
case 't':
operation_ = Operation.Test;
break;
case 'c':
operation_ = Operation.Create;
break;
case 'o':
optionIndex += 1;
overwriteFiles = optionIndex < option.Length ? (option[optionIndex] == '+') ? Overwrite.Always : Overwrite.Never : Overwrite.Never;
break;
case 'q':
silent_ = true;
if (overwriteFiles == Overwrite.Prompt)
{
overwriteFiles = Overwrite.Never;
}
break;
case 'r':
recursive_ = true;
break;
case 'v':
operation_ = Operation.List;
break;
case 'x':
if (optionIndex != 0)
{
result = false;
Console.Error.WriteLine("-x cannot be in a group");
}
else
{
operation_ = Operation.Extract;
if (optArg.Length > 0)
{
targetOutputDirectory_ = optArg;
}
}
optionIndex = option.Length;
break;
default:
Console.Error.WriteLine("Invalid argument: " + args[argIndex]);
result = false;
break;
}
++optionIndex;
}
}
}
else
{
#if OPTIONTEST
Console.WriteLine("file spec {0} = '{1}'", argIndex, args[argIndex]);
#endif
fileSpecs_.Add(args[argIndex]);
}
++argIndex;
}
if (fileSpecs_.Count > 0)
{
string checkPath = (string)fileSpecs_[0];
int deviceCheck = checkPath.IndexOf(':');
#if NET_VER_1
if (checkPath.IndexOfAny(Path.InvalidPathChars) >= 0
#else
if (checkPath.IndexOfAny(Path.GetInvalidPathChars()) >= 0
#endif
|| checkPath.IndexOf('*') >= 0 || checkPath.IndexOf('?') >= 0
|| ((deviceCheck >= 0) && (deviceCheck != 1)))
{
Console.WriteLine("There are invalid characters in the specified zip file name");
result = false;
}
}
return result && (fileSpecs_.Count > 0);
}
#endregion
#region Show - Help/Environment/Version
///
/// Show encoding/locale information
///
void ShowEnvironment()
{
seenHelp_ = true;
Console.Out.WriteLine("");
Console.Out.WriteLine(
"Current encoding is {0}, code page {1}, windows code page {2}",
Console.Out.Encoding.EncodingName,
Console.Out.Encoding.CodePage,
Console.Out.Encoding.WindowsCodePage);
Console.WriteLine("Default code page is {0}",
Encoding.Default.CodePage);
Console.WriteLine( "Current culture LCID 0x{0:X}, {1}", CultureInfo.CurrentCulture.LCID, CultureInfo.CurrentCulture.EnglishName);
Console.WriteLine( "Current thread OEM codepage {0}", System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.OEMCodePage);
Console.WriteLine( "Current thread Mac codepage {0}", System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.MacCodePage);
Console.WriteLine( "Current thread Ansi codepage {0}", System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ANSICodePage);
Console.WriteLine(".NET version {0}", Environment.Version);
}
///
/// Display version information
///
void ShowVersion()
{
seenHelp_ = true;
Console.Out.WriteLine("ZipFile Archiver v0.3 Copyright 2006 John Reilly");
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
if (assembly.GetName().Name == "ICSharpCode.SharpZipLib")
{
Console.Out.WriteLine("#ZipLib v{0} {1}", assembly.GetName().Version,
assembly.GlobalAssemblyCache ? "Running from GAC" : "Running from DLL"
);
}
}
Console.Out.WriteLine();
}
///
/// Show help on possible options and arguments
///
void ShowHelp()
{
if (seenHelp_)
{
return;
}
seenHelp_ = true;
ShowVersion();
Console.Out.WriteLine("usage zf {options} archive files");
Console.Out.WriteLine("");
Console.Out.WriteLine("Options:");
Console.Out.WriteLine("--add Add files to archive");
Console.Out.WriteLine("--create Create new archive");
Console.Out.WriteLine("--data Test archive data"); Console.Out.WriteLine("--delete Delete files from archive");
Console.Out.WriteLine("--encoding=codepage|name Set code page for encoding by name or number");
Console.Out.WriteLine("--extract{=dir} Extract archive contents to dir(default .)");
Console.Out.WriteLine("--help Show this help");
Console.Out.WriteLine("--env Show current environment information" );
Console.Out.WriteLine("--list List archive contents extended format");
Console.Out.WriteLine("--test Test archive for validity");
Console.Out.WriteLine("--version Show version information");
Console.Out.WriteLine("-r Recurse sub-folders");
Console.Out.WriteLine("-s=password Set archive password");
Console.Out.WriteLine("--zip64=[on|off|auto] Zip64 extension handling to use");
/*
Console.Out.WriteLine("--store Store entries (default=deflate)");
Console.Out.WriteLine("--emptydirs Create entries for empty directories");
Console.Out.WriteLine("--restore-dates Restore dates on extraction");
Console.Out.WriteLine("-o+ Overwrite files without prompting");
Console.Out.WriteLine("-o- Never overwrite files");
Console.Out.WriteLine("-q Quiet mode");
*/
Console.Out.WriteLine("");
}
#endregion
#region Archive Listing
void ListArchiveContents(ZipFile zipFile, FileInfo fileInfo)
{
const string headerTitles = "Name Length Ratio Size Date & time CRC-32 Attr";
const string headerUnderline = "------------ ---------- ----- ---------- ------------------- -------- ------";
int entryCount = 0;
long totalCompressedSize = 0;
long totalSize = 0;
foreach (ZipEntry theEntry in zipFile)
{
if ( theEntry.IsDirectory )
{
Console.Out.WriteLine("Directory {0}", theEntry.Name);
}
else if ( !theEntry.IsFile )
{
Console.Out.WriteLine("Non file entry {0}", theEntry.Name);
continue;
}
else
{
if (entryCount == 0)
{
Console.Out.WriteLine(headerTitles);
Console.Out.WriteLine(headerUnderline);
}
++entryCount;
int ratio = GetCompressionRatio(theEntry.CompressedSize, theEntry.Size);
totalSize += theEntry.Size;
totalCompressedSize += theEntry.CompressedSize;
char cryptoDisplay = ( theEntry.IsCrypted ) ? '*' : ' ';
if (theEntry.Name.Length > 12)
{
Console.Out.WriteLine(theEntry.Name);
Console.Out.WriteLine(
"{0,-12}{7} {1,10:0} {2,3}% {3,10:0} {4,10:d} {4:hh:mm:ss} {5,8:x} {6,4}",
"", theEntry.Size, ratio, theEntry.CompressedSize, theEntry.DateTime, theEntry.Crc,
InterpretExternalAttributes(theEntry.HostSystem, theEntry.ExternalFileAttributes),
cryptoDisplay);
}
else
{
Console.Out.WriteLine(
"{0,-12}{7} {1,10:0} {2,3}% {3,10:0} {4,10:d} {4:hh:mm:ss} {5,8:x} {6,4}",
theEntry.Name, theEntry.Size, ratio, theEntry.CompressedSize, theEntry.DateTime, theEntry.Crc,
InterpretExternalAttributes(theEntry.HostSystem, theEntry.ExternalFileAttributes),
cryptoDisplay);
}
}
}
if (entryCount == 0)
{
Console.Out.WriteLine("Archive is empty!");
}
else
{
Console.Out.WriteLine(headerUnderline);
Console.Out.WriteLine(
"{0,-12} {1,10:0} {2,3}% {3,10:0} {4,10:d} {4:hh:mm:ss}",
entryCount.ToString() + " entries", totalSize, GetCompressionRatio(totalCompressedSize, totalSize), fileInfo.Length, fileInfo.LastWriteTime);
}
}
///
/// List zip file contents using ZipFile class
///
/// File to list contents of
void ListArchiveContents(string fileName)
{
try
{
FileInfo fileInfo = new FileInfo(fileName);
if (!fileInfo.Exists)
{
Console.Error.WriteLine("No such file exists {0}", fileName);
}
else
{
Console.Out.WriteLine(fileName);
try
{
using (ZipFile zipFile = new ZipFile(fileName))
{
ListArchiveContents(zipFile, fileInfo);
}
}
catch(Exception ex)
{
Console.Out.WriteLine("Problem reading archive - '{0}'", ex.Message);
}
}
}
catch(Exception exception)
{
Console.Error.WriteLine("Exception during list operation: {0}", exception.Message);
}
}
///
/// Execute List operation
/// Currently only Zip files are supported
///
/// Files to list
void List(ArrayList fileSpecs)
{
foreach (string spec in fileSpecs)
{
string pathName = Path.GetDirectoryName(spec);
if ( (pathName == null) || (pathName.Length == 0) )
{
pathName = @".\";
}
string[] names = Directory.GetFiles(pathName, Path.GetFileName(spec));
if (names.Length == 0)
{
Console.Error.WriteLine("No files found matching {0}", spec);
}
else
{
foreach (string file in names)
{
ListArchiveContents(file);
}
Console.Out.WriteLine("");
}
}
}
#endregion
#region Creation
///
/// Create archives based on specifications passed and internal state
///
void Create(ArrayList fileSpecs)
{
string zipFileName = fileSpecs[0] as string;
if (Path.GetExtension(zipFileName).Length == 0)
{
zipFileName = Path.ChangeExtension(zipFileName, ".zip");
}
fileSpecs.RemoveAt(0);
if ( (overwriteFiles == Overwrite.Never) && File.Exists(zipFileName))
{
Console.Error.WriteLine("File {0} already exists", zipFileName);
return;
}
try
{
using (ZipFile zf = ZipFile.Create(zipFileName) )
{
zf.Password = password_;
zf.UseZip64 = useZip64_;
zf.BeginUpdate();
activeZipFile_ = zf;
foreach (string spec in fileSpecs)
{
// This can fail with wildcards in spec...
string path = Path.GetDirectoryName(Path.GetFullPath(spec));
string fileSpec = Path.GetFileName(spec);
zf.NameTransform = new ZipNameTransform(path);
FileSystemScanner scanner = new FileSystemScanner(WildcardToRegex(fileSpec));
scanner.ProcessFile = new ProcessFileHandler(ProcessFile);
scanner.ProcessDirectory = new ProcessDirectoryHandler(ProcessDirectory);
scanner.Scan(path, recursive_);
}
zf.CommitUpdate();
}
}
catch (Exception ex)
{
Console.WriteLine("Problem creating archive - '{0}'", ex.Message);
}
}
#endregion
#region Extraction
///
/// Extract a file storing its contents.
///
/// The input stream to source file contents from.
/// The representing the stored file details
/// The directory to store the output.
/// True if operation is successful; false otherwise.
bool ExtractFile(Stream inputStream, ZipEntry theEntry, string targetDir)
{
// try and sort out the correct place to save this entry
string entryFileName;
if (Path.IsPathRooted(theEntry.Name))
{
string workName = Path.GetPathRoot(theEntry.Name);
workName = theEntry.Name.Substring(workName.Length);
entryFileName = Path.Combine(Path.GetDirectoryName(workName), Path.GetFileName(theEntry.Name));
}
else
{
entryFileName = theEntry.Name;
}
string targetName = Path.Combine(targetDir, entryFileName);
string fullPath = Path.GetDirectoryName(Path.GetFullPath(targetName));
#if TEST
Console.WriteLine("Decompress targetfile name " + entryFileName);
Console.WriteLine("Decompress targetpath " + fullPath);
#endif
// Could be an option or parameter to allow failure or try creation
if (Directory.Exists(fullPath) == false)
{
try
{
Directory.CreateDirectory(fullPath);
}
catch
{
return false;
}
}
else if (overwriteFiles == Overwrite.Prompt)
{
if (File.Exists(targetName))
{
Console.Write("File " + targetName + " already exists. Overwrite? ");
string readValue;
try
{
readValue = Console.ReadLine();
}
catch
{
readValue = null;
}
if ( (readValue == null) || (readValue.ToLower() != "y") )
{
return true;
}
}
}
if (entryFileName.Length > 0)
{
if ( !silent_ )
{
Console.Write("{0}", targetName);
}
using (FileStream outputStream = File.Create(targetName))
{
StreamUtils.Copy(inputStream, outputStream, GetBuffer());
}
if (restoreDateTime_)
{
File.SetLastWriteTime(targetName, theEntry.DateTime);
}
if ( !silent_ )
{
Console.WriteLine(" OK");
}
}
return true;
}
///
/// Decompress a file
///
/// File to decompress
/// Directory to create output in
/// true iff all has been done successfully
bool DecompressArchive(string fileName, string targetDir)
{
bool result = true;
try
{
using (ZipFile zf = new ZipFile(fileName))
{
zf.Password = password_;
foreach ( ZipEntry entry in zf )
{
if ( entry.IsFile )
{
ExtractFile(zf.GetInputStream(entry), entry, targetDir);
}
else
{
if ( !silent_ )
{
Console.WriteLine("Skipping {0}", entry.Name);
}
}
}
if ( !silent_ )
{
Console.WriteLine("Done");
}
}
}
catch(Exception ex)
{
Console.WriteLine("Exception decompressing - '{0}'", ex);
result = false;
}
return result;
}
///
/// Extract archives based on user input
/// Allows simple wildcards to specify multiple archives
///
void Extract(ArrayList fileSpecs)
{
if ( (targetOutputDirectory_ == null) || (targetOutputDirectory_.Length == 0) )
{
targetOutputDirectory_ = @".\";
}
foreach(string spec in fileSpecs)
{
string [] names;
if ( (spec.IndexOf('*') >= 0) || (spec.IndexOf('?') >= 0) )
{
string pathName = Path.GetDirectoryName(spec);
if ( (pathName == null) || (pathName.Length == 0) )
{
pathName = @".\";
}
names = Directory.GetFiles(pathName, Path.GetFileName(spec));
}
else
{
names = new string[] { spec };
}
foreach (string fileName in names)
{
if (File.Exists(fileName) == false)
{
Console.Error.WriteLine("No such file exists {0}", fileName);
}
else
{
DecompressArchive(fileName, targetOutputDirectory_);
}
}
}
}
#endregion
#region Testing
///
/// Handler for test result callbacks.
///
/// The current .
/// The message applicable for this result.
void TestResultHandler(TestStatus status, string message)
{
switch ( status.Operation )
{
case TestOperation.Initialising:
Console.WriteLine("Testing");
break;
case TestOperation.Complete:
Console.WriteLine("Testing complete");
break;
case TestOperation.EntryHeader:
// Not an error if message is null.
if ( message == null )
{
Console.Write("{0} - ", status.Entry.Name);
}
else
{
Console.WriteLine(message);
}
break;
case TestOperation.EntryData:
if ( message != null )
{
Console.WriteLine(message);
}
break;
case TestOperation.EntryComplete:
if ( status.EntryValid )
{
Console.WriteLine("OK");
}
break;
case TestOperation.MiscellaneousTests:
if ( message != null )
{
Console.WriteLine(message);
}
break;
}
}
///
/// Test an archive to see if its valid.
///
/// The files to test.
void Test(ArrayList fileSpecs)
{
string zipFileName = fileSpecs[0] as string;
if (Path.GetExtension(zipFileName).Length == 0)
{
zipFileName = Path.ChangeExtension(zipFileName, ".zip");
}
try
{
using (ZipFile zipFile = new ZipFile(zipFileName))
{
zipFile.Password = password_;
if ( zipFile.TestArchive(testData_, TestStrategy.FindAllErrors,
new ZipTestResultHandler(TestResultHandler)) )
{
Console.Out.WriteLine("Archive test passed");
}
else
{
Console.Out.WriteLine("Archive test failure");
}
}
}
catch(Exception ex)
{
Console.Out.WriteLine("Error list files - '{0}'", ex.Message);
}
}
#endregion
#region Deleting
///
/// Delete entries from an archive
///
/// The file specs to operate on.
void Delete(ArrayList fileSpecs)
{
string zipFileName = fileSpecs[0] as string;
if (Path.GetExtension(zipFileName).Length == 0)
{
zipFileName = Path.ChangeExtension(zipFileName, ".zip");
}
try
{
using (ZipFile zipFile = new ZipFile(zipFileName))
{
zipFile.BeginUpdate();
for ( int i = 1; i < fileSpecs.Count; ++i )
{
zipFile.Delete((string)fileSpecs[i]);
}
zipFile.CommitUpdate();
}
}
catch(Exception ex)
{
Console.WriteLine("Problem deleting files - '{0}'", ex.Message);
}
}
#endregion
#region Adding
///
/// Callback for adding a new file.
///
/// The scanner calling this delegate.
/// The event arguments.
void ProcessFile(object sender, ScanEventArgs args)
{
if ( !silent_ )
{
Console.WriteLine(args.Name);
}
activeZipFile_.Add(args.Name);
}
///
/// Callback for adding a new directory.
///
/// The scanner calling this delegate.
/// The event arguments.
/// Directories are only added if they are empty and
/// the user has specified that empty directories are to be added.
void ProcessDirectory(object sender, DirectoryEventArgs args)
{
if ( !args.HasMatchingFiles && addEmptyDirectoryEntries_ )
{
activeZipFile_.AddDirectory(args.Name);
}
}
///
/// Add files to an archive
///
/// The specification for files to add.
void Add(ArrayList fileSpecs)
{
string zipFileName = fileSpecs[0] as string;
if (Path.GetExtension(zipFileName).Length == 0)
{
zipFileName = Path.ChangeExtension(zipFileName, ".zip");
}
fileSpecs.RemoveAt(0);
ZipFile zipFile;
try
{
if ( File.Exists(zipFileName) )
{
zipFile = new ZipFile(zipFileName);
}
else
{
zipFile = ZipFile.Create(zipFileName);
}
using (zipFile)
{
zipFile.Password = password_;
zipFile.UseZip64 = useZip64_;
zipFile.BeginUpdate();
activeZipFile_ = zipFile;
foreach (string spec in fileSpecs)
{
string path = Path.GetDirectoryName(Path.GetFullPath(spec));
string fileSpec = Path.GetFileName(spec);
zipFile.NameTransform = new ZipNameTransform(path);
FileSystemScanner scanner = new FileSystemScanner(WildcardToRegex(fileSpec));
scanner.ProcessFile = new ProcessFileHandler(ProcessFile);
scanner.ProcessDirectory = new ProcessDirectoryHandler(ProcessDirectory);
scanner.Scan(path, recursive_);
}
zipFile.CommitUpdate();
}
}
catch(Exception ex)
{
Console.WriteLine("Problem adding to archive - '{0}'", ex.Message);
}
}
#endregion
#region Class Execute Command
///
/// Parse command line arguments and 'execute' them.
///
void Execute(string[] args)
{
if (SetArgs(args))
{
if (fileSpecs_.Count == 0)
{
if (!silent_)
{
Console.Out.WriteLine("Nothing to do");
}
}
else
{
switch (operation_)
{
case Operation.List:
List(fileSpecs_);
break;
case Operation.Create:
Create(fileSpecs_);
break;
case Operation.Extract:
Extract(fileSpecs_);
break;
case Operation.Delete:
Delete(fileSpecs_);
break;
case Operation.Add:
Add(fileSpecs_);
break;
case Operation.Test:
Test(fileSpecs_);
break;
}
}
}
else
{
if ( !silent_ )
{
ShowHelp();
}
}
}
#endregion
#region Support Routines
byte[] GetBuffer()
{
if ( buffer_ == null )
{
buffer_ = new byte[bufferSize_];
}
return buffer_;
}
#endregion
#region Static support routines
///
/// Calculate compression ratio as a percentage
/// This wont allow for expansion (ratio > 100) as the resulting strings can get huge easily
///
static int GetCompressionRatio(long packedSize, long unpackedSize)
{
int result = 0;
if ( (unpackedSize > 0) && (unpackedSize >= packedSize) )
{
result = (int) Math.Round((1.0 - ((double)packedSize / (double)unpackedSize)) * 100.0);
}
return result;
}
///
/// Interpret attributes in conjunction with operatingSystem
///
/// The operating system.
/// The external attributes.
/// A string representation of the attributres passed.
static string InterpretExternalAttributes(int operatingSystem, int attributes)
{
string result = string.Empty;
if ((operatingSystem == 0) || (operatingSystem == 10))
{
if ((attributes & 0x10) != 0)
result = result + "D";
else
result = result + "-";
if ((attributes & 0x08) != 0)
result = result + "V";
else
result = result + "-";
if ((attributes & 0x01) != 0)
result = result + "r";
else
result = result + "-";
if ((attributes & 0x20) != 0)
result = result + "a";
else
result = result + "-";
if ((attributes & 0x04) != 0)
result = result + "s";
else
result = result + "-";
if ((attributes & 0x02) != 0)
result = result + "h";
else
result = result + "-";
// Device
if ((attributes & 0x4) != 0)
result = result + "d";
else
result = result + "-";
// OS is NTFS
if ( operatingSystem == 10 )
{
// Encrypted
if ( (attributes & 0x4000) != 0 )
{
result += "E";
}
else
{
result += "-";
}
// Not content indexed
if ( (attributes & 0x2000) != 0 )
{
result += "n";
}
else
{
result += "-";
}
// Offline
if ( (attributes & 0x1000) != 0 )
{
result += "O";
}
else
{
result += "-";
}
// Compressed
if ( (attributes & 0x0800) != 0 )
{
result += "C";
}
else
{
result += "-";
}
// Reparse point
if ( (attributes & 0x0400) != 0 )
{
result += "R";
}
else
{
result += "-";
}
// Sparse
if ( (attributes & 0x0200) != 0 )
{
result += "S";
}
else
{
result += "-";
}
// Temporary
if ( (attributes & 0x0100) != 0 )
{
result += "T";
}
else
{
result += "-";
}
}
}
return result;
}
///
/// Determine if string is numeric [0-9]+
///
/// string to test
/// true iff rhs is numeric
static bool IsNumeric(string rhs)
{
bool result;
if (rhs != null && rhs.Length > 0)
{
result = true;
for (int i = 0; i < rhs.Length; ++i)
{
if (!char.IsDigit(rhs[i]))
{
result = false;
break;
}
}
}
else
{
result = false;
}
return result;
}
///
/// Make external attributes suitable for a
///
/// The to convert
/// Returns External Attributes for Zip use
static int MakeExternalAttributes(FileInfo info)
{
return (int)info.Attributes;
}
///
/// Convert a wildcard expression to a regular expression
///
/// The wildcard expression to convert.
/// A regular expression representing the converted wildcard expression.
static string WildcardToRegex(string wildcard)
{
int dotPos = wildcard.IndexOf('.');
bool dotted = (dotPos >= 0) && (dotPos < wildcard.Length - 1);
string converted = wildcard.Replace(".", @"\.");
converted = converted.Replace("?", ".");
converted = converted.Replace("*", ".*");
converted = converted.Replace("(", @"\(");
converted = converted.Replace(")", @"\)");
if ( dotted )
{
converted += "$";
}
return converted;
}
#endregion
#region Main
///
/// Entry point for program, creates archiver and runs it
///
///
/// Command line argument to process
///
public static void Main(string[] args)
{
ZipFileArchiver zf = new ZipFileArchiver();
zf.Execute(args);
}
#endregion
#region Instance Fields
///
/// Has user already seen help output?
///
bool seenHelp_;
///
/// File specifications possibly with wildcards from command line
///
ArrayList fileSpecs_ = new ArrayList();
///
/// Create entries for directories with no files
///
bool addEmptyDirectoryEntries_;
///
/// Apply operations recursively
///
bool recursive_;
///
/// Operate silently
///
bool silent_;
///
/// Restore file date and time to that stored in zip file on extraction
///
bool restoreDateTime_;
///
/// Overwrite files handling
///
Overwrite overwriteFiles = Overwrite.Prompt;
///
/// Optional password for archive
///
string password_;
///
/// Where things will go when decompressed.
///
string targetOutputDirectory_;
///
/// What to do based on parsed command line arguments
///
Operation operation_ = Operation.List;
///
/// Flag whose value is true if data should be tested; false if it should not.
///
bool testData_;
///
/// The currently active .
///
/// Used for callbacks/delegates
ZipFile activeZipFile_;
///
/// Buffer used during some operations
///
byte[] buffer_;
///
/// The size of buffer to provide.
///
int bufferSize_ = 4096;
///
/// The Zip64 extension use to apply.
///
UseZip64 useZip64_ = UseZip64.Off;
#endregion
}
}