ContentReader for Compressed (+read content for provider)
This commit is contained in:
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace FileTime.Tools.VirtualDiskSources;
|
||||
|
||||
public class DiscUtilsInitializer : IPreStartupHandler
|
||||
public sealed class DiscUtilsInitializer : IPreStartupHandler
|
||||
{
|
||||
public Task InitAsync()
|
||||
{
|
||||
|
||||
@@ -5,43 +5,40 @@ using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Tools.VirtualDiskSources;
|
||||
|
||||
public class VirtualDiskContentProvider : SubContentProviderBase, IVirtualDiskContentProvider
|
||||
public sealed class VirtualDiskContentProvider : SubContentProviderBase, IVirtualDiskContentProvider
|
||||
{
|
||||
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||
|
||||
public VirtualDiskContentProvider(
|
||||
IContentProvider parentContentProvider,
|
||||
ITimelessContentProvider timelessContentProvider,
|
||||
IContentAccessorFactory contentAccessorFactory)
|
||||
: base(parentContentProvider, "virtual-disk", timelessContentProvider)
|
||||
IContentAccessorFactory contentAccessorFactory,
|
||||
IContentProvider parentContentProvider)
|
||||
: base(
|
||||
timelessContentProvider,
|
||||
contentAccessorFactory,
|
||||
parentContentProvider,
|
||||
"virtual-disk"
|
||||
)
|
||||
{
|
||||
_contentAccessorFactory = contentAccessorFactory;
|
||||
}
|
||||
|
||||
public override async Task<byte[]?> GetContentAsync(IElement element, int? maxLength = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var elementNativePath = element.NativePath!;
|
||||
|
||||
var supportedPath = await ParentContentProvider.GetSupportedPathPart(elementNativePath);
|
||||
if (supportedPath is null) return null;
|
||||
|
||||
var parentItem = await ParentContentProvider.GetItemByNativePathAsync(supportedPath, element.PointInTime);
|
||||
if (parentItem is not IElement parentElement) return null;
|
||||
|
||||
var contentReaderFactory = _contentAccessorFactory.GetContentReaderFactory(parentElement.Provider);
|
||||
var reader = await contentReaderFactory.CreateContentReaderAsync(parentElement);
|
||||
|
||||
var parentElementContext = await GetParentElementReaderAsync(element);
|
||||
var reader = parentElementContext.ContentReader;
|
||||
var subPath = parentElementContext.SubNativePath.Path;
|
||||
|
||||
await using var readerStream = reader.AsStream();
|
||||
using var discReader = new UdfReader(readerStream);
|
||||
|
||||
var subPath = elementNativePath.Path.Substring(supportedPath.Path.Length + 2 + Constants.SubContentProviderRootContainer.Length);
|
||||
var fileInfo = discReader.GetFileInfo(subPath);
|
||||
|
||||
await using var contentReader = fileInfo.Open(FileMode.Open, FileAccess.Read);
|
||||
var data = new byte[1024 * 1024];
|
||||
var readAsync = await contentReader.ReadAsync(data, cancellationToken);
|
||||
|
||||
return data[0..readAsync].ToArray();
|
||||
return data[..readAsync].ToArray();
|
||||
}
|
||||
|
||||
public override VolumeSizeInfo? GetVolumeSizeInfo(FullName path)
|
||||
|
||||
@@ -3,7 +3,7 @@ using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Tools.VirtualDiskSources;
|
||||
|
||||
public class VirtualDiskContentProviderFactory : IVirtualDiskContentProviderFactory
|
||||
public sealed class VirtualDiskContentProviderFactory : IVirtualDiskContentProviderFactory
|
||||
{
|
||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||
@@ -17,5 +17,5 @@ public class VirtualDiskContentProviderFactory : IVirtualDiskContentProviderFact
|
||||
}
|
||||
|
||||
public IVirtualDiskContentProvider Create(IContentProvider parentContentProvider)
|
||||
=> new VirtualDiskContentProvider(parentContentProvider, _timelessContentProvider, _contentAccessorFactory);
|
||||
=> new VirtualDiskContentProvider(_timelessContentProvider, _contentAccessorFactory, parentContentProvider);
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace FileTime.Tools.VirtualDiskSources;
|
||||
|
||||
public class VirtualDiskContentReader : IContentReader
|
||||
public sealed class VirtualDiskContentReader : IContentReader
|
||||
{
|
||||
private readonly Stream _stream;
|
||||
private readonly ICollection<IDisposable> _disposables;
|
||||
|
||||
@@ -4,37 +4,28 @@ using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.Tools.VirtualDiskSources;
|
||||
|
||||
public class VirtualDiskContentReaderFactory : IContentReaderFactory<VirtualDiskContentProvider>
|
||||
public sealed class VirtualDiskContentReaderFactory : SubContentReaderBase<VirtualDiskContentProvider>
|
||||
{
|
||||
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||
|
||||
public VirtualDiskContentReaderFactory(IContentAccessorFactory contentAccessorFactory)
|
||||
public VirtualDiskContentReaderFactory(IContentAccessorFactory contentAccessorFactory)
|
||||
: base(contentAccessorFactory)
|
||||
{
|
||||
_contentAccessorFactory = contentAccessorFactory;
|
||||
}
|
||||
|
||||
public async Task<IContentReader> CreateContentReaderAsync(IElement element)
|
||||
public override async Task<IContentReader> CreateContentReaderAsync(IElement element)
|
||||
{
|
||||
if (element.Provider is not VirtualDiskContentProvider provider)
|
||||
throw new ArgumentException(
|
||||
"Provider must be VirtualDiskContentProvider, but it is " + element.Provider.GetType(),
|
||||
$"Provider must be {nameof(VirtualDiskContentProvider)}, but it is " + element.Provider.GetType(),
|
||||
nameof(element));
|
||||
|
||||
var elementNativePath = element.NativePath!;
|
||||
|
||||
var supportedPath = (await provider.ParentContentProvider.GetSupportedPathPart(elementNativePath))!;
|
||||
|
||||
var parentElement = (IElement) await provider.ParentContentProvider.GetItemByNativePathAsync(supportedPath, element.PointInTime);
|
||||
|
||||
|
||||
var contentReaderFactory = _contentAccessorFactory.GetContentReaderFactory(parentElement.Provider);
|
||||
var reader = await contentReaderFactory.CreateContentReaderAsync(parentElement);
|
||||
|
||||
var parentElementReaderContext = await GetParentElementReaderAsync(element, provider);
|
||||
var reader = parentElementReaderContext.ContentReader;
|
||||
var subPath = parentElementReaderContext.SubNativePath;
|
||||
|
||||
var readerStream = reader.AsStream();
|
||||
var discReader = new UdfReader(readerStream);
|
||||
|
||||
var subPath = elementNativePath.Path.Substring(supportedPath.Path.Length + 2 + Constants.SubContentProviderRootContainer.Length);
|
||||
var fileInfo = discReader.GetFileInfo(subPath);
|
||||
var fileInfo = discReader.GetFileInfo(subPath.Path);
|
||||
|
||||
var contentReader = fileInfo.Open(FileMode.Open, FileAccess.Read);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Tools.VirtualDiskSources;
|
||||
|
||||
public class VirtualDiskSubContentProvider : IVirtualDiskSubContentProvider
|
||||
public sealed class VirtualDiskSubContentProvider : IVirtualDiskSubContentProvider
|
||||
{
|
||||
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||
|
||||
Reference in New Issue
Block a user