ContentReader for Compressed (+read content for provider)

This commit is contained in:
2023-09-05 22:24:25 +02:00
parent e6fd8d4ab5
commit def5ece688
15 changed files with 195 additions and 57 deletions

View File

@@ -1,22 +1,42 @@
using System.Text;
using FileTime.Core.ContentAccess;
using FileTime.Core.ContentAccess;
using FileTime.Core.Models;
using FileTime.Core.Timeline;
using SharpCompress.Archives;
namespace FileTime.Tools.Compression.ContentProvider;
public class CompressedContentProvider : SubContentProviderBase, ICompressedContentProvider
public sealed class CompressedContentProvider : SubContentProviderBase, ICompressedContentProvider
{
public CompressedContentProvider(
IContentProvider parentContentProvider,
ITimelessContentProvider timelessContentProvider
ITimelessContentProvider timelessContentProvider,
IContentAccessorFactory contentAccessorFactory,
IContentProvider parentContentProvider
)
: base(parentContentProvider, "compression", timelessContentProvider)
: base(
timelessContentProvider,
contentAccessorFactory,
parentContentProvider,
"compression")
{
}
public override Task<byte[]?> GetContentAsync(IElement element, int? maxLength = null, CancellationToken cancellationToken = default)
=> Task.FromResult((byte[]?)"Not implemented..."u8.ToArray());
public override async Task<byte[]?> GetContentAsync(IElement element, int? maxLength = null, CancellationToken cancellationToken = default)
{
var parentElementContext = await GetParentElementReaderAsync(element);
var reader = parentElementContext.ContentReader;
var subPath = parentElementContext.SubNativePath.Path;
await using var readerStream = reader.AsStream();
using var archive = ArchiveFactory.Open(readerStream);
var entry = archive.Entries.First(e => e.Key == subPath);
await using var contentReader= entry.OpenEntryStream();
var data = new byte[1024 * 1024];
var readAsync = await contentReader.ReadAsync(data, cancellationToken);
return data[..readAsync].ToArray();
}
public override VolumeSizeInfo? GetVolumeSizeInfo(FullName path) => throw new NotImplementedException();
}

View File

@@ -3,17 +3,19 @@ using FileTime.Core.Timeline;
namespace FileTime.Tools.Compression.ContentProvider;
public class CompressedContentProviderFactory : ICompressedContentProviderFactory
public sealed class CompressedContentProviderFactory : ICompressedContentProviderFactory
{
private readonly ITimelessContentProvider _timelessContentProvider;
private readonly IContentAccessorFactory _contentAccessorFactory;
public CompressedContentProviderFactory(ITimelessContentProvider timelessContentProvider)
public CompressedContentProviderFactory(
ITimelessContentProvider timelessContentProvider,
IContentAccessorFactory contentAccessorFactory)
{
_timelessContentProvider = timelessContentProvider;
_contentAccessorFactory = contentAccessorFactory;
}
public ICompressedContentProvider Create(IContentProvider parentContentProvider)
{
return new CompressedContentProvider(parentContentProvider, _timelessContentProvider);
}
public ICompressedContentProvider Create(IContentProvider parentContentProvider)
=> new CompressedContentProvider(_timelessContentProvider, _contentAccessorFactory, parentContentProvider);
}

View File

@@ -0,0 +1,40 @@
using FileTime.Core.ContentAccess;
using SharpCompress.Archives;
namespace FileTime.Tools.Compression.ContentProvider;
public sealed class CompressedContentReader : IContentReader
{
private readonly IDisposable[] _disposables;
private readonly Stream _stream;
public int PreferredBufferSize => 1024 * 1024;
public long? Position => _stream.Position;
public CompressedContentReader(IArchiveEntry entry, IDisposable[] disposables)
{
_disposables = disposables;
_stream = entry.OpenEntryStream();
}
public void Dispose()
{
_stream.Dispose();
foreach (var disposable in _disposables)
{
disposable.Dispose();
}
}
public async Task<byte[]> ReadBytesAsync(int bufferSize, int? offset = null)
{
var data = new byte[bufferSize];
var read = await _stream.ReadAsync(data, offset ?? 0, bufferSize);
return data[..read].ToArray();
}
public void SetPosition(long position) => _stream.Seek(position, SeekOrigin.Begin);
public Stream AsStream() => _stream;
}

View File

@@ -0,0 +1,34 @@
using FileTime.Core.ContentAccess;
using FileTime.Core.Models;
using SharpCompress.Archives;
namespace FileTime.Tools.Compression.ContentProvider;
public sealed class CompressedContentReaderFactory : SubContentReaderBase<CompressedContentProvider>
{
public CompressedContentReaderFactory(IContentAccessorFactory contentAccessorFactory)
: base(contentAccessorFactory)
{
}
public override async Task<IContentReader> CreateContentReaderAsync(IElement element)
{
if (element.Provider is not CompressedContentProvider provider)
throw new ArgumentException(
$"Provider must be {nameof(CompressedContentProvider)}, but it is " + element.Provider.GetType(),
nameof(element));
var parentElementReaderContext = await GetParentElementReaderAsync(element, provider);
var reader = parentElementReaderContext.ContentReader;
var subPath = parentElementReaderContext.SubNativePath;
var readerStream = reader.AsStream();
var archive = ArchiveFactory.Open(readerStream);
var entry = archive.Entries.First(e => e.Key == subPath.Path);
var disposables = new IDisposable[] {archive, readerStream};
return new CompressedContentReader(entry, disposables);
}
}

View File

@@ -28,6 +28,7 @@ public static class Startup
services.AddSingleton<IUserCommandHandler, CompressionUserCommandHandler>();
services.TryAddSingleton<ICompressedContentProviderFactory, CompressedContentProviderFactory>();
services.AddSingleton<ISubContentProvider, CompressedSubContentProvider>();
services.TryAddSingleton<IContentReaderFactory<CompressedContentProvider>, CompressedContentReaderFactory>();
return services;
}
}