using System; using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; namespace StellaOps.Concelier.Exporter.TrivyDb; public sealed class TrivyDbBlob { private readonly Func> _openReadAsync; private TrivyDbBlob(Func> openReadAsync, long length) { _openReadAsync = openReadAsync ?? throw new ArgumentNullException(nameof(openReadAsync)); if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } Length = length; } public long Length { get; } public ValueTask OpenReadAsync(CancellationToken cancellationToken) => _openReadAsync(cancellationToken); public static TrivyDbBlob FromBytes(ReadOnlyMemory payload) { if (payload.IsEmpty) { return new TrivyDbBlob(static _ => ValueTask.FromResult(Stream.Null), 0); } if (MemoryMarshal.TryGetArray(payload, out ArraySegment segment) && segment.Array is not null && segment.Offset == 0) { return FromArray(segment.Array); } return FromArray(payload.ToArray()); } public static TrivyDbBlob FromFile(string path, long length) { if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentException("File path must be provided.", nameof(path)); } if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } return new TrivyDbBlob( cancellationToken => ValueTask.FromResult(new FileStream( path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 81920, options: FileOptions.Asynchronous | FileOptions.SequentialScan)), length); } public static TrivyDbBlob FromArray(byte[] buffer) { if (buffer is null) { throw new ArgumentNullException(nameof(buffer)); } return new TrivyDbBlob( _ => ValueTask.FromResult(new MemoryStream(buffer, writable: false)), buffer.LongLength); } }