diff --git a/src/SharpCompress/Archives/ArchiveFactory.cs b/src/SharpCompress/Archives/ArchiveFactory.cs index f9e304ad..8bb8f3f3 100644 --- a/src/SharpCompress/Archives/ArchiveFactory.cs +++ b/src/SharpCompress/Archives/ArchiveFactory.cs @@ -26,11 +26,11 @@ namespace SharpCompress.Archives { archiveFactories = new HashSet(); - RegisterFactory(new Tar.TarArchiveFactory()); - RegisterFactory(new Rar.RarArchiveFactory()); RegisterFactory(new Zip.ZipArchiveFactory()); - RegisterFactory(new GZip.GZipArchiveFactory()); + RegisterFactory(new Rar.RarArchiveFactory()); RegisterFactory(new SevenZip.SevenZipArchiveFactory()); + RegisterFactory(new GZip.GZipArchiveFactory()); + RegisterFactory(new Tar.TarArchiveFactory()); } /// @@ -61,25 +61,7 @@ namespace SharpCompress.Archives readerOptions ??= new ReaderOptions(); - long startPosition = stream.Position; - - foreach(var factory in Factories) - { - stream.Seek(startPosition, SeekOrigin.Begin); - - if (factory.IsArchive(stream)) - { - stream.Seek(startPosition, SeekOrigin.Begin); - - return factory.Open(stream, readerOptions); - } - } - - var extensions = Factories - .Select(item => item.Name) - .Aggregate((a,b) => a + ", " + b ); - - throw new InvalidOperationException($"Cannot determine compressed stream type. Supported Archive Formats: {extensions}"); + return FindArchiveFactory(stream).Open(stream, readerOptions); } public static IWritableArchive Create(ArchiveType type) @@ -114,29 +96,7 @@ namespace SharpCompress.Archives fileInfo.CheckNotNull(nameof(fileInfo)); options ??= new ReaderOptions { LeaveStreamOpen = false }; - ArchiveType? type; - using (Stream stream = fileInfo.OpenRead()) - { - IsArchive(stream, out type); //test and reset stream position - - if (type != null) - { - switch (type.Value) - { - case ArchiveType.Zip: - return ZipArchive.Open(fileInfo, options); - case ArchiveType.SevenZip: - return SevenZipArchive.Open(fileInfo, options); - case ArchiveType.GZip: - return GZipArchive.Open(fileInfo, options); - case ArchiveType.Rar: - return RarArchive.Open(fileInfo, options); - case ArchiveType.Tar: - return TarArchive.Open(fileInfo, options); - } - } - } - throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip"); + return FindArchiveFactory(fileInfo).Open(fileInfo, options); } /// @@ -154,31 +114,10 @@ namespace SharpCompress.Archives if (files.Length == 1) return Open(fileInfo, options); - fileInfo.CheckNotNull(nameof(fileInfo)); options ??= new ReaderOptions { LeaveStreamOpen = false }; - ArchiveType? type; - using (Stream stream = fileInfo.OpenRead()) - IsArchive(stream, out type); //test and reset stream position - - if (type != null) - { - switch (type.Value) - { - case ArchiveType.Zip: - return ZipArchive.Open(files, options); - case ArchiveType.SevenZip: - return SevenZipArchive.Open(files, options); - case ArchiveType.GZip: - return GZipArchive.Open(files, options); - case ArchiveType.Rar: - return RarArchive.Open(files, options); - case ArchiveType.Tar: - return TarArchive.Open(files, options); - } - } - throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip"); + return FindArchiveFactory(fileInfo).Open(fileInfos, options); } /// @@ -189,36 +128,18 @@ namespace SharpCompress.Archives public static IArchive Open(IEnumerable streams, ReaderOptions? options = null) { streams.CheckNotNull(nameof(streams)); - if (streams.Count() == 0) + Stream[] streamsArray = streams.ToArray(); + if (streamsArray.Length == 0) throw new InvalidOperationException("No streams"); - if (streams.Count() == 1) - return Open(streams.First(), options); - + Stream firstStream = streamsArray[0]; + if (streamsArray.Length == 1) + return Open(firstStream, options); + firstStream.CheckNotNull(nameof(firstStream)); options ??= new ReaderOptions(); - ArchiveType? type; - using (Stream stream = streams.First()) - IsArchive(stream, out type); //test and reset stream position - - if (type != null) - { - switch (type.Value) - { - case ArchiveType.Zip: - return ZipArchive.Open(streams, options); - case ArchiveType.SevenZip: - return SevenZipArchive.Open(streams, options); - case ArchiveType.GZip: - return GZipArchive.Open(streams, options); - case ArchiveType.Rar: - return RarArchive.Open(streams, options); - case ArchiveType.Tar: - return TarArchive.Open(streams, options); - } - } - throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip"); - } + return FindArchiveFactory(firstStream).Open(streamsArray, options); + } /// /// Extract to specific directory, retaining filename @@ -233,6 +154,44 @@ namespace SharpCompress.Archives } } + private static IArchiveFactory FindArchiveFactory(FileInfo finfo) + { + finfo.CheckNotNull(nameof(finfo)); + using (Stream stream = finfo.OpenRead()) + { + return FindArchiveFactory(stream); + } + } + + private static IArchiveFactory FindArchiveFactory(Stream stream) + { + stream.CheckNotNull(nameof(stream)); + if (!stream.CanRead || !stream.CanSeek) + { + throw new ArgumentException("Stream should be readable and seekable"); + } + + long startPosition = stream.Position; + + foreach (var factory in Factories) + { + stream.Seek(startPosition, SeekOrigin.Begin); + + if (factory.IsArchive(stream)) + { + stream.Seek(startPosition, SeekOrigin.Begin); + + return factory; + } + } + + var extensions = Factories + .Select(item => item.Name) + .Aggregate((a, b) => a + ", " + b); + + throw new InvalidOperationException($"Cannot determine compressed stream type. Supported Archive Formats: {extensions}"); + } + public static bool IsArchive(string filePath, out ArchiveType? type) { filePath.CheckNotNullOrEmpty(nameof(filePath)); diff --git a/src/SharpCompress/Archives/GZip/GZipArchiveFactory.cs b/src/SharpCompress/Archives/GZip/GZipArchiveFactory.cs index d4faa639..0d52d6ca 100644 --- a/src/SharpCompress/Archives/GZip/GZipArchiveFactory.cs +++ b/src/SharpCompress/Archives/GZip/GZipArchiveFactory.cs @@ -19,7 +19,7 @@ namespace SharpCompress.Archives.GZip } /// - public bool IsArchive(Stream stream) + public bool IsArchive(Stream stream, string? password = null) { return GZipArchive.IsGZipFile(stream); } @@ -29,5 +29,23 @@ namespace SharpCompress.Archives.GZip { return GZipArchive.Open(stream, readerOptions); } + + /// + public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) + { + return GZipArchive.Open(fileInfo, readerOptions); + } + + /// + public IArchive Open(IEnumerable streams, ReaderOptions? readerOptions = null) + { + return GZipArchive.Open(streams, readerOptions); + } + + /// + public IArchive Open(IEnumerable fileInfos, ReaderOptions? readerOptions = null) + { + return GZipArchive.Open(fileInfos, readerOptions); + } } } diff --git a/src/SharpCompress/Archives/IArchiveFactory.cs b/src/SharpCompress/Archives/IArchiveFactory.cs index ea3f5bb7..5674307d 100644 --- a/src/SharpCompress/Archives/IArchiveFactory.cs +++ b/src/SharpCompress/Archives/IArchiveFactory.cs @@ -36,14 +36,36 @@ namespace SharpCompress.Archives /// /// Returns true if the stream represents an archive of the format defined by this type. /// - /// - bool IsArchive(Stream stream); + /// + /// /// optional password + bool IsArchive(Stream stream, string? password = null); /// /// Opens an Archive for random access. /// /// An open, readable and seekable stream. - /// reading options. + /// reading options. IArchive Open(Stream stream, ReaderOptions? readerOptions = null); + + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// the file to open. + /// reading options. + IArchive Open(System.IO.FileInfo fileInfo, ReaderOptions? readerOptions = null); + + /// + /// Constructor with IEnumerable FileInfo objects, multi and split support. + /// + /// + /// reading options. + IArchive Open(IEnumerable streams, ReaderOptions? readerOptions = null); + + /// + /// Constructor with IEnumerable Stream objects, multi and split support. + /// + /// + /// reading options. + IArchive Open(IEnumerable fileInfos, ReaderOptions? readerOptions = null); } } diff --git a/src/SharpCompress/Archives/Rar/RarArchiveFactory.cs b/src/SharpCompress/Archives/Rar/RarArchiveFactory.cs index bc13bd94..a049275c 100644 --- a/src/SharpCompress/Archives/Rar/RarArchiveFactory.cs +++ b/src/SharpCompress/Archives/Rar/RarArchiveFactory.cs @@ -20,7 +20,7 @@ namespace SharpCompress.Archives.Rar } /// - public bool IsArchive(Stream stream) + public bool IsArchive(Stream stream, string? password = null) { return RarArchive.IsRarFile(stream); } @@ -30,5 +30,23 @@ namespace SharpCompress.Archives.Rar { return RarArchive.Open(stream, readerOptions); } + + /// + public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) + { + return RarArchive.Open(fileInfo, readerOptions); + } + + /// + public IArchive Open(IEnumerable streams, ReaderOptions? readerOptions = null) + { + return RarArchive.Open(streams, readerOptions); + } + + /// + public IArchive Open(IEnumerable fileInfos, ReaderOptions? readerOptions = null) + { + return RarArchive.Open(fileInfos, readerOptions); + } } } diff --git a/src/SharpCompress/Archives/SevenZip/SevenZipArchiveFactory.cs b/src/SharpCompress/Archives/SevenZip/SevenZipArchiveFactory.cs index 923c7810..153fb431 100644 --- a/src/SharpCompress/Archives/SevenZip/SevenZipArchiveFactory.cs +++ b/src/SharpCompress/Archives/SevenZip/SevenZipArchiveFactory.cs @@ -19,7 +19,7 @@ namespace SharpCompress.Archives.SevenZip } /// - public bool IsArchive(Stream stream) + public bool IsArchive(Stream stream, string? password = null) { return SevenZipArchive.IsSevenZipFile(stream); } @@ -29,5 +29,23 @@ namespace SharpCompress.Archives.SevenZip { return SevenZipArchive.Open(stream, readerOptions); } + + /// + public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) + { + return SevenZipArchive.Open(fileInfo, readerOptions); + } + + /// + public IArchive Open(IEnumerable streams, ReaderOptions? readerOptions = null) + { + return SevenZipArchive.Open(streams, readerOptions); + } + + /// + public IArchive Open(IEnumerable fileInfos, ReaderOptions? readerOptions = null) + { + return SevenZipArchive.Open(fileInfos, readerOptions); + } } } diff --git a/src/SharpCompress/Archives/Tar/TarArchiveFactory.cs b/src/SharpCompress/Archives/Tar/TarArchiveFactory.cs index 8a67a5f3..fb9c170c 100644 --- a/src/SharpCompress/Archives/Tar/TarArchiveFactory.cs +++ b/src/SharpCompress/Archives/Tar/TarArchiveFactory.cs @@ -19,7 +19,7 @@ namespace SharpCompress.Archives.Tar } /// - public bool IsArchive(Stream stream) + public bool IsArchive(Stream stream, string? password = null) { return TarArchive.IsTarFile(stream); } @@ -29,5 +29,24 @@ namespace SharpCompress.Archives.Tar { return TarArchive.Open(stream, readerOptions); } + + /// + public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) + { + return TarArchive.Open(fileInfo, readerOptions); + } + + /// + public IArchive Open(IEnumerable streams, ReaderOptions? readerOptions = null) + { + return TarArchive.Open(streams, readerOptions); + } + + /// + public IArchive Open(IEnumerable fileInfos, ReaderOptions? readerOptions = null) + { + return TarArchive.Open(fileInfos, readerOptions); + } + } } diff --git a/src/SharpCompress/Archives/Zip/ZipArchiveFactory.cs b/src/SharpCompress/Archives/Zip/ZipArchiveFactory.cs index eade3e5e..68c3f2b6 100644 --- a/src/SharpCompress/Archives/Zip/ZipArchiveFactory.cs +++ b/src/SharpCompress/Archives/Zip/ZipArchiveFactory.cs @@ -21,9 +21,18 @@ namespace SharpCompress.Archives.Zip } /// - public bool IsArchive(Stream stream) + public bool IsArchive(Stream stream, string? password = null) { - return ZipArchive.IsZipFile(stream); + long startPosition = stream.Position; + + if (ZipArchive.IsZipFile(stream, password)) return true; + + stream.Seek(startPosition, SeekOrigin.Begin); + + //test the zip (last) file of a multipart zip + if (ZipArchive.IsZipMulti(stream)) return true; + + return false; } /// @@ -31,5 +40,23 @@ namespace SharpCompress.Archives.Zip { return ZipArchive.Open(stream, readerOptions); } + + /// + public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) + { + return ZipArchive.Open(fileInfo, readerOptions); + } + + /// + public IArchive Open(IEnumerable streams, ReaderOptions? readerOptions = null) + { + return ZipArchive.Open(streams, readerOptions); + } + + /// + public IArchive Open(IEnumerable fileInfos, ReaderOptions? readerOptions = null) + { + return ZipArchive.Open(fileInfos, readerOptions); + } } }