mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-08 13:34:57 +00:00
Compare commits
4 Commits
master
...
copilot/ad
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b746c49cf | ||
|
|
1da178a4be | ||
|
|
2b74807f5e | ||
|
|
38d295b089 |
@@ -10,4 +10,5 @@ public enum ArchiveType
|
||||
Arc,
|
||||
Arj,
|
||||
Ace,
|
||||
Lzw,
|
||||
}
|
||||
|
||||
20
src/SharpCompress/Common/Lzw/LzwEntry.Async.cs
Normal file
20
src/SharpCompress/Common/Lzw/LzwEntry.Async.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace SharpCompress.Common.Lzw;
|
||||
|
||||
public partial class LzwEntry
|
||||
{
|
||||
internal static async IAsyncEnumerable<LzwEntry> GetEntriesAsync(
|
||||
Stream stream,
|
||||
OptionsBase options,
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
yield return new LzwEntry(
|
||||
await LzwFilePart.CreateAsync(stream, options.ArchiveEncoding, cancellationToken)
|
||||
);
|
||||
}
|
||||
}
|
||||
47
src/SharpCompress/Common/Lzw/LzwEntry.cs
Normal file
47
src/SharpCompress/Common/Lzw/LzwEntry.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Common.Lzw;
|
||||
|
||||
public partial class LzwEntry : Entry
|
||||
{
|
||||
private readonly LzwFilePart? _filePart;
|
||||
|
||||
internal LzwEntry(LzwFilePart? filePart) => _filePart = filePart;
|
||||
|
||||
public override CompressionType CompressionType => CompressionType.Lzw;
|
||||
|
||||
public override long Crc => 0;
|
||||
|
||||
public override string? Key => _filePart?.FilePartName;
|
||||
|
||||
public override string? LinkTarget => null;
|
||||
|
||||
public override long CompressedSize => 0;
|
||||
|
||||
public override long Size => 0;
|
||||
|
||||
public override DateTime? LastModifiedTime => null;
|
||||
|
||||
public override DateTime? CreatedTime => null;
|
||||
|
||||
public override DateTime? LastAccessedTime => null;
|
||||
|
||||
public override DateTime? ArchivedTime => null;
|
||||
|
||||
public override bool IsEncrypted => false;
|
||||
|
||||
public override bool IsDirectory => false;
|
||||
|
||||
public override bool IsSplitAfter => false;
|
||||
|
||||
internal override IEnumerable<FilePart> Parts => _filePart.Empty();
|
||||
|
||||
internal static IEnumerable<LzwEntry> GetEntries(Stream stream, OptionsBase options)
|
||||
{
|
||||
yield return new LzwEntry(LzwFilePart.Create(stream, options.ArchiveEncoding));
|
||||
}
|
||||
|
||||
// Async methods moved to LzwEntry.Async.cs
|
||||
}
|
||||
30
src/SharpCompress/Common/Lzw/LzwFilePart.Async.cs
Normal file
30
src/SharpCompress/Common/Lzw/LzwFilePart.Async.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpCompress.Common.Lzw;
|
||||
|
||||
internal sealed partial class LzwFilePart
|
||||
{
|
||||
internal static async ValueTask<LzwFilePart> CreateAsync(
|
||||
Stream stream,
|
||||
IArchiveEncoding archiveEncoding,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
var part = new LzwFilePart(stream, archiveEncoding);
|
||||
|
||||
if (stream.CanSeek)
|
||||
{
|
||||
part.EntryStartPosition = stream.Position;
|
||||
}
|
||||
else
|
||||
{
|
||||
// For non-seekable streams, we can't track position.
|
||||
// Set to 0 since the stream will be read sequentially from its current position.
|
||||
part.EntryStartPosition = 0;
|
||||
}
|
||||
return part;
|
||||
}
|
||||
}
|
||||
38
src/SharpCompress/Common/Lzw/LzwFilePart.cs
Normal file
38
src/SharpCompress/Common/Lzw/LzwFilePart.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Compressors.Lzw;
|
||||
|
||||
namespace SharpCompress.Common.Lzw;
|
||||
|
||||
internal sealed partial class LzwFilePart : FilePart
|
||||
{
|
||||
private readonly Stream _stream;
|
||||
|
||||
internal static LzwFilePart Create(Stream stream, IArchiveEncoding archiveEncoding)
|
||||
{
|
||||
var part = new LzwFilePart(stream, archiveEncoding);
|
||||
|
||||
if (stream.CanSeek)
|
||||
{
|
||||
part.EntryStartPosition = stream.Position;
|
||||
}
|
||||
else
|
||||
{
|
||||
// For non-seekable streams, we can't track position.
|
||||
// Set to 0 since the stream will be read sequentially from its current position.
|
||||
part.EntryStartPosition = 0;
|
||||
}
|
||||
return part;
|
||||
}
|
||||
|
||||
private LzwFilePart(Stream stream, IArchiveEncoding archiveEncoding)
|
||||
: base(archiveEncoding) => _stream = stream;
|
||||
|
||||
internal long EntryStartPosition { get; private set; }
|
||||
|
||||
internal override string? FilePartName => null;
|
||||
|
||||
internal override Stream GetCompressedStream() =>
|
||||
new LzwStream(_stream) { IsStreamOwner = false };
|
||||
|
||||
internal override Stream GetRawStream() => _stream;
|
||||
}
|
||||
17
src/SharpCompress/Common/Lzw/LzwVolume.cs
Normal file
17
src/SharpCompress/Common/Lzw/LzwVolume.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Common.Lzw;
|
||||
|
||||
public class LzwVolume : Volume
|
||||
{
|
||||
public LzwVolume(Stream stream, ReaderOptions? options, int index)
|
||||
: base(stream, options, index) { }
|
||||
|
||||
public LzwVolume(FileInfo fileInfo, ReaderOptions options)
|
||||
: base(fileInfo.OpenRead(), options) => options.LeaveStreamOpen = false;
|
||||
|
||||
public override bool IsFirstVolume => true;
|
||||
|
||||
public override bool IsMultiVolume => false;
|
||||
}
|
||||
@@ -18,6 +18,7 @@ public abstract class Factory : IFactory
|
||||
RegisterFactory(new RarFactory());
|
||||
RegisterFactory(new TarFactory()); //put tar before most
|
||||
RegisterFactory(new GZipFactory());
|
||||
RegisterFactory(new LzwFactory());
|
||||
RegisterFactory(new ArcFactory());
|
||||
RegisterFactory(new ArjFactory());
|
||||
RegisterFactory(new AceFactory());
|
||||
|
||||
67
src/SharpCompress/Factories/LzwFactory.cs
Normal file
67
src/SharpCompress/Factories/LzwFactory.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Compressors.Lzw;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.Lzw;
|
||||
|
||||
namespace SharpCompress.Factories;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the foundation factory of LZW archive.
|
||||
/// </summary>
|
||||
public class LzwFactory : Factory, IReaderFactory
|
||||
{
|
||||
#region IFactory
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string Name => "Lzw";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override ArchiveType? KnownArchiveType => ArchiveType.Lzw;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IEnumerable<string> GetSupportedExtensions()
|
||||
{
|
||||
yield return "z";
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool IsArchive(Stream stream, string? password = null) =>
|
||||
LzwStream.IsLzwStream(stream);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override ValueTask<bool> IsArchiveAsync(
|
||||
Stream stream,
|
||||
string? password = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new(IsArchive(stream, password));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IReaderFactory
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IReader OpenReader(Stream stream, ReaderOptions? options) =>
|
||||
LzwReader.OpenReader(stream, options);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
Stream stream,
|
||||
ReaderOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncReader)LzwReader.OpenReader(stream, options));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
15
src/SharpCompress/Readers/Lzw/LzwReader.Async.cs
Normal file
15
src/SharpCompress/Readers/Lzw/LzwReader.Async.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Lzw;
|
||||
|
||||
namespace SharpCompress.Readers.Lzw;
|
||||
|
||||
public partial class LzwReader
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns entries asynchronously for streams that only support async reads.
|
||||
/// </summary>
|
||||
protected override IAsyncEnumerable<LzwEntry> GetEntriesAsync(Stream stream) =>
|
||||
LzwEntry.GetEntriesAsync(stream, Options);
|
||||
}
|
||||
59
src/SharpCompress/Readers/Lzw/LzwReader.Factory.cs
Normal file
59
src/SharpCompress/Readers/Lzw/LzwReader.Factory.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace SharpCompress.Readers.Lzw;
|
||||
|
||||
public partial class LzwReader
|
||||
#if NET8_0_OR_GREATER
|
||||
: IReaderOpenable
|
||||
#endif
|
||||
{
|
||||
public static IAsyncReader OpenAsyncReader(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
path.NotNullOrEmpty(nameof(path));
|
||||
return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions);
|
||||
}
|
||||
|
||||
public static IAsyncReader OpenAsyncReader(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IAsyncReader)OpenReader(stream, readerOptions);
|
||||
}
|
||||
|
||||
public static IAsyncReader OpenAsyncReader(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IAsyncReader)OpenReader(fileInfo, readerOptions);
|
||||
}
|
||||
|
||||
public static IReader OpenReader(string filePath, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
filePath.NotNullOrEmpty(nameof(filePath));
|
||||
return OpenReader(new FileInfo(filePath), readerOptions);
|
||||
}
|
||||
|
||||
public static IReader OpenReader(FileInfo fileInfo, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
fileInfo.NotNull(nameof(fileInfo));
|
||||
return OpenReader(fileInfo.OpenRead(), readerOptions);
|
||||
}
|
||||
|
||||
public static IReader OpenReader(Stream stream, ReaderOptions? options = null)
|
||||
{
|
||||
stream.NotNull(nameof(stream));
|
||||
return new LzwReader(stream, options ?? new ReaderOptions());
|
||||
}
|
||||
}
|
||||
19
src/SharpCompress/Readers/Lzw/LzwReader.cs
Normal file
19
src/SharpCompress/Readers/Lzw/LzwReader.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Lzw;
|
||||
|
||||
namespace SharpCompress.Readers.Lzw;
|
||||
|
||||
public partial class LzwReader : AbstractReader<LzwEntry, LzwVolume>
|
||||
{
|
||||
private LzwReader(Stream stream, ReaderOptions options)
|
||||
: base(options, ArchiveType.Lzw) => Volume = new LzwVolume(stream, options, 0);
|
||||
|
||||
public override LzwVolume Volume { get; }
|
||||
|
||||
protected override IEnumerable<LzwEntry> GetEntries(Stream stream) =>
|
||||
LzwEntry.GetEntries(stream, Options);
|
||||
|
||||
// GetEntriesAsync moved to LzwReader.Async.cs
|
||||
}
|
||||
@@ -77,7 +77,7 @@ public static partial class ReaderFactory
|
||||
}
|
||||
|
||||
throw new InvalidFormatException(
|
||||
"Cannot determine compressed stream type. Supported Reader Formats: Ace, Arc, Arj, Zip, GZip, BZip2, Tar, Rar, LZip, XZ, ZStandard"
|
||||
"Cannot determine compressed stream type. Supported Reader Formats: Ace, Arc, Arj, Zip, GZip, BZip2, Tar, Rar, LZip, Lzw, XZ, ZStandard"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
15
tests/SharpCompress.Test/Lzw/LzwReaderAsyncTests.cs
Normal file
15
tests/SharpCompress.Test/Lzw/LzwReaderAsyncTests.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using SharpCompress.Common;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpCompress.Test.Lzw;
|
||||
|
||||
public class LzwReaderAsyncTests : ReaderTests
|
||||
{
|
||||
public LzwReaderAsyncTests() => UseExtensionInsteadOfNameToVerify = true;
|
||||
|
||||
[Fact]
|
||||
public async System.Threading.Tasks.Task Lzw_Reader_Async()
|
||||
{
|
||||
await ReadAsync("Tar.tar.Z", CompressionType.Lzw);
|
||||
}
|
||||
}
|
||||
41
tests/SharpCompress.Test/Lzw/LzwReaderTests.cs
Normal file
41
tests/SharpCompress.Test/Lzw/LzwReaderTests.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.Lzw;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpCompress.Test.Lzw;
|
||||
|
||||
public class LzwReaderTests : ReaderTests
|
||||
{
|
||||
public LzwReaderTests() => UseExtensionInsteadOfNameToVerify = true;
|
||||
|
||||
[Fact]
|
||||
public void Lzw_Reader_Generic() => Read("Tar.tar.Z", CompressionType.Lzw);
|
||||
|
||||
[Fact]
|
||||
public void Lzw_Reader_Generic2()
|
||||
{
|
||||
//read only as Lzw item
|
||||
using Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.Z"));
|
||||
using var reader = LzwReader.OpenReader(SharpCompressStream.CreateNonDisposing(stream));
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
// LZW doesn't have CRC or Size in header like GZip, so we just check the entry exists
|
||||
Assert.NotNull(reader.Entry);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Lzw_Reader_Factory_Detects_Format()
|
||||
{
|
||||
using Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.Z"));
|
||||
using var reader = ReaderFactory.OpenReader(
|
||||
stream,
|
||||
new ReaderOptions { LeaveStreamOpen = false }
|
||||
);
|
||||
Assert.True(reader.MoveToNextEntry());
|
||||
Assert.NotNull(reader.Entry);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user