diff --git a/BizHawk.Client.Common/7z/ArchiveOpenCallback.cs b/BizHawk.Client.Common/7z/ArchiveOpenCallback.cs index d870be30bb..080ce8c6da 100644 --- a/BizHawk.Client.Common/7z/ArchiveOpenCallback.cs +++ b/BizHawk.Client.Common/7z/ArchiveOpenCallback.cs @@ -35,7 +35,18 @@ namespace SevenZip private FileInfo _fileInfo; private Dictionary _wrappers = new Dictionary(); - public readonly List VolumeFileNames = new List(); + private readonly List _volumeFileNames = new List(); + + /// + /// Gets the list of volume file names. + /// + public IList VolumeFileNames + { + get + { + return _volumeFileNames; + } + } /// /// Performs the common initialization. @@ -46,7 +57,21 @@ namespace SevenZip if (!String.IsNullOrEmpty(fileName)) { _fileInfo = new FileInfo(fileName); - VolumeFileNames.Add(fileName); + _volumeFileNames.Add(fileName); + if (fileName.EndsWith("001")) + { + int index = 2; + var baseName = fileName.Substring(0, fileName.Length - 3); + var volName = baseName + (index > 99 ? index.ToString() : + index > 9 ? "0" + index : "00" + index); + while (File.Exists(volName)) + { + _volumeFileNames.Add(volName); + index++; + volName = baseName + (index > 99 ? index.ToString() : + index > 9 ? "0" + index : "00" + index); + } + } } } @@ -127,7 +152,7 @@ namespace SevenZip return 1; } } - VolumeFileNames.Add(name); + _volumeFileNames.Add(name); if (_wrappers.ContainsKey(name)) { inStream = _wrappers[name]; diff --git a/BizHawk.Client.Common/7z/ArchiveUpdateCallback.cs b/BizHawk.Client.Common/7z/ArchiveUpdateCallback.cs index 9e8be21990..a9f838e70b 100644 --- a/BizHawk.Client.Common/7z/ArchiveUpdateCallback.cs +++ b/BizHawk.Client.Common/7z/ArchiveUpdateCallback.cs @@ -780,7 +780,7 @@ namespace SevenZip private void IntEventArgsHandler(object sender, IntEventArgs e) { - lock (this) + lock (_files) { var pold = (byte) ((_bytesWrittenOld*100)/_bytesCount); _bytesWritten += e.Value; diff --git a/BizHawk.Client.Common/7z/Common.cs b/BizHawk.Client.Common/7z/Common.cs index dd88cfbf2c..a9ff2deb9d 100644 --- a/BizHawk.Client.Common/7z/Common.cs +++ b/BizHawk.Client.Common/7z/Common.cs @@ -56,7 +56,7 @@ namespace SevenZip /// /// SevenZip Extractor/Compressor base class. Implements Password string, ReportErrors flag. /// - public class SevenZipBase : MarshalByRefObject + public abstract class SevenZipBase : MarshalByRefObject { private readonly string _password; private readonly bool _reportErrors; @@ -74,18 +74,18 @@ namespace SevenZip /// AsyncCallback implementation used in asynchronous invocations. /// /// IAsyncResult instance. - internal static void AsyncCallbackMethod(IAsyncResult ar) + internal static void AsyncCallbackMethod(IAsyncResult ar) { - var result = (AsyncResult) 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 +DispatcherPriority priority = DispatcherPriority.Normal #endif - ) +) { #if !DOTNET20 Dispatcher = Dispatcher.CurrentDispatcher; @@ -96,7 +96,7 @@ namespace SevenZip NeedsToBeRecreated = true; } - internal void ReleaseContext() + virtual internal void ReleaseContext() { #if !DOTNET20 Dispatcher = null; @@ -104,11 +104,12 @@ namespace SevenZip 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 + internal void OnEvent(EventHandler handler, T e, bool synchronous) where T : EventArgs { try { @@ -125,7 +126,7 @@ namespace SevenZip } if ( #if !DOTNET20 - Dispatcher == null +Dispatcher == null #else Context == null #endif @@ -221,6 +222,9 @@ namespace SevenZip private static int GetUniqueID() { + lock(Identificators) + { + int id; var rnd = new Random(DateTime.Now.Millisecond); do @@ -230,6 +234,7 @@ namespace SevenZip while (Identificators.Contains(id)); Identificators.Add(id); return id; + } } #region Constructors @@ -264,7 +269,11 @@ namespace SevenZip /// ~SevenZipBase() { - Identificators.Remove(_uniqueID); + // This lock probably isn't necessary but just in case... + lock (Identificators) + { + Identificators.Remove(_uniqueID); + } } /// @@ -330,7 +339,7 @@ namespace SevenZip throw e[0]; } return false; - } + } internal void ThrowUserException() { @@ -348,7 +357,7 @@ namespace SevenZip /// The class responsible for the callback. internal void CheckedExecute(int hresult, string message, CallbackBase handler) { - if (hresult != (int) OperationResult.Ok || handler.HasExceptions) + if (hresult != (int)OperationResult.Ok || handler.HasExceptions) { if (!handler.HasExceptions) { @@ -386,6 +395,7 @@ namespace SevenZip /// /// Gets the current library features. /// + [CLSCompliant(false)] public static LibraryFeature CurrentLibraryFeatures { get @@ -434,7 +444,7 @@ namespace SevenZip type = "SevenZipCompressor"; } return string.Format("{0} [{1}]", type, _uniqueID); - } + } } internal class CallbackBase : MarshalByRefObject @@ -571,6 +581,7 @@ namespace SevenZip /// /// Gets or sets index of the file in the archive file table. /// + [CLSCompliant(false)] public int Index { get; set; } /// @@ -596,16 +607,19 @@ namespace SevenZip /// /// 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; } /// @@ -630,7 +644,7 @@ namespace SevenZip /// 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; + return (obj is ArchiveFileInfo) ? Equals((ArchiveFileInfo)obj) : false; } /// @@ -706,7 +720,7 @@ namespace SevenZip /// 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; + return (obj is ArchiveProperty) ? Equals((ArchiveProperty)obj) : false; } /// diff --git a/BizHawk.Client.Common/7z/EventArgs.cs b/BizHawk.Client.Common/7z/EventArgs.cs index 8f3928b295..82890ee8b4 100644 --- a/BizHawk.Client.Common/7z/EventArgs.cs +++ b/BizHawk.Client.Common/7z/EventArgs.cs @@ -19,6 +19,17 @@ using System.IO; namespace SevenZip { + /// + /// The definition of the interface which supports the cancellation of a process. + /// + public interface ICancellable + { + /// + /// Gets or sets whether to stop the current archive operation. + /// + bool Cancel { get; set; } + } + /// /// EventArgs for storing PercentDone property. /// @@ -50,12 +61,7 @@ namespace SevenZip { return _percentDone; } - } - - /// - /// Gets or sets whether to stop the current archive operation. - /// - public bool Cancel { get; set; } + } /// /// Converts a [0, 1] rate to its percent equivalent. @@ -107,7 +113,7 @@ namespace SevenZip /// /// EventArgs used to report the file information which is going to be packed. /// - public sealed class FileInfoEventArgs : PercentDoneEventArgs + public sealed class FileInfoEventArgs : PercentDoneEventArgs, ICancellable { private readonly ArchiveFileInfo _fileInfo; @@ -122,6 +128,11 @@ namespace SevenZip _fileInfo = fileInfo; } + /// + /// Gets or sets whether to stop the current archive operation. + /// + public bool Cancel { get; set; } + /// /// Gets the corresponding FileInfo to the event. /// @@ -145,6 +156,7 @@ namespace SevenZip /// Initializes a new instance of the OpenEventArgs class /// /// Size of unpacked archive data + [CLSCompliant(false)] public OpenEventArgs(ulong totalSize) { _totalSize = totalSize; @@ -153,6 +165,7 @@ namespace SevenZip /// /// Gets the size of unpacked archive data /// + [CLSCompliant(false)] public ulong TotalSize { get @@ -193,7 +206,7 @@ namespace SevenZip /// /// EventArgs class which stores the file name. /// - public sealed class FileNameEventArgs : PercentDoneEventArgs + public sealed class FileNameEventArgs : PercentDoneEventArgs, ICancellable { private readonly string _fileName; @@ -208,6 +221,11 @@ namespace SevenZip _fileName = fileName; } + /// + /// Gets or sets whether to stop the current archive operation. + /// + public bool Cancel { get; set; } + /// /// Gets the file name. /// diff --git a/BizHawk.Client.Common/7z/LibraryFeature.cs b/BizHawk.Client.Common/7z/LibraryFeature.cs index fdc1d5a3bf..5085b6b170 100644 --- a/BizHawk.Client.Common/7z/LibraryFeature.cs +++ b/BizHawk.Client.Common/7z/LibraryFeature.cs @@ -22,6 +22,7 @@ namespace SevenZip /// The set of features supported by the library. /// [Flags] + [CLSCompliant(false)] public enum LibraryFeature : uint { /// diff --git a/BizHawk.Client.Common/7z/LibraryManager.cs b/BizHawk.Client.Common/7z/LibraryManager.cs index caa398dc1c..7cd7fcb606 100644 --- a/BizHawk.Client.Common/7z/LibraryManager.cs +++ b/BizHawk.Client.Common/7z/LibraryManager.cs @@ -39,9 +39,18 @@ namespace SevenZip /// 7-zip library low-level wrapper. /// internal static class SevenZipLibraryManager - { -#if !WINCE && !MONO + { /// + /// Synchronization root for all locking. + /// + private static readonly object _syncRoot = new object(); + +#if !WINCE && !MONO + + //zero 07-jul-2014 - no sense for this industrial strength enterprise bullshit. lets just hack it to our needs. + //NOTE - I think we hacked this originally.. it was this way from the initial commit, perhaps it had already been modified for our use + + /// /// Path to the 7-zip dll. /// /// 7zxa.dll supports only decoding from .7z archives. @@ -52,7 +61,8 @@ namespace SevenZip /// 7z.dll (from the 7-zip distribution) supports every InArchiveFormat for encoding and decoding. /// //private static string _libraryFileName = ConfigurationManager.AppSettings["7zLocation"] ?? Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "7z.dll"); - private static string _libraryFileName = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "7z.dll"); + private static string _libraryFileName = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "7z.dll"); + #endif #if WINCE private static string _libraryFileName = @@ -68,9 +78,9 @@ namespace SevenZip /// private static LibraryFeature? _features; - private static Dictionary> _inArchives; + private static Dictionary> _inArchives; #if COMPRESS - private static Dictionary> _outArchives; + private static Dictionary> _outArchives; #endif private static int _totalUsers; @@ -120,6 +130,8 @@ namespace SevenZip /// Archive format public static void LoadLibrary(object user, Enum format) { + lock (_syncRoot) + { if (_inArchives == null #if COMPRESS || _outArchives == null @@ -149,6 +161,7 @@ namespace SevenZip throw new SevenZipLibraryException("library is invalid."); } } +} #endif if (format is InArchiveFormat) { @@ -164,6 +177,7 @@ namespace SevenZip #endif throw new ArgumentException( "Enum " + format + " is not a valid archive format attribute!"); + } /*/// @@ -192,30 +206,32 @@ namespace SevenZip { get { - if (!_modifyCapabale.HasValue) + lock (_syncRoot) { + if (!_modifyCapabale.HasValue) + { #if !WINCE && !MONO - FileVersionInfo dllVersionInfo = FileVersionInfo.GetVersionInfo(_libraryFileName); - _modifyCapabale = dllVersionInfo.FileMajorPart >= 9; + FileVersionInfo dllVersionInfo = FileVersionInfo.GetVersionInfo(_libraryFileName); + _modifyCapabale = dllVersionInfo.FileMajorPart >= 9; #else _modifyCapabale = true; -#endif +#endif + } + return _modifyCapabale.Value; } - return _modifyCapabale.Value; } } - //static readonly string Namespace = Assembly.GetExecutingAssembly().GetManifestResourceNames()[0].Split('.')[0]; static readonly string Namespace = "BizHawk"; //Remove dirty hack above private static string GetResourceString(string str) - { - return Namespace + ".arch." + str; + { + return Namespace + ".arch." + str; } private static bool ExtractionBenchmark(string archiveFileName, Stream outStream, ref LibraryFeature? features, LibraryFeature testedFeature) - { + { var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream( GetResourceString(archiveFileName)); try @@ -225,7 +241,7 @@ namespace SevenZip extr.ExtractFile(0, outStream); } } - catch(Exception) + catch (Exception) { return false; } @@ -239,7 +255,7 @@ namespace SevenZip { try { - var compr = new SevenZipCompressor {ArchiveFormat = format, CompressionMethod = method}; + var compr = new SevenZipCompressor { ArchiveFormat = format, CompressionMethod = method }; compr.CompressStream(inStream, outStream); } catch (Exception) @@ -254,93 +270,96 @@ namespace SevenZip { get { - if (_features != null && _features.HasValue) + lock (_syncRoot) { - return _features.Value; - } - _features = LibraryFeature.None; - #region Benchmark - #region Extraction features - using (var outStream = new MemoryStream()) - { - ExtractionBenchmark("Test.lzma.7z", outStream, ref _features, LibraryFeature.Extract7z); - ExtractionBenchmark("Test.lzma2.7z", outStream, ref _features, LibraryFeature.Extract7zLZMA2); - int i = 0; - if (ExtractionBenchmark("Test.bzip2.7z", outStream, ref _features, _features.Value)) + if (_features != null && _features.HasValue) { - i++; + return _features.Value; } - if (ExtractionBenchmark("Test.ppmd.7z", outStream, ref _features, _features.Value)) - { - i++; - if (i == 2 && (_features & LibraryFeature.Extract7z) != 0 && - (_features & LibraryFeature.Extract7zLZMA2) != 0) - { - _features |= LibraryFeature.Extract7zAll; - } - } - ExtractionBenchmark("Test.rar", outStream, ref _features, LibraryFeature.ExtractRar); - ExtractionBenchmark("Test.tar", outStream, ref _features, LibraryFeature.ExtractTar); - ExtractionBenchmark("Test.txt.bz2", outStream, ref _features, LibraryFeature.ExtractBzip2); - ExtractionBenchmark("Test.txt.gz", outStream, ref _features, LibraryFeature.ExtractGzip); - ExtractionBenchmark("Test.txt.xz", outStream, ref _features, LibraryFeature.ExtractXz); - ExtractionBenchmark("Test.zip", outStream, ref _features, LibraryFeature.ExtractZip); - } - #endregion - #region Compression features - using (var inStream = new MemoryStream()) - { - inStream.Write(Encoding.UTF8.GetBytes("Test"), 0, 4); + _features = LibraryFeature.None; + #region Benchmark + #region Extraction features using (var outStream = new MemoryStream()) { - CompressionBenchmark(inStream, outStream, - OutArchiveFormat.SevenZip, CompressionMethod.Lzma, - ref _features, LibraryFeature.Compress7z); - CompressionBenchmark(inStream, outStream, - OutArchiveFormat.SevenZip, CompressionMethod.Lzma2, - ref _features, LibraryFeature.Compress7zLZMA2); + ExtractionBenchmark("Test.lzma.7z", outStream, ref _features, LibraryFeature.Extract7z); + ExtractionBenchmark("Test.lzma2.7z", outStream, ref _features, LibraryFeature.Extract7zLZMA2); int i = 0; - if (CompressionBenchmark(inStream, outStream, - OutArchiveFormat.SevenZip, CompressionMethod.BZip2, - ref _features, _features.Value)) + if (ExtractionBenchmark("Test.bzip2.7z", outStream, ref _features, _features.Value)) { i++; } - if (CompressionBenchmark(inStream, outStream, - OutArchiveFormat.SevenZip, CompressionMethod.Ppmd, - ref _features, _features.Value)) + if (ExtractionBenchmark("Test.ppmd.7z", outStream, ref _features, _features.Value)) { i++; - if (i == 2 && (_features & LibraryFeature.Compress7z) != 0 && - (_features & LibraryFeature.Compress7zLZMA2) != 0) + if (i == 2 && (_features & LibraryFeature.Extract7z) != 0 && + (_features & LibraryFeature.Extract7zLZMA2) != 0) { - _features |= LibraryFeature.Compress7zAll; + _features |= LibraryFeature.Extract7zAll; } } - CompressionBenchmark(inStream, outStream, - OutArchiveFormat.Zip, CompressionMethod.Default, - ref _features, LibraryFeature.CompressZip); - CompressionBenchmark(inStream, outStream, - OutArchiveFormat.BZip2, CompressionMethod.Default, - ref _features, LibraryFeature.CompressBzip2); - CompressionBenchmark(inStream, outStream, - OutArchiveFormat.GZip, CompressionMethod.Default, - ref _features, LibraryFeature.CompressGzip); - CompressionBenchmark(inStream, outStream, - OutArchiveFormat.Tar, CompressionMethod.Default, - ref _features, LibraryFeature.CompressTar); - CompressionBenchmark(inStream, outStream, - OutArchiveFormat.XZ, CompressionMethod.Default, - ref _features, LibraryFeature.CompressXz); + ExtractionBenchmark("Test.rar", outStream, ref _features, LibraryFeature.ExtractRar); + ExtractionBenchmark("Test.tar", outStream, ref _features, LibraryFeature.ExtractTar); + ExtractionBenchmark("Test.txt.bz2", outStream, ref _features, LibraryFeature.ExtractBzip2); + ExtractionBenchmark("Test.txt.gz", outStream, ref _features, LibraryFeature.ExtractGzip); + ExtractionBenchmark("Test.txt.xz", outStream, ref _features, LibraryFeature.ExtractXz); + ExtractionBenchmark("Test.zip", outStream, ref _features, LibraryFeature.ExtractZip); } + #endregion + #region Compression features + using (var inStream = new MemoryStream()) + { + inStream.Write(Encoding.UTF8.GetBytes("Test"), 0, 4); + using (var outStream = new MemoryStream()) + { + CompressionBenchmark(inStream, outStream, + OutArchiveFormat.SevenZip, CompressionMethod.Lzma, + ref _features, LibraryFeature.Compress7z); + CompressionBenchmark(inStream, outStream, + OutArchiveFormat.SevenZip, CompressionMethod.Lzma2, + ref _features, LibraryFeature.Compress7zLZMA2); + int i = 0; + if (CompressionBenchmark(inStream, outStream, + OutArchiveFormat.SevenZip, CompressionMethod.BZip2, + ref _features, _features.Value)) + { + i++; + } + if (CompressionBenchmark(inStream, outStream, + OutArchiveFormat.SevenZip, CompressionMethod.Ppmd, + ref _features, _features.Value)) + { + i++; + if (i == 2 && (_features & LibraryFeature.Compress7z) != 0 && + (_features & LibraryFeature.Compress7zLZMA2) != 0) + { + _features |= LibraryFeature.Compress7zAll; + } + } + CompressionBenchmark(inStream, outStream, + OutArchiveFormat.Zip, CompressionMethod.Default, + ref _features, LibraryFeature.CompressZip); + CompressionBenchmark(inStream, outStream, + OutArchiveFormat.BZip2, CompressionMethod.Default, + ref _features, LibraryFeature.CompressBzip2); + CompressionBenchmark(inStream, outStream, + OutArchiveFormat.GZip, CompressionMethod.Default, + ref _features, LibraryFeature.CompressGzip); + CompressionBenchmark(inStream, outStream, + OutArchiveFormat.Tar, CompressionMethod.Default, + ref _features, LibraryFeature.CompressTar); + CompressionBenchmark(inStream, outStream, + OutArchiveFormat.XZ, CompressionMethod.Default, + ref _features, LibraryFeature.CompressXz); + } + } + #endregion + #endregion + if (ModifyCapable && (_features.Value & LibraryFeature.Compress7z) != 0) + { + _features |= LibraryFeature.Modify; + } + return _features.Value; } - #endregion - #endregion - if (ModifyCapable && (_features.Value & LibraryFeature.Compress7z) != 0) - { - _features |= LibraryFeature.Modify; - } - return _features.Value; } } @@ -355,7 +374,9 @@ namespace SevenZip var sp = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode); sp.Demand(); #endif - if (_modulePtr != IntPtr.Zero) + lock (_syncRoot) + { + if (_modulePtr != IntPtr.Zero) { if (format is InArchiveFormat) { @@ -417,6 +438,7 @@ namespace SevenZip } } } + } } /// @@ -426,10 +448,8 @@ namespace SevenZip /// Archive format user. public static IInArchive InArchive(InArchiveFormat format, object user) { -#if !WINCE && !MONO - lock (_libraryFileName) + lock (_syncRoot) { -#endif if (_inArchives[user][format] == null) { #if !WINCE && !MONO @@ -453,7 +473,7 @@ namespace SevenZip throw new SevenZipLibraryException(); } #endif - object result; + object result; Guid interfaceId = #if !WINCE && !MONO typeof(IInArchive).GUID; @@ -478,10 +498,10 @@ namespace SevenZip InitUserInFormat(user, format); _inArchives[user][format] = result as IInArchive; } + return _inArchives[user][format]; #if !WINCE && !MONO } #endif - return _inArchives[user][format]; } #if COMPRESS @@ -492,10 +512,8 @@ namespace SevenZip /// Archive format user. public static IOutArchive OutArchive(OutArchiveFormat format, object user) { -#if !WINCE && !MONO - lock (_libraryFileName) + lock (_syncRoot) { -#endif if (_outArchives[user][format] == null) { #if !WINCE && !MONO @@ -539,10 +557,11 @@ namespace SevenZip InitUserOutFormat(user, format); _outArchives[user][format] = result as IOutArchive; } + return _outArchives[user][format]; #if !WINCE && !MONO } #endif - return _outArchives[user][format]; + } #endif #if !WINCE && !MONO diff --git a/BizHawk.Client.Common/7z/SevenZipCompressor.cs b/BizHawk.Client.Common/7z/SevenZipCompressor.cs index 2227150f97..fcb2ea7307 100644 --- a/BizHawk.Client.Common/7z/SevenZipCompressor.cs +++ b/BizHawk.Client.Common/7z/SevenZipCompressor.cs @@ -37,8 +37,12 @@ namespace SevenZip { #if COMPRESS /// - /// Class for packing files into 7-zip archives + /// Class to pack data into archives supported by 7-Zip. /// + /// + /// var compr = new SevenZipCompressor(); + /// compr.CompressDirectory(@"C:\Dir", @"C:\Archive.7z"); + /// public sealed partial class SevenZipCompressor #if UNMANAGED : SevenZipBase @@ -105,7 +109,7 @@ namespace SevenZip public bool FastCompression { get; set; } #endregion #endif - private static int _lzmaDictionarySize = 1 << 22; + private static volatile int _lzmaDictionarySize = 1 << 22; #if UNMANAGED @@ -125,7 +129,7 @@ namespace SevenZip /// Initializes a new instance of the SevenZipCompressor class. /// public SevenZipCompressor() - { + { try { #if !WINCE @@ -143,7 +147,7 @@ namespace SevenZip throw new SevenZipCompressionFailedException( "Path.GetTempPath() threw a System.Security.SecurityException. You must call SevenZipCompressor constructor overload with your own temporary path."); } - CommonInit(); + CommonInit(); } /// @@ -191,7 +195,7 @@ namespace SevenZip using (ArchiveOpenCallback openCallback = GetArchiveOpenCallback()) { ulong checkPos = 1 << 15; - if (inArchive.Open(inArchiveStream, ref checkPos, openCallback) != (int) OperationResult.Ok) + if (inArchive.Open(inArchiveStream, ref checkPos, openCallback) != (int)OperationResult.Ok) { if ( !ThrowException(null, new SevenZipArchiveException("Can not update the archive: Open() failed."))) @@ -201,7 +205,7 @@ namespace SevenZip } _oldFilesCount = inArchive.GetNumberOfItems(); } - return (IOutArchive) inArchive; + return (IOutArchive)inArchive; } /// @@ -248,9 +252,9 @@ namespace SevenZip break; default: ISetProperties setter = CompressionMode == CompressionMode.Create && _updateData.FileNamesToModify == null - ? (ISetProperties) SevenZipLibraryManager.OutArchive( + ? (ISetProperties)SevenZipLibraryManager.OutArchive( _archiveFormat, this) - : (ISetProperties) SevenZipLibraryManager.InArchive( + : (ISetProperties)SevenZipLibraryManager.InArchive( Formats.InForOutFormats[_archiveFormat], this); if (setter == null) { @@ -312,10 +316,10 @@ namespace SevenZip : Marshal.StringToBSTR("0")); values.Add(new PropVariant()); var pv = new PropVariant - { - VarType = VarEnum.VT_BSTR, - Value = Marshal.StringToBSTR(Formats.MethodNames[_compressionMethod]) - }; + { + VarType = VarEnum.VT_BSTR, + Value = Marshal.StringToBSTR(Formats.MethodNames[_compressionMethod]) + }; values.Add(pv); foreach (var pair in CustomParameters) { @@ -372,7 +376,7 @@ namespace SevenZip !SwitchIsInCustomParameters("he")) { names.Add(Marshal.StringToBSTR("he")); - var tmp = new PropVariant {VarType = VarEnum.VT_BSTR, Value = Marshal.StringToBSTR("on")}; + var tmp = new PropVariant { VarType = VarEnum.VT_BSTR, Value = Marshal.StringToBSTR("on") }; values.Add(tmp); } @@ -389,7 +393,7 @@ namespace SevenZip VarType = VarEnum.VT_BSTR, Value = Marshal.StringToBSTR( #if !WINCE - Enum.GetName(typeof (ZipEncryptionMethod), ZipEncryptionMethod)) +Enum.GetName(typeof(ZipEncryptionMethod), ZipEncryptionMethod)) #else OpenNETCF.Enum2.GetName(typeof (ZipEncryptionMethod), ZipEncryptionMethod)) #endif @@ -579,7 +583,8 @@ namespace SevenZip { string[] splittedAfn = f.Substring(commonRootLength).Split(Path.DirectorySeparatorChar); string cfn = commonRoot; - foreach (string t in splittedAfn) { + foreach (string t in splittedAfn) + { cfn += Path.DirectorySeparatorChar + t; if (!fns.Contains(cfn)) { @@ -630,10 +635,10 @@ namespace SevenZip { try { - using (fi.OpenWrite()) {} + using (fi.OpenWrite()) { } files.Add(fi.FullName); } - catch (IOException) {} + catch (IOException) { } } } foreach (DirectoryInfo cdi in di.GetDirectories()) @@ -660,7 +665,7 @@ namespace SevenZip auc.Compressing += CompressingEventProxy; auc.FileCompressionFinished += FileCompressionFinishedEventProxy; auc.DefaultItemName = DefaultItemName; - auc.FastCompression = FastCompression; + auc.FastCompression = FastCompression; } private float GetDictionarySize() @@ -825,7 +830,7 @@ namespace SevenZip { if (_updateData.FileNamesToModify == null) { - var updateData = new UpdateData {Mode = (InternalCompressionMode) ((int) CompressionMode)}; + var updateData = new UpdateData { Mode = (InternalCompressionMode)((int)CompressionMode) }; switch (CompressionMode) { case CompressionMode.Create: @@ -986,7 +991,7 @@ namespace SevenZip { _compressionMethod = !MethodIsValid(value) ? CompressionMethod.Default : value; } - } + } /// /// Gets or sets the size in bytes of an archive volume (0 for no volumes). @@ -1094,7 +1099,7 @@ namespace SevenZip _archiveName = archiveName; using (FileStream fs = GetArchiveFileStream(archiveName)) { - if (fs == null) + if (fs == null && _volumeSize == 0) { return; } @@ -1177,7 +1182,7 @@ namespace SevenZip if (files != null) //ReSharper CheckedExecute( outArchive.UpdateItems( - sequentialArchiveStream, (uint) files.Length + _oldFilesCount, auc), + sequentialArchiveStream, (uint)files.Length + _oldFilesCount, auc), SevenZipCompressionFailedException.DEFAULT_MESSAGE, auc); } finally @@ -1379,7 +1384,7 @@ namespace SevenZip CompressDirectory(directory, fs, password, searchPattern, recursion); } FinalizeUpdate(); - } + } #if !CS4 /// @@ -1482,7 +1487,7 @@ namespace SevenZip CompressFileDictionary(fileDictionary, archiveStream, ""); } #endif - + #if !CS4 /// /// Packs the specified file dictionary. @@ -1509,15 +1514,15 @@ namespace SevenZip _archiveName = archiveName; using (FileStream fs = GetArchiveFileStream(archiveName)) { - if (fs == null) + if (fs == null && _volumeSize == 0) { return; } CompressFileDictionary(fileDictionary, fs, password); } FinalizeUpdate(); - } - + } + #if !CS4 /// /// Packs the specified file dictionary. @@ -1593,7 +1598,7 @@ namespace SevenZip CompressStreamDictionary(streamDictionary, archiveStream, ""); } #endif - + #if !CS4 /// /// Packs the specified stream dictionary. @@ -1620,15 +1625,15 @@ namespace SevenZip _archiveName = archiveName; using (FileStream fs = GetArchiveFileStream(archiveName)) { - if (fs == null) + if (fs == null && _volumeSize == 0) { return; } CompressStreamDictionary(streamDictionary, fs, password); } FinalizeUpdate(); - } - + } + #if !CS4 /// /// Packs the specified stream dictionary. @@ -1673,7 +1678,8 @@ namespace SevenZip pair => pair.Value != null && (!pair.Value.CanSeek || !pair.Value.CanRead)).Any( pair => !ThrowException(null, new ArgumentException("The specified stream dictionary contains an invalid stream corresponding to the archive entry \"" - + pair.Key + "\".", "streamDictionary")))) { + + pair.Key + "\".", "streamDictionary")))) + { return; } #else @@ -1689,7 +1695,7 @@ namespace SevenZip } } } -#endif +#endif try { ISequentialOutStream sequentialArchiveStream; @@ -1829,7 +1835,7 @@ namespace SevenZip ModifyArchive(archiveName, newFileNames, ""); } #endif - + /// /// Modifies the existing archive (renames files or deletes them). /// @@ -1927,7 +1933,7 @@ namespace SevenZip { FreeCompressionCallback(auc); } - } + } } } } @@ -1942,7 +1948,7 @@ namespace SevenZip OnEvent(CompressionFinished, EventArgs.Empty, false); } ThrowUserException(); - } + } #endregion #endregion @@ -2016,7 +2022,7 @@ namespace SevenZip long streamSize = inLength.HasValue ? inLength.Value : inStream.Length; for (int i = 0; i < 8; i++) { - outStream.WriteByte((byte) (streamSize >> (8*i))); + outStream.WriteByte((byte)(streamSize >> (8 * i))); } encoder.Code(inStream, outStream, -1, -1, new LzmaProgressCallback(streamSize, codeProgressEvent)); } @@ -2037,7 +2043,7 @@ namespace SevenZip encoder.WriteCoderProperties(outStream); long streamSize = inStream.Length; for (int i = 0; i < 8; i++) - outStream.WriteByte((byte) (streamSize >> (8*i))); + outStream.WriteByte((byte)(streamSize >> (8 * i))); encoder.Code(inStream, outStream, -1, -1, null); return outStream.ToArray(); } diff --git a/BizHawk.Client.Common/7z/SevenZipCompressorAsynchronous.cs b/BizHawk.Client.Common/7z/SevenZipCompressorAsynchronous.cs index 11af46cf73..d6efc582ce 100644 --- a/BizHawk.Client.Common/7z/SevenZipCompressorAsynchronous.cs +++ b/BizHawk.Client.Common/7z/SevenZipCompressorAsynchronous.cs @@ -1,4 +1,20 @@ -namespace SevenZip +/* 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 . +*/ + +namespace SevenZip { using System.Collections.Generic; using System.IO; diff --git a/BizHawk.Client.Common/7z/SevenZipExtractor.cs b/BizHawk.Client.Common/7z/SevenZipExtractor.cs index 90562496b9..36d275bf54 100644 --- a/BizHawk.Client.Common/7z/SevenZipExtractor.cs +++ b/BizHawk.Client.Common/7z/SevenZipExtractor.cs @@ -33,8 +33,14 @@ using SevenZip.Mono.COM; namespace SevenZip { /// - /// Class for extracting and getting information about 7-zip archives + /// Class to unpack data from archives supported by 7-Zip. /// + /// + /// using (var extr = new SevenZipExtractor(@"C:\Test.7z")) + /// { + /// extr.ExtractArchive(@"C:\TestDirectory"); + /// } + /// public sealed partial class SevenZipExtractor #if UNMANAGED : SevenZipBase, IDisposable @@ -54,10 +60,14 @@ namespace SevenZip private bool? _isSolid; private bool _opened; private bool _disposed; - private InArchiveFormat _format; + private InArchiveFormat _format = (InArchiveFormat)(-1); private ReadOnlyCollection _archiveFileInfoCollection; private ReadOnlyCollection _archiveProperties; - private ReadOnlyCollection _volumeFileNames; + private ReadOnlyCollection _volumeFileNames; + /// + /// This is used to lock possible Dispose() calls. + /// + private bool _asynchronousDisposeLock; #region Constructors /// @@ -67,8 +77,11 @@ namespace SevenZip private void Init(string archiveFullName) { _fileName = archiveFullName; - bool isExecutable; - _format = FileChecker.CheckSignature(archiveFullName, out _offset, out isExecutable); + bool isExecutable = false; + if ((int)_format == -1) + { + _format = FileChecker.CheckSignature(archiveFullName, out _offset, out isExecutable); + } PreserveDirectoryStructure = true; SevenZipLibraryManager.LoadLibrary(this, _format); try @@ -107,8 +120,11 @@ namespace SevenZip private void Init(Stream stream) { ValidateStream(stream); - bool isExecutable; - _format = FileChecker.CheckSignature(stream, out _offset, out isExecutable); + bool isExecutable = false; + if ((int)_format == -1) + { + _format = FileChecker.CheckSignature(stream, out _offset, out isExecutable); + } PreserveDirectoryStructure = true; SevenZipLibraryManager.LoadLibrary(this, _format); try @@ -155,14 +171,41 @@ namespace SevenZip } /// - /// Initializes a new instance of SevenZipExtractor class + /// Initializes a new instance of SevenZipExtractor class. /// - /// The archive full file name + /// The stream to read the archive from. + /// Use SevenZipExtractor(string) to extract from disk, though it is not necessary. + /// Manual archive format setup. You SHOULD NOT normally specify it this way. + /// Instead, use SevenZipExtractor(Stream archiveStream), that constructor + /// automatically detects the archive format. + public SevenZipExtractor(Stream archiveStream, InArchiveFormat format) + { + _format = format; + Init(archiveStream); + } + + /// + /// Initializes a new instance of SevenZipExtractor class. + /// + /// The archive full file name. public SevenZipExtractor(string archiveFullName) { Init(archiveFullName); } + /// + /// Initializes a new instance of SevenZipExtractor class. + /// + /// The archive full file name. + /// Manual archive format setup. You SHOULD NOT normally specify it this way. + /// Instead, use SevenZipExtractor(string archiveFullName), that constructor + /// automatically detects the archive format. + public SevenZipExtractor(string archiveFullName, InArchiveFormat format) + { + _format = format; + Init(archiveFullName); + } + /// /// Initializes a new instance of SevenZipExtractor class. /// @@ -174,19 +217,48 @@ namespace SevenZip Init(archiveFullName); } + /// + /// Initializes a new instance of SevenZipExtractor class. + /// + /// The archive full file name. + /// Password for an encrypted archive. + /// Manual archive format setup. You SHOULD NOT normally specify it this way. + /// Instead, use SevenZipExtractor(string archiveFullName, string password), that constructor + /// automatically detects the archive format. + public SevenZipExtractor(string archiveFullName, string password, InArchiveFormat format) + : base(password) + { + _format = format; + Init(archiveFullName); + } + /// /// Initializes a new instance of SevenZipExtractor class. /// /// The stream to read the archive from. /// Password for an encrypted archive. /// The archive format is guessed by the signature. - public SevenZipExtractor( - Stream archiveStream, string password) + public SevenZipExtractor(Stream archiveStream, string password) : base(password) { Init(archiveStream); } + /// + /// Initializes a new instance of SevenZipExtractor class. + /// + /// The stream to read the archive from. + /// Password for an encrypted archive. + /// Manual archive format setup. You SHOULD NOT normally specify it this way. + /// Instead, use SevenZipExtractor(Stream archiveStream, string password), that constructor + /// automatically detects the archive format. + public SevenZipExtractor(Stream archiveStream, string password, InArchiveFormat format) + : base(password) + { + _format = format; + Init(archiveStream); + } + #endregion #region Properties @@ -251,17 +323,15 @@ namespace SevenZip { GetArchiveInfo(true); } - if (_isSolid != null) - { - return _isSolid.Value; - } - throw new SevenZipException("_isSolid == null"); + Debug.Assert(_isSolid != null); + return _isSolid.Value; } } /// /// Gets the number of files in the archive /// + [CLSCompliant(false)] public uint FilesCount { get @@ -271,11 +341,8 @@ namespace SevenZip { GetArchiveInfo(true); } - if (_filesCount != null) - { - return _filesCount.Value; - } - throw new SevenZipException("_filesCount == null"); + Debug.Assert(_filesCount != null); + return _filesCount.Value; } } @@ -292,7 +359,7 @@ namespace SevenZip } /// - /// Gets or sets the value indicatin whether to preserve the directory structure of extracted files. + /// Gets or sets the value indicating whether to preserve the directory structure of extracted files. /// public bool PreserveDirectoryStructure { get; set; } #endregion @@ -343,7 +410,8 @@ namespace SevenZip } else { - if (!_fileName.EndsWith(".001", StringComparison.OrdinalIgnoreCase)) + if (!_fileName.EndsWith(".001", StringComparison.OrdinalIgnoreCase) + || (_volumeFileNames.Count == 1)) { _archiveStream = new InStreamWrapper( new ArchiveEmulationStreamProxy(new FileStream( @@ -692,6 +760,10 @@ namespace SevenZip _archiveFileData = null; _archiveProperties = null; _archiveFileInfoCollection = null; + if (_inStream != null) + { + _inStream.Dispose(); + } _inStream = null; if (_openCallback != null) { @@ -726,6 +798,11 @@ namespace SevenZip /// public void Dispose() { + if (_asynchronousDisposeLock) + { + throw new InvalidOperationException("SevenZipExtractor instance must not be disposed " + + "while making an asynchronous method call."); + } if (!_disposed) { CommonDispose(); @@ -916,6 +993,7 @@ namespace SevenZip { _archive.Close(); } + ((InStreamWrapper)_archiveStream).Dispose(); _archiveStream = null; _opened = false; } diff --git a/BizHawk.Client.Common/7z/SevenZipExtractorAsynchronous.cs b/BizHawk.Client.Common/7z/SevenZipExtractorAsynchronous.cs index bffc19cc5e..4d00ddc4ce 100644 --- a/BizHawk.Client.Common/7z/SevenZipExtractorAsynchronous.cs +++ b/BizHawk.Client.Common/7z/SevenZipExtractorAsynchronous.cs @@ -1,4 +1,20 @@ -namespace SevenZip +/* 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 . +*/ + +namespace SevenZip { using System; using System.IO; @@ -53,6 +69,7 @@ ) { DisposedCheck(); + _asynchronousDisposeLock = true; base.SaveContext( #if !DOTNET20 eventPriority @@ -61,6 +78,12 @@ } + internal override void ReleaseContext() + { + base.ReleaseContext(); + _asynchronousDisposeLock = false; + } + #endregion #region Delegates