#pragma warning disable 3021 /* This file is part of SevenZipSharp. SevenZipSharp is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SevenZipSharp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with SevenZipSharp. If not, see . */ #define DOTNET20 #define UNMANAGED #define COMPRESS using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Globalization; #if !WINCE using System.Runtime.Remoting.Messaging; #endif #if DOTNET20 using System.Threading; #else using System.Windows.Threading; #endif #if MONO using SevenZip.Mono.COM; #endif namespace SevenZip { #if UNMANAGED /// /// The way of the event synchronization. /// public enum EventSynchronizationStrategy { /// /// Events are called synchronously if user can do some action; that is, cancel the execution process for example. /// Default, /// /// Always call events asynchronously. /// AlwaysAsynchronous, /// /// Always call events synchronously. /// AlwaysSynchronous } /// /// SevenZip Extractor/Compressor base class. Implements Password string, ReportErrors flag. /// public abstract class SevenZipBase : MarshalByRefObject { private readonly string _password; private readonly bool _reportErrors; private readonly int _uniqueID; private static readonly List Identificators = new List(); #if !WINCE internal static readonly AsyncCallback AsyncCallbackImplementation = AsyncCallbackMethod; /// /// True if the instance of the class needs to be recreated in new thread context; otherwise, false. /// protected internal bool NeedsToBeRecreated; /// /// AsyncCallback implementation used in asynchronous invocations. /// /// IAsyncResult instance. internal static void AsyncCallbackMethod(IAsyncResult ar) { var result = (AsyncResult)ar; result.AsyncDelegate.GetType().GetMethod("EndInvoke").Invoke(result.AsyncDelegate, new[] { ar }); ((SevenZipBase)ar.AsyncState).ReleaseContext(); } virtual internal void SaveContext( #if !DOTNET20 DispatcherPriority priority = DispatcherPriority.Normal #endif ) { #if !DOTNET20 Dispatcher = Dispatcher.CurrentDispatcher; Priority = priority; #else Context = SynchronizationContext.Current; #endif NeedsToBeRecreated = true; } virtual internal void ReleaseContext() { #if !DOTNET20 Dispatcher = null; #else Context = null; #endif NeedsToBeRecreated = true; GC.SuppressFinalize(this); } private delegate void EventHandlerDelegate(EventHandler handler, T e) where T : EventArgs; internal void OnEvent(EventHandler handler, T e, bool synchronous) where T : EventArgs { try { if (handler != null) { switch (EventSynchronization) { case EventSynchronizationStrategy.AlwaysAsynchronous: synchronous = false; break; case EventSynchronizationStrategy.AlwaysSynchronous: synchronous = true; break; } if ( #if !DOTNET20 Dispatcher == null #else Context == null #endif ) { // Usual synchronous call handler(this, e); } else { #if !DOTNET20 var eventHandlerDelegate = new EventHandlerDelegate((h, ee) => h(this, ee)); if (synchronous) { // Could be just handler(this, e); Dispatcher.Invoke(eventHandlerDelegate, Priority, handler, e); } else { Dispatcher.BeginInvoke(eventHandlerDelegate, Priority, handler, e); } #else var callback = new SendOrPostCallback((obj) => { var array = (object[])obj; ((EventHandler)array[0])(array[1], (T)array[2]); }); if (synchronous) { // Could be just handler(this, e); this.Context.Send(callback, new object[] { handler, this, e }); } else { this.Context.Post(callback, new object[] { handler, this, e }); } #endif } } } catch (Exception ex) { AddException(ex); } } #if !DOTNET20 /// /// Gets or sets the Dispatcher object for this instance. /// It will be used to fire events in the user context. /// internal Dispatcher Dispatcher { get; set; } /// /// Gets or sets the Dispatcher priority of calling user events. /// internal DispatcherPriority Priority { get; set; } #else internal SynchronizationContext Context { get; set; } #endif /// /// Gets or sets the event synchronization strategy. /// public EventSynchronizationStrategy EventSynchronization { get; set; } #else // WINCE internal void OnEvent(EventHandler handler, T e, bool synchronous) where T : System.EventArgs { try { handler(this, e); } catch (Exception ex) { AddException(ex); } } #endif /// /// Gets the unique identificator of this SevenZipBase instance. /// public int UniqueID { get { return _uniqueID; } } /// /// User exceptions thrown during the requested operations, for example, in events. /// private readonly List _exceptions = new List(); private static int GetUniqueID() { lock(Identificators) { int id; var rnd = new Random(DateTime.Now.Millisecond); do { id = rnd.Next(Int32.MaxValue); } while (Identificators.Contains(id)); Identificators.Add(id); return id; } } #region Constructors /// /// Initializes a new instance of the SevenZipBase class. /// protected SevenZipBase() { _password = ""; _reportErrors = true; _uniqueID = GetUniqueID(); } /// /// Initializes a new instance of the SevenZipBase class /// /// The archive password. protected SevenZipBase(string password) { if (String.IsNullOrEmpty(password)) { throw new SevenZipException("Empty password was specified."); } _password = password; _reportErrors = true; _uniqueID = GetUniqueID(); } #endregion /// /// Removes the UniqueID from the list. /// ~SevenZipBase() { // This lock probably isn't necessary but just in case... lock (Identificators) { Identificators.Remove(_uniqueID); } } /// /// Gets or sets the archive password /// public string Password { get { return _password; } } /// /// Gets or sets throw exceptions on archive errors flag /// internal bool ReportErrors { get { return _reportErrors; } } /// /// Gets the user exceptions thrown during the requested operations, for example, in events. /// internal ReadOnlyCollection Exceptions { get { return new ReadOnlyCollection(_exceptions); } } internal void AddException(Exception e) { _exceptions.Add(e); } internal void ClearExceptions() { _exceptions.Clear(); } internal bool HasExceptions { get { return _exceptions.Count > 0; } } /// /// Throws the specified exception when is able to. /// /// The exception to throw. /// The handler responsible for the exception. internal bool ThrowException(CallbackBase handler, params Exception[] e) { if (_reportErrors && (handler == null || !handler.Canceled)) { throw e[0]; } return false; } internal void ThrowUserException() { if (HasExceptions) { throw new SevenZipException(SevenZipException.USER_EXCEPTION_MESSAGE); } } /// /// Throws exception if HRESULT != 0. /// /// Result code to check. /// Exception message. /// The class responsible for the callback. internal void CheckedExecute(int hresult, string message, CallbackBase handler) { if (hresult != (int)OperationResult.Ok || handler.HasExceptions) { if (!handler.HasExceptions) { if (hresult < -2000000000) { ThrowException(handler, new SevenZipException( "The execution has failed due to the bug in the SevenZipSharp.\n" + "Please report about it to http://sevenzipsharp.codeplex.com/WorkItem/List.aspx, post the release number and attach the archive.")); } else { ThrowException(handler, new SevenZipException(message + hresult.ToString(CultureInfo.InvariantCulture) + '.')); } } else { ThrowException(handler, handler.Exceptions[0]); } } } #if !WINCE && !MONO /// /// Changes the path to the 7-zip native library. /// /// The path to the 7-zip native library. public static void SetLibraryPath(string libraryPath) { SevenZipLibraryManager.SetLibraryPath(libraryPath); } #endif /// /// Gets the current library features. /// [CLSCompliant(false)] public static LibraryFeature CurrentLibraryFeatures { get { return SevenZipLibraryManager.CurrentLibraryFeatures; } } /// /// Determines whether the specified System.Object is equal to the current SevenZipBase. /// /// The System.Object to compare with the current SevenZipBase. /// true if the specified System.Object is equal to the current SevenZipBase; otherwise, false. public override bool Equals(object obj) { var inst = obj as SevenZipBase; if (inst == null) { return false; } return _uniqueID == inst._uniqueID; } /// /// Serves as a hash function for a particular type. /// /// A hash code for the current SevenZipBase. public override int GetHashCode() { return _uniqueID; } /// /// Returns a System.String that represents the current SevenZipBase. /// /// A System.String that represents the current SevenZipBase. public override string ToString() { var type = "SevenZipBase"; if (this is SevenZipExtractor) { type = "SevenZipExtractor"; } /* if (this is SevenZipCompressor) { type = "SevenZipCompressor"; } */ return string.Format("{0} [{1}]", type, _uniqueID); } } internal class CallbackBase : MarshalByRefObject { private readonly string _password; private readonly bool _reportErrors; /// /// User exceptions thrown during the requested operations, for example, in events. /// private readonly List _exceptions = new List(); #region Constructors /// /// Initializes a new instance of the CallbackBase class. /// protected CallbackBase() { _password = ""; _reportErrors = true; } /// /// Initializes a new instance of the CallbackBase class. /// /// The archive password. protected CallbackBase(string password) { if (String.IsNullOrEmpty(password)) { throw new SevenZipException("Empty password was specified."); } _password = password; _reportErrors = true; } #endregion /// /// Gets or sets the archive password /// public string Password { get { return _password; } } /// /// Gets or sets the value indicating whether the current procedure was cancelled. /// public bool Canceled { get; set; } /// /// Gets or sets throw exceptions on archive errors flag /// public bool ReportErrors { get { return _reportErrors; } } /// /// Gets the user exceptions thrown during the requested operations, for example, in events. /// public ReadOnlyCollection Exceptions { get { return new ReadOnlyCollection(_exceptions); } } public void AddException(Exception e) { _exceptions.Add(e); } public void ClearExceptions() { _exceptions.Clear(); } public bool HasExceptions { get { return _exceptions.Count > 0; } } /// /// Throws the specified exception when is able to. /// /// The exception to throw. /// The handler responsible for the exception. public bool ThrowException(CallbackBase handler, params Exception[] e) { if (_reportErrors && (handler == null || !handler.Canceled)) { throw e[0]; } return false; } /// /// Throws the first exception in the list if any exists. /// /// True means no exceptions. public bool ThrowException() { if (HasExceptions && _reportErrors) { throw _exceptions[0]; } return true; } public void ThrowUserException() { if (HasExceptions) { throw new SevenZipException(SevenZipException.USER_EXCEPTION_MESSAGE); } } } /// /// Struct for storing information about files in the 7-zip archive. /// public struct ArchiveFileInfo { /// /// Gets or sets index of the file in the archive file table. /// [CLSCompliant(false)] public int Index { get; set; } /// /// Gets or sets file name /// public string FileName { get; set; } /// /// Gets or sets the file last write time. /// public DateTime LastWriteTime { get; set; } /// /// Gets or sets the file creation time. /// public DateTime CreationTime { get; set; } /// /// Gets or sets the file creation time. /// public DateTime LastAccessTime { get; set; } /// /// Gets or sets size of the file (unpacked). /// [CLSCompliant(false)] public ulong Size { get; set; } /// /// Gets or sets CRC checksum of the file. /// [CLSCompliant(false)] public uint Crc { get; set; } /// /// Gets or sets file attributes. /// [CLSCompliant(false)] public uint Attributes { get; set; } /// /// Gets or sets being a directory. /// public bool IsDirectory { get; set; } /// /// Gets or sets being encrypted. /// public bool Encrypted { get; set; } /// /// Gets or sets comment for the file. /// public string Comment { get; set; } /// /// Determines whether the specified System.Object is equal to the current ArchiveFileInfo. /// /// The System.Object to compare with the current ArchiveFileInfo. /// true if the specified System.Object is equal to the current ArchiveFileInfo; otherwise, false. public override bool Equals(object obj) { return (obj is ArchiveFileInfo) ? Equals((ArchiveFileInfo)obj) : false; } /// /// Determines whether the specified ArchiveFileInfo is equal to the current ArchiveFileInfo. /// /// The ArchiveFileInfo to compare with the current ArchiveFileInfo. /// true if the specified ArchiveFileInfo is equal to the current ArchiveFileInfo; otherwise, false. public bool Equals(ArchiveFileInfo afi) { return afi.Index == Index && afi.FileName == FileName; } /// /// Serves as a hash function for a particular type. /// /// A hash code for the current ArchiveFileInfo. public override int GetHashCode() { return FileName.GetHashCode() ^ Index; } /// /// Returns a System.String that represents the current ArchiveFileInfo. /// /// A System.String that represents the current ArchiveFileInfo. public override string ToString() { return "[" + Index.ToString(CultureInfo.CurrentCulture) + "] " + FileName; } /// /// Determines whether the specified ArchiveFileInfo instances are considered equal. /// /// The first ArchiveFileInfo to compare. /// The second ArchiveFileInfo to compare. /// true if the specified ArchiveFileInfo instances are considered equal; otherwise, false. public static bool operator ==(ArchiveFileInfo afi1, ArchiveFileInfo afi2) { return afi1.Equals(afi2); } /// /// Determines whether the specified ArchiveFileInfo instances are not considered equal. /// /// The first ArchiveFileInfo to compare. /// The second ArchiveFileInfo to compare. /// true if the specified ArchiveFileInfo instances are not considered equal; otherwise, false. public static bool operator !=(ArchiveFileInfo afi1, ArchiveFileInfo afi2) { return !afi1.Equals(afi2); } } /// /// Archive property struct. /// public struct ArchiveProperty { /// /// Gets the name of the archive property. /// public string Name { get; internal set; } /// /// Gets the value of the archive property. /// public object Value { get; internal set; } /// /// Determines whether the specified System.Object is equal to the current ArchiveProperty. /// /// The System.Object to compare with the current ArchiveProperty. /// true if the specified System.Object is equal to the current ArchiveProperty; otherwise, false. public override bool Equals(object obj) { return (obj is ArchiveProperty) ? Equals((ArchiveProperty)obj) : false; } /// /// Determines whether the specified ArchiveProperty is equal to the current ArchiveProperty. /// /// The ArchiveProperty to compare with the current ArchiveProperty. /// true if the specified ArchiveProperty is equal to the current ArchiveProperty; otherwise, false. public bool Equals(ArchiveProperty afi) { return afi.Name == Name && afi.Value == Value; } /// /// Serves as a hash function for a particular type. /// /// A hash code for the current ArchiveProperty. public override int GetHashCode() { return Name.GetHashCode() ^ Value.GetHashCode(); } /// /// Returns a System.String that represents the current ArchiveProperty. /// /// A System.String that represents the current ArchiveProperty. public override string ToString() { return Name + " = " + Value; } /// /// Determines whether the specified ArchiveProperty instances are considered equal. /// /// The first ArchiveProperty to compare. /// The second ArchiveProperty to compare. /// true if the specified ArchiveProperty instances are considered equal; otherwise, false. public static bool operator ==(ArchiveProperty afi1, ArchiveProperty afi2) { return afi1.Equals(afi2); } /// /// Determines whether the specified ArchiveProperty instances are not considered equal. /// /// The first ArchiveProperty to compare. /// The second ArchiveProperty to compare. /// true if the specified ArchiveProperty instances are not considered equal; otherwise, false. public static bool operator !=(ArchiveProperty afi1, ArchiveProperty afi2) { return !afi1.Equals(afi2); } } #if COMPRESS /// /// Archive compression mode. /// public enum CompressionMode { /// /// Create a new archive; overwrite the existing one. /// Create, /// /// Add data to the archive. /// Append, } internal enum InternalCompressionMode { /// /// Create a new archive; overwrite the existing one. /// Create, /// /// Add data to the archive. /// Append, /// /// Modify archive data. /// Modify } /// /// Zip encryption method enum. /// public enum ZipEncryptionMethod { /// /// ZipCrypto encryption method. /// ZipCrypto, /// /// AES 128 bit encryption method. /// Aes128, /// /// AES 192 bit encryption method. /// Aes192, /// /// AES 256 bit encryption method. /// Aes256 } /// /// Archive update data for UpdateCallback. /// internal struct UpdateData { public uint FilesCount; public InternalCompressionMode Mode; public Dictionary FileNamesToModify { get; set; } public List ArchiveFileData { get; set; } } #endif #endif }