From 5d9ed5e8b6c86212a0f5f7ddbd85085260c345fd Mon Sep 17 00:00:00 2001 From: Adam Crilly Date: Fri, 14 Oct 2022 14:12:43 +0100 Subject: [PATCH 1/3] Adding new support for leaving the streamopen --- SevenZip/SevenZipExtractor.cs | 161 ++++++++++++++++++---------------- 1 file changed, 87 insertions(+), 74 deletions(-) diff --git a/SevenZip/SevenZipExtractor.cs b/SevenZip/SevenZipExtractor.cs index 9b32f6e..32798e2 100644 --- a/SevenZip/SevenZipExtractor.cs +++ b/SevenZip/SevenZipExtractor.cs @@ -42,6 +42,7 @@ public sealed partial class SevenZipExtractor private ReadOnlyCollection _archiveFileInfoCollection; private ReadOnlyCollection _archiveProperties; private ReadOnlyCollection _volumeFileNames; + private bool _leaveOpen; /// /// This is used to lock possible Dispose() calls. @@ -58,15 +59,15 @@ private void Init(string archiveFullName) { _fileName = archiveFullName; var isExecutable = false; - + if ((int)_format == -1) { _format = FileChecker.CheckSignature(archiveFullName, out _offset, out isExecutable); } - + PreserveDirectoryStructure = true; SevenZipLibraryManager.LoadLibrary(this, _format); - + try { _archive = SevenZipLibraryManager.InArchive(_format, this); @@ -76,7 +77,7 @@ private void Init(string archiveFullName) SevenZipLibraryManager.FreeLibrary(this, _format); throw; } - + if (isExecutable && _format != InArchiveFormat.PE) { if (!Check()) @@ -84,7 +85,7 @@ private void Init(string archiveFullName) CommonDispose(); _format = InArchiveFormat.PE; SevenZipLibraryManager.LoadLibrary(this, _format); - + try { _archive = SevenZipLibraryManager.InArchive(_format, this); @@ -106,19 +107,19 @@ private void Init(Stream stream) { ValidateStream(stream); var isExecutable = false; - + if ((int)_format == -1) { _format = FileChecker.CheckSignature(stream, out _offset, out isExecutable); - } - + } + PreserveDirectoryStructure = true; SevenZipLibraryManager.LoadLibrary(this, _format); - + try { _inStream = new ArchiveEmulationStreamProxy(stream, _offset); - _packedSize = stream.Length; + _packedSize = stream.Length; _archive = SevenZipLibraryManager.InArchive(_format, this); } catch (SevenZipLibraryException) @@ -126,14 +127,14 @@ private void Init(Stream stream) SevenZipLibraryManager.FreeLibrary(this, _format); throw; } - + if (isExecutable && _format != InArchiveFormat.PE) { if (!Check()) { CommonDispose(); _format = InArchiveFormat.PE; - + try { _inStream = new ArchiveEmulationStreamProxy(stream, _offset); @@ -155,9 +156,19 @@ private void Init(Stream stream) /// The stream to read the archive from. /// Use SevenZipExtractor(string) to extract from disk, though it is not necessary. /// The archive format is guessed by the signature. - public SevenZipExtractor(Stream archiveStream) + public SevenZipExtractor(Stream archiveStream) : this(archiveStream, false) + { + } + + /// + /// Initializes a new instance of SevenZipExtractor class. + /// + /// The stream to read the archive from. + /// Use SevenZipExtractor(string) to extract from disk, though it is not necessary. + /// Leaves the base stream open. + /// The archive format is guessed by the signature. + public SevenZipExtractor(Stream archiveStream, bool leaveOpen) : this(archiveStream, leaveOpen, (InArchiveFormat)(-1)) { - Init(archiveStream); } /// @@ -165,11 +176,13 @@ public SevenZipExtractor(Stream archiveStream) /// /// The stream to read the archive from. /// Use SevenZipExtractor(string) to extract from disk, though it is not necessary. + /// Leaves the base stream open. /// 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) + public SevenZipExtractor(Stream archiveStream, bool leaveOpen, InArchiveFormat format) { + _leaveOpen = leaveOpen; _format = format; Init(archiveStream); } @@ -264,7 +277,7 @@ public string FileName return _fileName; } - } + } /// /// Gets the size of the archive file @@ -307,12 +320,12 @@ public bool IsSolid get { DisposedCheck(); - + if (!_isSolid.HasValue) { GetArchiveInfo(true); } - + Debug.Assert(_isSolid != null); return _isSolid.Value; } @@ -327,14 +340,14 @@ public uint FilesCount get { DisposedCheck(); - + if (!_filesCount.HasValue) { GetArchiveInfo(true); } - + Debug.Assert(_filesCount != null); - return _filesCount.Value; + return _filesCount.Value; } } @@ -346,7 +359,7 @@ public InArchiveFormat Format get { DisposedCheck(); - + return _format; } } @@ -355,8 +368,8 @@ public InArchiveFormat Format /// Gets or sets the value indicating whether to preserve the directory structure of extracted files. /// public bool PreserveDirectoryStructure { get; set; } - - #endregion + + #endregion /// /// Checked whether the class was disposed. @@ -431,7 +444,7 @@ private OperationResult OpenArchiveInner(IInStream archiveStream, IArchiveOpenCa { ulong checkPos = 1 << 15; var res = _archive.Open(archiveStream, ref checkPos, openCallback); - + return (OperationResult)res; } @@ -452,7 +465,7 @@ private bool OpenArchive(IInStream archiveStream, ArchiveOpenCallback openCallba return false; } } - + _volumeFileNames = new ReadOnlyCollection(openCallback.VolumeFileNames); _opened = true; } @@ -476,11 +489,11 @@ private void GetArchiveInfo(bool disposeStream) else { IInStream archiveStream; - + using ((archiveStream = GetArchiveStream(disposeStream)) as IDisposable) { var openCallback = GetArchiveOpenCallback(); - + if (!_opened) { if (!OpenArchive(archiveStream, openCallback)) @@ -492,11 +505,11 @@ private void GetArchiveInfo(bool disposeStream) _filesCount = _archive.GetNumberOfItems(); _archiveFileData = new List((int)_filesCount); - + if (_filesCount != 0) { var data = new PropVariant(); - + try { #region Getting archive items data @@ -546,7 +559,7 @@ private void GetArchiveInfo(bool disposeStream) var numProps = _archive.GetNumberOfArchiveProperties(); var archProps = new List((int)numProps); - + for (uint i = 0; i < numProps; i++) { _archive.GetArchivePropertyInfo(i, out var propName, out var propId, out var varType); @@ -556,7 +569,7 @@ private void GetArchiveInfo(bool disposeStream) { _isSolid = NativeMethods.SafeCast(data, true); } - + // TODO Add more archive properties if (PropIdToName.PropIdNames.ContainsKey(propId)) { @@ -625,7 +638,7 @@ private void InitArchiveFileData(bool disposeStream) /// The array of indexes from 0 to the maximum value in the specified array private static uint[] SolidIndexes(uint[] indexes) { - var max = indexes.Aggregate(0, (current, i) => Math.Max(current, (int) i)); + var max = indexes.Aggregate(0, (current, i) => Math.Max(current, (int)i)); if (max > 0) { @@ -657,7 +670,7 @@ private void ArchiveExtractCallbackCommonInit(ArchiveExtractCallback aec) { aec.Open += ((s, e) => { _unpackedSize = (long)e.TotalSize; }); aec.FileExtractionStarted += FileExtractionStartedEventProxy; - aec.FileExtractionFinished += FileExtractionFinishedEventProxy; + aec.FileExtractionFinished += FileExtractionFinishedEventProxy; aec.Extracting += ExtractingEventProxy; aec.FileExists += FileExistsEventProxy; } @@ -671,8 +684,8 @@ private void ArchiveExtractCallbackCommonInit(ArchiveExtractCallback aec) /// The ArchiveExtractCallback callback private ArchiveExtractCallback GetArchiveExtractCallback(string directory, int filesCount, List actualIndexes) { - var aec = string.IsNullOrEmpty(Password) ? - new ArchiveExtractCallback(_archive, directory, filesCount, PreserveDirectoryStructure, actualIndexes, this) : + var aec = string.IsNullOrEmpty(Password) ? + new ArchiveExtractCallback(_archive, directory, filesCount, PreserveDirectoryStructure, actualIndexes, this) : new ArchiveExtractCallback(_archive, directory, filesCount, PreserveDirectoryStructure, actualIndexes, Password, this); ArchiveExtractCallbackCommonInit(aec); @@ -714,10 +727,10 @@ private void FreeArchiveExtractCallback(ArchiveExtractCallback callback) /// The stream to check. private static void ValidateStream(Stream stream) { - if (stream == null) - { - throw new ArgumentNullException(nameof(stream)); - } + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } if (!stream.CanSeek || !stream.CanRead) { @@ -749,14 +762,14 @@ private void CommonDispose() _archiveFileData = null; _archiveProperties = null; _archiveFileInfoCollection = null; - - if (_inStream != null) - { + + if (_inStream != null && !_leaveOpen) + { _inStream.Dispose(); _inStream = null; - } - - if (_openCallback != null) + } + + if (_openCallback != null) { try { @@ -765,7 +778,7 @@ private void CommonDispose() catch (ObjectDisposedException) { } _openCallback = null; } - + if (_archiveStream != null) { if (_archiveStream is IDisposable) @@ -798,11 +811,11 @@ public void Dispose() } if (!_disposed) - { + { CommonDispose(); } - _disposed = true; + _disposed = true; GC.SuppressFinalize(this); } @@ -816,7 +829,7 @@ public void Dispose() /// Occurs when a new file is going to be unpacked. /// /// Occurs when 7-zip engine requests for an output stream for a new file to unpack in. - public event EventHandler FileExtractionStarted; + public event EventHandler FileExtractionStarted; /// /// Occurs when a file has been successfully unpacked. @@ -946,7 +959,7 @@ public ReadOnlyCollection VolumeFileNames InitArchiveFileData(true); return _volumeFileNames; - } + } } #endregion @@ -963,7 +976,7 @@ public bool Check() InitArchiveFileData(false); var archiveStream = GetArchiveStream(true); var openCallback = GetArchiveOpenCallback(); - + if (!OpenArchive(archiveStream, openCallback)) { return false; @@ -1012,7 +1025,7 @@ public void ExtractFile(string fileName, Stream stream) InitArchiveFileData(false); var index = -1; - + foreach (var afi in _archiveFileData) { if (afi.FileName == fileName && !afi.IsDirectory) @@ -1046,7 +1059,7 @@ public void ExtractFile(int index, Stream stream) { DisposedCheck(); ClearExceptions(); - + if (!CheckIndexes(index)) { if (!ThrowException(null, new ArgumentException("The index must be more or equal to zero.", nameof(index)))) @@ -1064,7 +1077,7 @@ public void ExtractFile(int index, Stream stream) } InitArchiveFileData(false); - + if (index > _filesCount - 1) { if (!ThrowException(null, new ArgumentOutOfRangeException( @@ -1073,7 +1086,7 @@ public void ExtractFile(int index, Stream stream) return; } } - + var archiveStream = GetArchiveStream(false); var openCallback = GetArchiveOpenCallback(); @@ -1091,13 +1104,13 @@ public void ExtractFile(int index, Stream stream) { indexes = SolidIndexes(indexes); } - - using (var aec = GetArchiveExtractCallback(stream, (uint) index, indexes.Length)) + + using (var aec = GetArchiveExtractCallback(stream, (uint)index, indexes.Length)) { try { CheckedExecute( - _archive.Extract(indexes, (uint) indexes.Length, 0, aec), + _archive.Extract(indexes, (uint)indexes.Length, 0, aec), SevenZipExtractionFailedException.DEFAULT_MESSAGE, aec); } finally @@ -1148,12 +1161,12 @@ public void ExtractFiles(string directory, params int[] indexes) for (var i = 0; i < indexes.Length; i++) { - uindexes[i] = (uint) indexes[i]; + uindexes[i] = (uint)indexes[i]; } if (uindexes.Where(i => i >= _filesCount).Any( - i => !ThrowException(null, - new ArgumentOutOfRangeException(nameof(indexes), + i => !ThrowException(null, + new ArgumentOutOfRangeException(nameof(indexes), $"Index must be less than {_filesCount.Value.ToString(CultureInfo.InvariantCulture)}!")))) { return; @@ -1162,7 +1175,7 @@ public void ExtractFiles(string directory, params int[] indexes) var origIndexes = new List(uindexes); origIndexes.Sort(); uindexes = origIndexes.ToArray(); - + if (_isSolid.Value) { uindexes = SolidIndexes(uindexes); @@ -1173,11 +1186,11 @@ public void ExtractFiles(string directory, params int[] indexes) try { IInStream archiveStream; - + using ((archiveStream = GetArchiveStream(origIndexes.Count != 1)) as IDisposable) { var openCallback = GetArchiveOpenCallback(); - + if (!OpenArchive(archiveStream, openCallback)) { return; @@ -1185,12 +1198,12 @@ public void ExtractFiles(string directory, params int[] indexes) try { - using (var aec = GetArchiveExtractCallback(directory, (int) _filesCount, origIndexes)) + using (var aec = GetArchiveExtractCallback(directory, (int)_filesCount, origIndexes)) { try { CheckedExecute( - _archive.Extract(uindexes, (uint) uindexes.Length, 0, aec), + _archive.Extract(uindexes, (uint)uindexes.Length, 0, aec), SevenZipExtractionFailedException.DEFAULT_MESSAGE, aec); } finally @@ -1234,7 +1247,7 @@ public void ExtractFiles(string directory, params string[] fileNames) InitArchiveFileData(false); var indexes = new List(fileNames.Length); var archiveFileNames = new List(ArchiveFileNames); - + foreach (var fn in fileNames) { if (!archiveFileNames.Contains(fn)) @@ -1289,7 +1302,7 @@ public void ExtractFiles(ExtractFileCallback extractFileCallback) if (extractFileCallbackArgs.ExtractToStream != null || extractFileCallbackArgs.ExtractToFile != null) { - var callDone = false; + var callDone = false; try { @@ -1336,7 +1349,7 @@ public void ExtractFiles(ExtractFileCallback extractFileCallback) /// The directory where the files are to be unpacked. public void ExtractArchive(string directory) { - DisposedCheck(); + DisposedCheck(); ClearExceptions(); InitArchiveFileData(false); @@ -1355,7 +1368,7 @@ public void ExtractArchive(string directory) try { - using (var aec = GetArchiveExtractCallback(directory, (int) _filesCount, null)) + using (var aec = GetArchiveExtractCallback(directory, (int)_filesCount, null)) { try { @@ -1387,8 +1400,8 @@ public void ExtractArchive(string directory) } ThrowUserException(); - } - + } + #endregion #endif @@ -1415,7 +1428,7 @@ internal static byte[] GetLzmaProperties(Stream inStream, out long outSize) throw new LzmaException(); } - outSize |= ((long) (byte) b) << (i << 3); + outSize |= ((long)(byte)b) << (i << 3); } return lzmAproperties; From 55a52ed15ebf2ec4531e913c390b3816bea38fb2 Mon Sep 17 00:00:00 2001 From: Adam Crilly Date: Fri, 14 Oct 2022 14:36:54 +0100 Subject: [PATCH 2/3] Fixing other constructors --- SevenZip/SevenZipExtractor.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/SevenZip/SevenZipExtractor.cs b/SevenZip/SevenZipExtractor.cs index 32798e2..80e71c5 100644 --- a/SevenZip/SevenZipExtractor.cs +++ b/SevenZip/SevenZipExtractor.cs @@ -241,10 +241,19 @@ public SevenZipExtractor(string archiveFullName, string password, InArchiveForma /// 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) - : base(password) + public SevenZipExtractor(Stream archiveStream, string password) : this(archiveStream, password, false) + { + } + + /// + /// Initializes a new instance of SevenZipExtractor class. + /// + /// The stream to read the archive from. + /// Password for an encrypted archive. + /// Leaves the base stream open. + /// The archive format is guessed by the signature. + public SevenZipExtractor(Stream archiveStream, string password, bool leaveOpen) : this(archiveStream, password, leaveOpen, (InArchiveFormat)(-1)) { - Init(archiveStream); } /// @@ -252,13 +261,15 @@ public SevenZipExtractor(Stream archiveStream, string password) /// /// The stream to read the archive from. /// Password for an encrypted archive. + /// Leaves the base stream open. /// 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) + public SevenZipExtractor(Stream archiveStream, string password, bool leaveOpen, InArchiveFormat format) : base(password) { _format = format; + _leaveOpen = leaveOpen; Init(archiveStream); } From d339130682104ff70be2c981e2284edc68514852 Mon Sep 17 00:00:00 2001 From: Adam Crilly Date: Fri, 14 Oct 2022 15:12:10 +0100 Subject: [PATCH 3/3] Fixing _archiveStream from closing using new _leaveOpen member --- SevenZip/SevenZipExtractor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SevenZip/SevenZipExtractor.cs b/SevenZip/SevenZipExtractor.cs index 80e71c5..719823e 100644 --- a/SevenZip/SevenZipExtractor.cs +++ b/SevenZip/SevenZipExtractor.cs @@ -790,7 +790,7 @@ private void CommonDispose() _openCallback = null; } - if (_archiveStream != null) + if (_archiveStream != null && !_leaveOpen) { if (_archiveStream is IDisposable) {