mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-24 07:54:39 +00:00
Merge pull request #945 from mitchcapper/archive_extension_hinting_pr
Extension hinting for ReaderFactory for better first try factory success
This commit is contained in:
@@ -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;
|
||||
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
|
||||
/// <inheritdoc/>
|
||||
public override IEnumerable<string> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -102,6 +87,77 @@ public class TarFactory
|
||||
|
||||
#region IReaderFactory
|
||||
|
||||
|
||||
protected class TestOption
|
||||
{
|
||||
public readonly CompressionType Type;
|
||||
public readonly Func<Stream, bool> CanHandle;
|
||||
public readonly bool WrapInSharpCompressStream;
|
||||
|
||||
public readonly Func<Stream, Stream> CreateStream;
|
||||
|
||||
public readonly IEnumerable<string> KnownExtensions;
|
||||
|
||||
public TestOption(
|
||||
CompressionType Type,
|
||||
Func<Stream, bool> CanHandle,
|
||||
Func<Stream, Stream> CreateStream,
|
||||
IEnumerable<string> 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
|
||||
),
|
||||
];
|
||||
|
||||
/// <inheritdoc/>
|
||||
internal override bool TryOpenReader(
|
||||
SharpCompressStream rewindableStream,
|
||||
@@ -111,84 +167,35 @@ public class TarFactory
|
||||
{
|
||||
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))
|
||||
{
|
||||
((IStreamStack)rewindableStream).StackSeek(pos);
|
||||
var testStream = new XZStream(rewindableStream);
|
||||
if (TarArchive.IsTarFile(testStream))
|
||||
{
|
||||
((IStreamStack)rewindableStream).StackSeek(pos);
|
||||
reader = new TarReader(rewindableStream, options, CompressionType.Xz);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
((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;
|
||||
}
|
||||
}
|
||||
@@ -196,6 +203,33 @@ public class TarFactory
|
||||
return false;
|
||||
}
|
||||
|
||||
private static IReader? TryOption(
|
||||
SharpCompressStream rewindableStream,
|
||||
ReaderOptions options,
|
||||
long pos,
|
||||
TestOption testOption
|
||||
)
|
||||
{
|
||||
if (testOption.CanHandle(rewindableStream))
|
||||
{
|
||||
((IStreamStack)rewindableStream).StackSeek(pos);
|
||||
var inStream = rewindableStream;
|
||||
if (testOption.WrapInSharpCompressStream)
|
||||
{
|
||||
inStream = SharpCompressStream.Create(rewindableStream, leaveOpen: true);
|
||||
}
|
||||
var testStream = testOption.CreateStream(rewindableStream);
|
||||
|
||||
if (TarArchive.IsTarFile(testStream))
|
||||
{
|
||||
((IStreamStack)rewindableStream).StackSeek(pos);
|
||||
return new TarReader(rewindableStream, options, testOption.Type);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IReader OpenReader(Stream stream, ReaderOptions? options) =>
|
||||
TarReader.Open(stream, options);
|
||||
|
||||
@@ -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 class ReaderFactory
|
||||
|
||||
long pos = ((IStreamStack)bStream).GetPosition();
|
||||
|
||||
foreach (var factory in Factories.Factory.Factories.OfType<Factories.Factory>())
|
||||
var factories = Factories.Factory.Factories.OfType<Factories.Factory>();
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -16,4 +16,9 @@ public class ReaderOptions : OptionsBase
|
||||
public bool DisableCheckIncomplete { get; set; }
|
||||
|
||||
public int BufferSize { get; set; } = DefaultBufferSize;
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
public string? ExtensionHint { get; set; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user