Merge branch 'master' into master

This commit is contained in:
Adam Hathcock
2022-09-06 11:46:16 +01:00
committed by GitHub
7 changed files with 419 additions and 91 deletions

View File

@@ -15,6 +15,36 @@ namespace SharpCompress.Archives
{
public static class ArchiveFactory
{
private static readonly HashSet<IArchiveFactory> archiveFactories;
/// <summary>
/// Gets the collection of registered archive factories
/// </summary>
public static IReadOnlyCollection<IArchiveFactory> Factories => archiveFactories;
static ArchiveFactory()
{
archiveFactories = new HashSet<IArchiveFactory>();
RegisterFactory(new Zip.ZipArchiveFactory());
RegisterFactory(new Rar.RarArchiveFactory());
RegisterFactory(new SevenZip.SevenZipArchiveFactory());
RegisterFactory(new GZip.GZipArchiveFactory());
RegisterFactory(new Tar.TarArchiveFactory());
}
/// <summary>
/// Registers an archive factory.
/// </summary>
/// <param name="factory">The factory to register.</param>
/// <exception cref="ArgumentNullException"><paramref name="factory"/> must not be null.</exception>
public static void RegisterFactory(IArchiveFactory factory)
{
factory.CheckNotNull(nameof(factory));
archiveFactories.Add(factory);
}
/// <summary>
/// Opens an Archive for random access
/// </summary>
@@ -28,28 +58,10 @@ namespace SharpCompress.Archives
{
throw new ArgumentException("Stream should be readable and seekable");
}
readerOptions ??= new ReaderOptions();
ArchiveType? type;
IsArchive(stream, out type); //test and reset stream position
if (type != null)
{
switch (type.Value)
{
case ArchiveType.Zip:
return ZipArchive.Open(stream, readerOptions);
case ArchiveType.SevenZip:
return SevenZipArchive.Open(stream, readerOptions);
case ArchiveType.GZip:
return GZipArchive.Open(stream, readerOptions);
case ArchiveType.Rar:
return RarArchive.Open(stream, readerOptions);
case ArchiveType.Tar:
return TarArchive.Open(stream, readerOptions);
}
}
throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip, LZip");
return FindArchiveFactory(stream).Open(stream, readerOptions);
}
public static IWritableArchive Create(ArchiveType type)
@@ -84,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);
}
/// <summary>
@@ -124,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);
}
/// <summary>
@@ -159,36 +128,18 @@ namespace SharpCompress.Archives
public static IArchive Open(IEnumerable<Stream> 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);
}
/// <summary>
/// Extract to specific directory, retaining filename
@@ -203,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));

View File

@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Readers;
namespace SharpCompress.Archives.GZip
{
public class GZipArchiveFactory : IArchiveFactory
{
/// <inheritdoc/>
public string Name => "GZip";
/// <inheritdoc/>
public IEnumerable<string> GetSupportedExtensions()
{
yield return "gz";
}
/// <inheritdoc/>
public bool IsArchive(Stream stream, string? password = null)
{
return GZipArchive.IsGZipFile(stream);
}
/// <inheritdoc/>
public IArchive Open(Stream stream, ReaderOptions? readerOptions = null)
{
return GZipArchive.Open(stream, readerOptions);
}
/// <inheritdoc/>
public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null)
{
return GZipArchive.Open(fileInfo, readerOptions);
}
/// <inheritdoc/>
public IArchive Open(IEnumerable<Stream> streams, ReaderOptions? readerOptions = null)
{
return GZipArchive.Open(streams, readerOptions);
}
/// <inheritdoc/>
public IArchive Open(IEnumerable<FileInfo> fileInfos, ReaderOptions? readerOptions = null)
{
return GZipArchive.Open(fileInfos, readerOptions);
}
}
}

View File

@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common;
using SharpCompress.Readers;
namespace SharpCompress.Archives
{
/// <summary>
/// Represents a factory used to identify and open archives.
/// </summary>
/// <remarks>
/// Currently implemented by:<br/>
/// <list type="table">
/// <item><see cref="Tar.TarArchiveFactory"/></item>
/// <item><see cref="Rar.RarArchiveFactory"/></item>
/// <item><see cref="Zip.ZipArchiveFactory"/></item>
/// <item><see cref="GZip.GZipArchiveFactory"/></item>
/// <item><see cref="SevenZip.SevenZipArchiveFactory"/></item>
/// </list>
/// </remarks>
public interface IArchiveFactory
{
/// <summary>
/// Gets the archive Type name
/// </summary>
string Name { get; }
/// <summary>
/// returns the extensions typically used by this archive type.
/// </summary>
/// <returns></returns>
IEnumerable<string> GetSupportedExtensions();
/// <summary>
/// Returns true if the stream represents an archive of the format defined by this type.
/// </summary>
/// <param name="stream"></param>
/// /// <param name="password">optional password</param>
bool IsArchive(Stream stream, string? password = null);
/// <summary>
/// Opens an Archive for random access.
/// </summary>
/// <param name="stream">An open, readable and seekable stream.</param>
/// <param name="readerOptions">reading options.</param>
IArchive Open(Stream stream, ReaderOptions? readerOptions = null);
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo">the file to open.</param>
/// <param name="readerOptions">reading options.</param>
IArchive Open(System.IO.FileInfo fileInfo, ReaderOptions? readerOptions = null);
/// <summary>
/// Constructor with IEnumerable FileInfo objects, multi and split support.
/// </summary>
/// <param name="streams"></param>
/// <param name="readerOptions">reading options.</param>
IArchive Open(IEnumerable<Stream> streams, ReaderOptions? readerOptions = null);
/// <summary>
/// Constructor with IEnumerable Stream objects, multi and split support.
/// </summary>
/// <param name="fileInfos"></param>
/// <param name="readerOptions">reading options.</param>
IArchive Open(IEnumerable<System.IO.FileInfo> fileInfos, ReaderOptions? readerOptions = null);
}
}

