diff --git a/src/SharpCompress/Factories/TarFactory.cs b/src/SharpCompress/Factories/TarFactory.cs
index b5fc14891..d32020fd7 100644
--- a/src/SharpCompress/Factories/TarFactory.cs
+++ b/src/SharpCompress/Factories/TarFactory.cs
@@ -1,10 +1,13 @@
+using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using SharpCompress.Archives;
using SharpCompress.Archives.Tar;
using SharpCompress.Common;
using SharpCompress.Compressors;
using SharpCompress.Compressors.BZip2;
+using SharpCompress.Compressors.Deflate;
using SharpCompress.Compressors.LZMA;
using SharpCompress.Compressors.Lzw;
using SharpCompress.Compressors.Xz;
@@ -14,6 +17,7 @@
using SharpCompress.Readers.Tar;
using SharpCompress.Writers;
using SharpCompress.Writers.Tar;
+using GZipArchive = SharpCompress.Archives.GZip.GZipArchive;
namespace SharpCompress.Factories;
@@ -39,32 +43,13 @@ public class TarFactory
///
public override IEnumerable GetSupportedExtensions()
{
- // from https://en.wikipedia.org/wiki/Tar_(computing)#Suffixes_for_compressed_files
-
- yield return "tar";
-
- // gzip
- yield return "taz";
- yield return "tgz";
-
- // bzip2
- yield return "tb2";
- yield return "tbz";
- yield return "tbz2";
- yield return "tz2";
-
- // lzma
- // yield return "tlz"; // unsupported
-
- // xz
- // yield return "txz"; // unsupported
-
- // compress
- yield return "tZ";
- yield return "taZ";
-
- // zstd
- yield return "tzst";
+ foreach (var testOption in compressionOptions)
+ {
+ foreach (var ext in testOption.KnownExtensions)
+ {
+ yield return ext;
+ }
+ }
}
///
@@ -102,6 +87,77 @@ public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOpt
#region IReaderFactory
+
+ protected class TestOption
+ {
+ public readonly CompressionType Type;
+ public readonly Func CanHandle;
+ public readonly bool WrapInSharpCompressStream;
+
+ public readonly Func CreateStream;
+
+ public readonly IEnumerable KnownExtensions;
+
+ public TestOption(
+ CompressionType Type,
+ Func CanHandle,
+ Func CreateStream,
+ IEnumerable KnownExtensions,
+ bool WrapInSharpCompressStream = true
+ )
+ {
+ this.Type = Type;
+ this.CanHandle = CanHandle;
+ this.WrapInSharpCompressStream = WrapInSharpCompressStream;
+ this.CreateStream = CreateStream;
+ this.KnownExtensions = KnownExtensions;
+ }
+ }
+
+ // https://en.wikipedia.org/wiki/Tar_(computing)#Suffixes_for_compressed_files
+ protected TestOption[] compressionOptions =
+ [
+ new(CompressionType.None, (stream) => true, (stream) => stream, ["tar"], false), // We always do a test for IsTarFile later
+ new(
+ CompressionType.BZip2,
+ BZip2Stream.IsBZip2,
+ (stream) => new BZip2Stream(stream, CompressionMode.Decompress, false),
+ ["tar.bz2", "tb2", "tbz", "tbz2", "tz2"]
+ ),
+ new(
+ CompressionType.GZip,
+ GZipArchive.IsGZipFile,
+ (stream) => new GZipStream(stream, CompressionMode.Decompress),
+ ["tar.gz", "taz", "tgz"]
+ ),
+ new(
+ CompressionType.ZStandard,
+ ZStandardStream.IsZStandard,
+ (stream) => new ZStandardStream(stream),
+ ["tar.zst", "tar.zstd", "tzst", "tzstd"]
+ ),
+ new(
+ CompressionType.LZip,
+ LZipStream.IsLZipFile,
+ (stream) => new LZipStream(stream, CompressionMode.Decompress),
+ ["tar.lz"]
+ ),
+ new(
+ CompressionType.Xz,
+ XZStream.IsXZStream,
+ (stream) => new XZStream(stream),
+ ["tar.xz", "txz"],
+ false
+ ),
+ new(
+ CompressionType.Lzw,
+ LzwStream.IsLzwStream,
+ (stream) => new LzwStream(stream),
+ ["tar.Z", "tZ", "taZ"],
+ false
+ ),
+ ];
+
///
internal override bool TryOpenReader(
SharpCompressStream rewindableStream,
@@ -111,89 +167,67 @@ out IReader? reader
{
reader = null;
long pos = ((IStreamStack)rewindableStream).GetPosition();
-
- if (TarArchive.IsTarFile(rewindableStream))
+ TestOption? testedOption = null;
+ if (!string.IsNullOrWhiteSpace(options.ExtensionHint))
{
- ((IStreamStack)rewindableStream).StackSeek(pos);
- reader = OpenReader(rewindableStream, options);
- return true;
- }
-
- ((IStreamStack)rewindableStream).StackSeek(pos);
- if (BZip2Stream.IsBZip2(rewindableStream))
- {
- ((IStreamStack)rewindableStream).StackSeek(pos);
- var testStream = new BZip2Stream(
- SharpCompressStream.Create(rewindableStream, leaveOpen: true),
- CompressionMode.Decompress,
- false
+ testedOption = compressionOptions.FirstOrDefault(a =>
+ a.KnownExtensions.Contains(
+ options.ExtensionHint,
+ StringComparer.CurrentCultureIgnoreCase
+ )
);
- if (TarArchive.IsTarFile(testStream))
+ if (testedOption != null)
{
- ((IStreamStack)rewindableStream).StackSeek(pos);
- reader = new TarReader(rewindableStream, options, CompressionType.BZip2);
- return true;
+ reader = TryOption(rewindableStream, options, pos, testedOption);
+ if (reader != null)
+ {
+ return true;
+ }
}
}
- ((IStreamStack)rewindableStream).StackSeek(pos);
- if (ZStandardStream.IsZStandard(rewindableStream))
+ foreach (var testOption in compressionOptions)
{
- ((IStreamStack)rewindableStream).StackSeek(pos);
- var testStream = new ZStandardStream(
- SharpCompressStream.Create(rewindableStream, leaveOpen: true)
- );
- if (TarArchive.IsTarFile(testStream))
+ if (testedOption == testOption)
{
- ((IStreamStack)rewindableStream).StackSeek(pos);
- reader = new TarReader(rewindableStream, options, CompressionType.ZStandard);
- return true;
+ continue; // Already tested above
}
- }
-
- ((IStreamStack)rewindableStream).StackSeek(pos);
- if (LZipStream.IsLZipFile(rewindableStream))
- {
((IStreamStack)rewindableStream).StackSeek(pos);
- var testStream = new LZipStream(
- SharpCompressStream.Create(rewindableStream, leaveOpen: true),
- CompressionMode.Decompress
- );
- if (TarArchive.IsTarFile(testStream))
+ reader = TryOption(rewindableStream, options, pos, testOption);
+ if (reader != null)
{
- ((IStreamStack)rewindableStream).StackSeek(pos);
- reader = new TarReader(rewindableStream, options, CompressionType.LZip);
return true;
}
}
- ((IStreamStack)rewindableStream).StackSeek(pos);
- if (XZStream.IsXZStream(rewindableStream))
+ return false;
+ }
+
+ private static IReader? TryOption(
+ SharpCompressStream rewindableStream,
+ ReaderOptions options,
+ long pos,
+ TestOption testOption
+ )
+ {
+ if (testOption.CanHandle(rewindableStream))
{
((IStreamStack)rewindableStream).StackSeek(pos);
- var testStream = new XZStream(rewindableStream);
- if (TarArchive.IsTarFile(testStream))
+ var inStream = rewindableStream;
+ if (testOption.WrapInSharpCompressStream)
{
- ((IStreamStack)rewindableStream).StackSeek(pos);
- reader = new TarReader(rewindableStream, options, CompressionType.Xz);
- return true;
+ inStream = SharpCompressStream.Create(rewindableStream, leaveOpen: true);
}
- }
+ var testStream = testOption.CreateStream(rewindableStream);
- ((IStreamStack)rewindableStream).StackSeek(pos);
- if (LzwStream.IsLzwStream(rewindableStream))
- {
- var testStream = new LzwStream(rewindableStream);
- ((IStreamStack)rewindableStream).StackSeek(pos);
if (TarArchive.IsTarFile(testStream))
{
((IStreamStack)rewindableStream).StackSeek(pos);
- reader = new TarReader(rewindableStream, options, CompressionType.Lzw);
- return true;
+ return new TarReader(rewindableStream, options, testOption.Type);
}
}
- return false;
+ return null;
}
///
diff --git a/src/SharpCompress/Readers/ReaderFactory.cs b/src/SharpCompress/Readers/ReaderFactory.cs
index b7b40401d..fb133d98a 100644
--- a/src/SharpCompress/Readers/ReaderFactory.cs
+++ b/src/SharpCompress/Readers/ReaderFactory.cs
@@ -1,6 +1,8 @@
+using System;
using System.IO;
using System.Linq;
using SharpCompress.Common;
+using SharpCompress.Factories;
using SharpCompress.IO;
namespace SharpCompress.Readers;
@@ -22,8 +24,32 @@ public static IReader Open(Stream stream, ReaderOptions? options = null)
long pos = ((IStreamStack)bStream).GetPosition();
- foreach (var factory in Factories.Factory.Factories.OfType())
+ var factories = Factories.Factory.Factories.OfType();
+
+ Factory? testedFactory = null;
+
+ if (!string.IsNullOrWhiteSpace(options.ExtensionHint))
{
+ testedFactory = factories.FirstOrDefault(a =>
+ a.GetSupportedExtensions()
+ .Contains(options.ExtensionHint, StringComparer.CurrentCultureIgnoreCase)
+ );
+ if (
+ testedFactory?.TryOpenReader(bStream, options, out var reader) == true
+ && reader != null
+ )
+ {
+ return reader;
+ }
+ ((IStreamStack)bStream).StackSeek(pos);
+ }
+
+ foreach (var factory in factories)
+ {
+ if (testedFactory == factory)
+ {
+ continue; // Already tested above
+ }
((IStreamStack)bStream).StackSeek(pos);
if (factory.TryOpenReader(bStream, options, out var reader) && reader != null)
{
diff --git a/src/SharpCompress/Readers/ReaderOptions.cs b/src/SharpCompress/Readers/ReaderOptions.cs
index a581d51a5..4ddfe94d2 100644
--- a/src/SharpCompress/Readers/ReaderOptions.cs
+++ b/src/SharpCompress/Readers/ReaderOptions.cs
@@ -16,4 +16,9 @@ public class ReaderOptions : OptionsBase
public bool DisableCheckIncomplete { get; set; }
public int BufferSize { get; set; } = DefaultBufferSize;
+
+ ///
+ /// Provide a hint for the extension of the archive being read, can speed up finding the correct decoder. Should be without the leading period in the form like: tar.gz or zip
+ ///
+ public string? ExtensionHint { get; set; }
}