mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-04 05:25:00 +00:00
Compare commits
3 Commits
0.42.0
...
copilot/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e55af11800 | ||
|
|
c8ca687dc2 | ||
|
|
ea8fcb9370 |
@@ -4,9 +4,17 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Archives.GZip;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Tar;
|
||||
using SharpCompress.Common.Tar.Headers;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Compressors.BZip2;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
using SharpCompress.Compressors.Lzw;
|
||||
using SharpCompress.Compressors.Xz;
|
||||
using SharpCompress.Compressors.ZStandard;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.Tar;
|
||||
@@ -36,6 +44,76 @@ public class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVolume>
|
||||
public static TarArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
fileInfo.NotNull(nameof(fileInfo));
|
||||
|
||||
// Check if the file extension suggests it's a compressed TAR file
|
||||
var extension = fileInfo.Extension.ToLowerInvariant();
|
||||
if (
|
||||
extension is ".gz" or ".bz2" or ".xz" or ".zst" or ".lz" or ".z"
|
||||
|| fileInfo.Name.ToLowerInvariant().Contains(".tar.")
|
||||
)
|
||||
{
|
||||
// Open the file to check for compression
|
||||
using var testStream = fileInfo.OpenRead();
|
||||
using var rewindableStream = SharpCompressStream.Create(testStream, leaveOpen: false);
|
||||
var streamStack = (IStreamStack)rewindableStream;
|
||||
var startPos = streamStack.GetPosition();
|
||||
|
||||
string? detectedCompression = null;
|
||||
|
||||
if (GZipArchive.IsGZipFile(rewindableStream))
|
||||
{
|
||||
detectedCompression = "GZip";
|
||||
}
|
||||
else
|
||||
{
|
||||
streamStack.StackSeek(startPos);
|
||||
if (BZip2Stream.IsBZip2(rewindableStream))
|
||||
{
|
||||
detectedCompression = "BZip2";
|
||||
}
|
||||
else
|
||||
{
|
||||
streamStack.StackSeek(startPos);
|
||||
if (ZStandardStream.IsZStandard(rewindableStream))
|
||||
{
|
||||
detectedCompression = "ZStandard";
|
||||
}
|
||||
else
|
||||
{
|
||||
streamStack.StackSeek(startPos);
|
||||
if (LZipStream.IsLZipFile(rewindableStream))
|
||||
{
|
||||
detectedCompression = "LZip";
|
||||
}
|
||||
else
|
||||
{
|
||||
streamStack.StackSeek(startPos);
|
||||
if (XZStream.IsXZStream(rewindableStream))
|
||||
{
|
||||
detectedCompression = "XZ";
|
||||
}
|
||||
else
|
||||
{
|
||||
streamStack.StackSeek(startPos);
|
||||
if (LzwStream.IsLzwStream(rewindableStream))
|
||||
{
|
||||
detectedCompression = "LZW";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (detectedCompression is not null)
|
||||
{
|
||||
throw new InvalidFormatException(
|
||||
$"Compressed TAR archives ({detectedCompression}) are not supported by TarArchive.Open(). "
|
||||
+ "Please use TarReader.Open() instead for forward-only reading of compressed TAR files."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return new TarArchive(
|
||||
new SourceStream(
|
||||
fileInfo,
|
||||
@@ -98,9 +176,75 @@ public class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVolume>
|
||||
throw new ArgumentException("Stream must be seekable", nameof(stream));
|
||||
}
|
||||
|
||||
return new TarArchive(
|
||||
new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions())
|
||||
readerOptions ??= new ReaderOptions();
|
||||
|
||||
// Wrap in SharpCompressStream to enable rewindable reading for compression detection
|
||||
var rewindableStream = SharpCompressStream.Create(
|
||||
stream,
|
||||
leaveOpen: readerOptions.LeaveStreamOpen
|
||||
);
|
||||
var streamStack = (IStreamStack)rewindableStream;
|
||||
var startPos = streamStack.GetPosition();
|
||||
|
||||
// Detect if the TAR file is compressed
|
||||
string? detectedCompression = null;
|
||||
|
||||
if (GZipArchive.IsGZipFile(rewindableStream))
|
||||
{
|
||||
detectedCompression = "GZip";
|
||||
}
|
||||
else
|
||||
{
|
||||
streamStack.StackSeek(startPos);
|
||||
if (BZip2Stream.IsBZip2(rewindableStream))
|
||||
{
|
||||
detectedCompression = "BZip2";
|
||||
}
|
||||
else
|
||||
{
|
||||
streamStack.StackSeek(startPos);
|
||||
if (ZStandardStream.IsZStandard(rewindableStream))
|
||||
{
|
||||
detectedCompression = "ZStandard";
|
||||
}
|
||||
else
|
||||
{
|
||||
streamStack.StackSeek(startPos);
|
||||
if (LZipStream.IsLZipFile(rewindableStream))
|
||||
{
|
||||
detectedCompression = "LZip";
|
||||
}
|
||||
else
|
||||
{
|
||||
streamStack.StackSeek(startPos);
|
||||
if (XZStream.IsXZStream(rewindableStream))
|
||||
{
|
||||
detectedCompression = "XZ";
|
||||
}
|
||||
else
|
||||
{
|
||||
streamStack.StackSeek(startPos);
|
||||
if (LzwStream.IsLzwStream(rewindableStream))
|
||||
{
|
||||
detectedCompression = "LZW";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (detectedCompression is not null)
|
||||
{
|
||||
throw new InvalidFormatException(
|
||||
$"Compressed TAR archives ({detectedCompression}) are not supported by TarArchive.Open(Stream). "
|
||||
+ "Please use TarReader.Open(Stream) instead for forward-only reading of compressed TAR files."
|
||||
);
|
||||
}
|
||||
|
||||
// No compression detected, treat as plain tar file
|
||||
streamStack.StackSeek(startPos);
|
||||
return new TarArchive(new SourceStream(rewindableStream, i => null, readerOptions));
|
||||
}
|
||||
|
||||
public static bool IsTarFile(string filePath) => IsTarFile(new FileInfo(filePath));
|
||||
|
||||
@@ -111,6 +111,32 @@ public class TarReader : AbstractReader<TarEntry, TarVolume>
|
||||
throw new InvalidFormatException("Not a tar file.");
|
||||
}
|
||||
|
||||
((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);
|
||||
return new TarReader(rewindableStream, options, CompressionType.Xz);
|
||||
}
|
||||
throw new InvalidFormatException("Not a tar file.");
|
||||
}
|
||||
|
||||
((IStreamStack)rewindableStream).StackSeek(pos);
|
||||
if (LzwStream.IsLzwStream(rewindableStream))
|
||||
{
|
||||
((IStreamStack)rewindableStream).StackSeek(pos);
|
||||
var testStream = new LzwStream(rewindableStream);
|
||||
if (TarArchive.IsTarFile(testStream))
|
||||
{
|
||||
((IStreamStack)rewindableStream).StackSeek(pos);
|
||||
return new TarReader(rewindableStream, options, CompressionType.Lzw);
|
||||
}
|
||||
throw new InvalidFormatException("Not a tar file.");
|
||||
}
|
||||
|
||||
((IStreamStack)rewindableStream).StackSeek(pos);
|
||||
return new TarReader(rewindableStream, options, CompressionType.None);
|
||||
}
|
||||
|
||||
@@ -295,4 +295,47 @@ public class TarArchiveTests : ArchiveTests
|
||||
|
||||
Assert.False(isTar);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TarArchive_Open_Compressed_XZ_Throws()
|
||||
{
|
||||
var exception = Assert.Throws<InvalidFormatException>(() =>
|
||||
TarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.xz"))
|
||||
);
|
||||
|
||||
Assert.Contains("XZ", exception.Message);
|
||||
Assert.Contains("TarReader.Open", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TarArchive_Open_Compressed_GZip_Throws()
|
||||
{
|
||||
var exception = Assert.Throws<InvalidFormatException>(() =>
|
||||
TarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"))
|
||||
);
|
||||
|
||||
Assert.Contains("GZip", exception.Message);
|
||||
Assert.Contains("TarReader.Open", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TarArchive_Open_Compressed_BZip2_Throws()
|
||||
{
|
||||
var exception = Assert.Throws<InvalidFormatException>(() =>
|
||||
TarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.bz2"))
|
||||
);
|
||||
|
||||
Assert.Contains("BZip2", exception.Message);
|
||||
Assert.Contains("TarReader.Open", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TarArchive_Open_Compressed_Stream_XZ_Throws()
|
||||
{
|
||||
using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.xz"));
|
||||
var exception = Assert.Throws<InvalidFormatException>(() => TarArchive.Open(stream));
|
||||
|
||||
Assert.Contains("XZ", exception.Message);
|
||||
Assert.Contains("TarReader.Open", exception.Message);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user