View File

@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Readers;
namespace SharpCompress.Archives.Rar
{
public class RarArchiveFactory : IArchiveFactory
{
/// <inheritdoc/>
public string Name => "Rar";
/// <inheritdoc/>
public IEnumerable<string> GetSupportedExtensions()
{
yield return "rar";
yield return "cbr";
}
/// <inheritdoc/>
public bool IsArchive(Stream stream, string? password = null)
{
return RarArchive.IsRarFile(stream);
}
/// <inheritdoc/>
public IArchive Open(Stream stream, ReaderOptions? readerOptions = null)
{
return RarArchive.Open(stream, readerOptions);
}
/// <inheritdoc/>
public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null)
{
return RarArchive.Open(fileInfo, readerOptions);
}
/// <inheritdoc/>
public IArchive Open(IEnumerable<Stream> streams, ReaderOptions? readerOptions = null)
{
return RarArchive.Open(streams, readerOptions);
}
/// <inheritdoc/>
public IArchive Open(IEnumerable<FileInfo> fileInfos, ReaderOptions? readerOptions = null)
{
return RarArchive.Open(fileInfos, readerOptions);
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Readers;
namespace SharpCompress.Archives.SevenZip
{
public class SevenZipArchiveFactory : IArchiveFactory
{
/// <inheritdoc/>
public string Name => "7Zip";
/// <inheritdoc/>
public IEnumerable<string> GetSupportedExtensions()
{
yield return "7z";
}
/// <inheritdoc/>
public bool IsArchive(Stream stream, string? password = null)
{
return SevenZipArchive.IsSevenZipFile(stream);
}
/// <inheritdoc/>
public IArchive Open(Stream stream, ReaderOptions? readerOptions = null)
{
return SevenZipArchive.Open(stream, readerOptions);
}
/// <inheritdoc/>
public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null)
{
return SevenZipArchive.Open(fileInfo, readerOptions);
}
/// <inheritdoc/>
public IArchive Open(IEnumerable<Stream> streams, ReaderOptions? readerOptions = null)
{
return SevenZipArchive.Open(streams, readerOptions);
}
/// <inheritdoc/>
public IArchive Open(IEnumerable<FileInfo> fileInfos, ReaderOptions? readerOptions = null)
{
return SevenZipArchive.Open(fileInfos, readerOptions);
}
}
}

View File

@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Readers;
namespace SharpCompress.Archives.Tar
{
public class TarArchiveFactory : IArchiveFactory
{
/// <inheritdoc/>
public string Name => "Tar";
/// <inheritdoc/>
public IEnumerable<string> GetSupportedExtensions()
{
yield return "tar";
}
/// <inheritdoc/>
public bool IsArchive(Stream stream, string? password = null)
{
return TarArchive.IsTarFile(stream);
}
/// <inheritdoc/>
public IArchive Open(Stream stream, ReaderOptions? readerOptions = null)
{
return TarArchive.Open(stream, readerOptions);
}
/// <inheritdoc/>
public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null)
{
return TarArchive.Open(fileInfo, readerOptions);
}
/// <inheritdoc/>
public IArchive Open(IEnumerable<Stream> streams, ReaderOptions? readerOptions = null)
{
return TarArchive.Open(streams, readerOptions);
}
/// <inheritdoc/>
public IArchive Open(IEnumerable<FileInfo> fileInfos, ReaderOptions? readerOptions = null)
{
return TarArchive.Open(fileInfos, readerOptions);
}
}
}

View File

@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Readers;
namespace SharpCompress.Archives.Zip
{
public class ZipArchiveFactory : IArchiveFactory
{
/// <inheritdoc/>
public string Name => "Zip";
/// <inheritdoc/>
public IEnumerable<string> GetSupportedExtensions()
{
yield return "zip";
yield return "zipx";
yield return "cbz";
}
/// <inheritdoc/>
public bool IsArchive(Stream stream, string? password = null)
{
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;
}
/// <inheritdoc/>
public IArchive Open(Stream stream, ReaderOptions? readerOptions = null)
{
return ZipArchive.Open(stream, readerOptions);
}
/// <inheritdoc/>
public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null)
{
return ZipArchive.Open(fileInfo, readerOptions);
}
/// <inheritdoc/>
public IArchive Open(IEnumerable<Stream> streams, ReaderOptions? readerOptions = null)
{
return ZipArchive.Open(streams, readerOptions);
}
/// <inheritdoc/>
public IArchive Open(IEnumerable<FileInfo> fileInfos, ReaderOptions? readerOptions = null)
{
return ZipArchive.Open(fileInfos, readerOptions);
}
}
}