mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-07-08 18:16:30 +00:00
move some files around to make more sense
This commit is contained in:
108
src/SharpCompress/Polyfills/FileInfoExtensions.cs
Normal file
108
src/SharpCompress/Polyfills/FileInfoExtensions.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace SharpCompress;
|
||||
|
||||
public static class FileInfoExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Opens a file stream for asynchronous writing.
|
||||
/// Uses File.OpenHandle with FileOptions.Asynchronous on .NET 8.0+ for optimal performance.
|
||||
/// Falls back to FileStream constructor with async options on legacy frameworks.
|
||||
/// </summary>
|
||||
/// <param name="path">The file path to open.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A FileStream configured for asynchronous operations.</returns>
|
||||
public static Stream OpenAsyncWriteStream(string path, CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
// Use File.OpenHandle with async options for .NET 8.0+
|
||||
var handle = File.OpenHandle(
|
||||
path,
|
||||
FileMode.Create,
|
||||
FileAccess.Write,
|
||||
FileShare.None,
|
||||
FileOptions.Asynchronous
|
||||
);
|
||||
return new FileStream(handle, FileAccess.Write);
|
||||
#else
|
||||
// For older target frameworks, use FileStream constructor with async options
|
||||
return new FileStream(
|
||||
path,
|
||||
FileMode.Create,
|
||||
FileAccess.Write,
|
||||
FileShare.None,
|
||||
bufferSize: 4096, //default
|
||||
FileOptions.Asynchronous
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a file stream for asynchronous reading.
|
||||
/// Uses File.OpenHandle with FileOptions.Asynchronous on .NET 8.0+ for optimal performance.
|
||||
/// Falls back to FileStream constructor with async options on legacy frameworks.
|
||||
/// </summary>
|
||||
/// <param name="path">The file path to open.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A FileStream configured for asynchronous operations.</returns>
|
||||
public static Stream OpenAsyncReadStream(string path, CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
// Use File.OpenHandle with async options for .NET 8.0+
|
||||
var handle = File.OpenHandle(
|
||||
path,
|
||||
FileMode.Open,
|
||||
FileAccess.Read,
|
||||
FileShare.Read,
|
||||
FileOptions.Asynchronous
|
||||
);
|
||||
return new FileStream(handle, FileAccess.Read);
|
||||
#else
|
||||
// For older target frameworks, use FileStream constructor with async options
|
||||
return new FileStream(
|
||||
path,
|
||||
FileMode.Open,
|
||||
FileAccess.Read,
|
||||
FileShare.Read,
|
||||
bufferSize: 4096,
|
||||
FileOptions.Asynchronous
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <param name="fileInfo">The FileInfo to open.</param>
|
||||
extension(FileInfo fileInfo)
|
||||
{
|
||||
/// <summary>
|
||||
/// Opens a file stream for asynchronous reading from a FileInfo.
|
||||
/// Uses File.OpenHandle with FileOptions.Asynchronous on .NET 8.0+ for optimal performance.
|
||||
/// Falls back to FileStream constructor with async options on legacy frameworks.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A FileStream configured for asynchronous operations.</returns>
|
||||
public Stream OpenAsyncReadStream(CancellationToken cancellationToken)
|
||||
{
|
||||
fileInfo.NotNull(nameof(fileInfo));
|
||||
return OpenAsyncReadStream(fileInfo.FullName, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a file stream for asynchronous writing from a FileInfo.
|
||||
/// Uses File.OpenHandle with FileOptions.Asynchronous on .NET 8.0+ for optimal performance.
|
||||
/// Falls back to FileStream constructor with async options on legacy frameworks.
|
||||
/// </summary>
|
||||
/// <param name="fileInfo">The FileInfo to open.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A FileStream configured for asynchronous operations.</returns>
|
||||
public Stream OpenAsyncWriteStream(CancellationToken cancellationToken)
|
||||
{
|
||||
fileInfo.NotNull(nameof(fileInfo));
|
||||
return OpenAsyncWriteStream(fileInfo.FullName, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
123
src/SharpCompress/Polyfills/StreamExtensions.Async.cs
Normal file
123
src/SharpCompress/Polyfills/StreamExtensions.Async.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress;
|
||||
|
||||
public static partial class StreamExtensions
|
||||
{
|
||||
extension(Stream source)
|
||||
{
|
||||
/// <summary>
|
||||
/// Read exactly the requested number of bytes from a stream asynchronously. Throws EndOfStreamException if not enough data is available.
|
||||
/// </summary>
|
||||
public async ValueTask ReadExactAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
int length,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
#if LEGACY_DOTNET
|
||||
if (source is null)
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
#else
|
||||
ThrowHelper.ThrowIfNull(source);
|
||||
#endif
|
||||
|
||||
ThrowHelper.ThrowIfNull(buffer);
|
||||
|
||||
if (offset < 0 || offset > buffer.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(offset));
|
||||
}
|
||||
|
||||
if (length < 0 || length > buffer.Length - offset)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(length));
|
||||
}
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
var fetched = await source
|
||||
.ReadAsync(buffer, offset, length, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (fetched <= 0)
|
||||
{
|
||||
throw new IncompleteArchiveException("Unexpected end of stream.");
|
||||
}
|
||||
|
||||
offset += fetched;
|
||||
length -= fetched;
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<long> TransferToAsync(
|
||||
Stream destination,
|
||||
long maxLength,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
// Use ReadOnlySubStream to limit reading and leverage framework's CopyToAsync
|
||||
using var limitedStream = new IO.ReadOnlySubStream(source, maxLength);
|
||||
await limitedStream
|
||||
.CopyToAsync(destination, Constants.BufferSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
return limitedStream.Position;
|
||||
}
|
||||
|
||||
public async ValueTask<bool> ReadFullyAsync(
|
||||
byte[] buffer,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var total = 0;
|
||||
int read;
|
||||
while (
|
||||
(
|
||||
read = await source
|
||||
.ReadAsync(buffer, total, buffer.Length - total, cancellationToken)
|
||||
.ConfigureAwait(false)
|
||||
) > 0
|
||||
)
|
||||
{
|
||||
total += read;
|
||||
if (total >= buffer.Length)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return (total >= buffer.Length);
|
||||
}
|
||||
|
||||
public async ValueTask<bool> ReadFullyAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
int count,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var total = 0;
|
||||
int read;
|
||||
while (
|
||||
(
|
||||
read = await source
|
||||
.ReadAsync(buffer, offset + total, count - total, cancellationToken)
|
||||
.ConfigureAwait(false)
|
||||
) > 0
|
||||
)
|
||||
{
|
||||
total += read;
|
||||
if (total >= count)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return (total >= count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,12 @@ using System.Buffers;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress;
|
||||
|
||||
public static class StreamExtensions
|
||||
public static partial class StreamExtensions
|
||||
{
|
||||
extension(Stream stream)
|
||||
{
|
||||
@@ -68,5 +69,146 @@ public static class StreamExtensions
|
||||
ArrayPool<byte>.Shared.Return(temp);
|
||||
}
|
||||
}
|
||||
|
||||
public long TransferTo(Stream destination, long maxLength)
|
||||
{
|
||||
// Use ReadOnlySubStream to limit reading and leverage framework's CopyTo
|
||||
using var limitedStream = new IO.ReadOnlySubStream(stream, maxLength);
|
||||
limitedStream.CopyTo(destination, Constants.BufferSize);
|
||||
return limitedStream.Position;
|
||||
}
|
||||
|
||||
public async ValueTask SkipAsync(
|
||||
long advanceAmount,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (stream.CanSeek && stream is not SharpCompressStream)
|
||||
{
|
||||
stream.Position += advanceAmount;
|
||||
return;
|
||||
}
|
||||
|
||||
var array = ArrayPool<byte>.Shared.Rent(Constants.BufferSize);
|
||||
try
|
||||
{
|
||||
while (advanceAmount > 0)
|
||||
{
|
||||
var toRead = (int)Math.Min(array.Length, advanceAmount);
|
||||
var read = await stream
|
||||
.ReadAsync(array, 0, toRead, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (read <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
advanceAmount -= read;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(array);
|
||||
}
|
||||
}
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
public bool ReadFully(byte[] buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
stream.ReadExactly(buffer);
|
||||
return true;
|
||||
}
|
||||
catch (EndOfStreamException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ReadFully(Span<byte> buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
stream.ReadExactly(buffer);
|
||||
return true;
|
||||
}
|
||||
catch (EndOfStreamException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
public bool ReadFully(byte[] buffer)
|
||||
{
|
||||
var total = 0;
|
||||
int read;
|
||||
while ((read = stream.Read(buffer, total, buffer.Length - total)) > 0)
|
||||
{
|
||||
total += read;
|
||||
if (total >= buffer.Length)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return (total >= buffer.Length);
|
||||
}
|
||||
|
||||
public bool ReadFully(Span<byte> buffer)
|
||||
{
|
||||
var total = 0;
|
||||
int read;
|
||||
while ((read = stream.Read(buffer.Slice(total, buffer.Length - total))) > 0)
|
||||
{
|
||||
total += read;
|
||||
if (total >= buffer.Length)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return (total >= buffer.Length);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Read exactly the requested number of bytes from a stream. Throws EndOfStreamException if not enough data is available.
|
||||
/// </summary>
|
||||
public void ReadExact(byte[] buffer, int offset, int length)
|
||||
{
|
||||
#if LEGACY_DOTNET
|
||||
if (stream is null)
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
#else
|
||||
ThrowHelper.ThrowIfNull(stream);
|
||||
#endif
|
||||
|
||||
ThrowHelper.ThrowIfNull(buffer);
|
||||
|
||||
if (offset < 0 || offset > buffer.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(offset));
|
||||
}
|
||||
|
||||
if (length < 0 || length > buffer.Length - offset)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(length));
|
||||
}
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
var fetched = stream.Read(buffer, offset, length);
|
||||
if (fetched <= 0)
|
||||
{
|
||||
throw new IncompleteArchiveException("Unexpected end of stream.");
|
||||
}
|
||||
|
||||
offset += fetched;
|
||||
length -= fetched;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,227 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress;
|
||||
|
||||
internal static partial class Utility
|
||||
{
|
||||
extension(Stream source)
|
||||
{
|
||||
/// <summary>
|
||||
/// Read exactly the requested number of bytes from a stream asynchronously. Throws EndOfStreamException if not enough data is available.
|
||||
/// </summary>
|
||||
public async ValueTask ReadExactAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
int length,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
#if LEGACY_DOTNET
|
||||
if (source is null)
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
#else
|
||||
ThrowHelper.ThrowIfNull(source);
|
||||
#endif
|
||||
|
||||
ThrowHelper.ThrowIfNull(buffer);
|
||||
|
||||
if (offset < 0 || offset > buffer.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(offset));
|
||||
}
|
||||
|
||||
if (length < 0 || length > buffer.Length - offset)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(length));
|
||||
}
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
var fetched = await source
|
||||
.ReadAsync(buffer, offset, length, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (fetched <= 0)
|
||||
{
|
||||
throw new IncompleteArchiveException("Unexpected end of stream.");
|
||||
}
|
||||
|
||||
offset += fetched;
|
||||
length -= fetched;
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<long> TransferToAsync(
|
||||
Stream destination,
|
||||
long maxLength,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
// Use ReadOnlySubStream to limit reading and leverage framework's CopyToAsync
|
||||
using var limitedStream = new IO.ReadOnlySubStream(source, maxLength);
|
||||
await limitedStream
|
||||
.CopyToAsync(destination, Constants.BufferSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
return limitedStream.Position;
|
||||
}
|
||||
|
||||
public async ValueTask<bool> ReadFullyAsync(
|
||||
byte[] buffer,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var total = 0;
|
||||
int read;
|
||||
while (
|
||||
(
|
||||
read = await source
|
||||
.ReadAsync(buffer, total, buffer.Length - total, cancellationToken)
|
||||
.ConfigureAwait(false)
|
||||
) > 0
|
||||
)
|
||||
{
|
||||
total += read;
|
||||
if (total >= buffer.Length)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return (total >= buffer.Length);
|
||||
}
|
||||
|
||||
public async ValueTask<bool> ReadFullyAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
int count,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var total = 0;
|
||||
int read;
|
||||
while (
|
||||
(
|
||||
read = await source
|
||||
.ReadAsync(buffer, offset + total, count - total, cancellationToken)
|
||||
.ConfigureAwait(false)
|
||||
) > 0
|
||||
)
|
||||
{
|
||||
total += read;
|
||||
if (total >= count)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return (total >= count);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a file stream for asynchronous writing.
|
||||
/// Uses File.OpenHandle with FileOptions.Asynchronous on .NET 8.0+ for optimal performance.
|
||||
/// Falls back to FileStream constructor with async options on legacy frameworks.
|
||||
/// </summary>
|
||||
/// <param name="path">The file path to open.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A FileStream configured for asynchronous operations.</returns>
|
||||
public static Stream OpenAsyncWriteStream(string path, CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
// Use File.OpenHandle with async options for .NET 8.0+
|
||||
var handle = File.OpenHandle(
|
||||
path,
|
||||
FileMode.Create,
|
||||
FileAccess.Write,
|
||||
FileShare.None,
|
||||
FileOptions.Asynchronous
|
||||
);
|
||||
return new FileStream(handle, FileAccess.Write);
|
||||
#else
|
||||
// For older target frameworks, use FileStream constructor with async options
|
||||
return new FileStream(
|
||||
path,
|
||||
FileMode.Create,
|
||||
FileAccess.Write,
|
||||
FileShare.None,
|
||||
bufferSize: 4096, //default
|
||||
FileOptions.Asynchronous
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a file stream for asynchronous writing from a FileInfo.
|
||||
/// Uses File.OpenHandle with FileOptions.Asynchronous on .NET 8.0+ for optimal performance.
|
||||
/// Falls back to FileStream constructor with async options on legacy frameworks.
|
||||
/// </summary>
|
||||
/// <param name="fileInfo">The FileInfo to open.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A FileStream configured for asynchronous operations.</returns>
|
||||
public static Stream OpenAsyncWriteStream(
|
||||
this FileInfo fileInfo,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
fileInfo.NotNull(nameof(fileInfo));
|
||||
return OpenAsyncWriteStream(fileInfo.FullName, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a file stream for asynchronous reading.
|
||||
/// Uses File.OpenHandle with FileOptions.Asynchronous on .NET 8.0+ for optimal performance.
|
||||
/// Falls back to FileStream constructor with async options on legacy frameworks.
|
||||
/// </summary>
|
||||
/// <param name="path">The file path to open.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A FileStream configured for asynchronous operations.</returns>
|
||||
public static Stream OpenAsyncReadStream(string path, CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
// Use File.OpenHandle with async options for .NET 8.0+
|
||||
var handle = File.OpenHandle(
|
||||
path,
|
||||
FileMode.Open,
|
||||
FileAccess.Read,
|
||||
FileShare.Read,
|
||||
FileOptions.Asynchronous
|
||||
);
|
||||
return new FileStream(handle, FileAccess.Read);
|
||||
#else
|
||||
// For older target frameworks, use FileStream constructor with async options
|
||||
return new FileStream(
|
||||
path,
|
||||
FileMode.Open,
|
||||
FileAccess.Read,
|
||||
FileShare.Read,
|
||||
bufferSize: 4096,
|
||||
FileOptions.Asynchronous
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a file stream for asynchronous reading from a FileInfo.
|
||||
/// Uses File.OpenHandle with FileOptions.Asynchronous on .NET 8.0+ for optimal performance.
|
||||
/// Falls back to FileStream constructor with async options on legacy frameworks.
|
||||
/// </summary>
|
||||
/// <param name="fileInfo">The FileInfo to open.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A FileStream configured for asynchronous operations.</returns>
|
||||
public static Stream OpenAsyncReadStream(
|
||||
this FileInfo fileInfo,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
fileInfo.NotNull(nameof(fileInfo));
|
||||
return OpenAsyncReadStream(fileInfo.FullName, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -138,150 +138,6 @@ internal static partial class Utility
|
||||
return sTime.AddSeconds(unixtime);
|
||||
}
|
||||
|
||||
extension(Stream source)
|
||||
{
|
||||
public long TransferTo(Stream destination, long maxLength)
|
||||
{
|
||||
// Use ReadOnlySubStream to limit reading and leverage framework's CopyTo
|
||||
using var limitedStream = new IO.ReadOnlySubStream(source, maxLength);
|
||||
limitedStream.CopyTo(destination, Constants.BufferSize);
|
||||
return limitedStream.Position;
|
||||
}
|
||||
|
||||
public async ValueTask SkipAsync(
|
||||
long advanceAmount,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (source.CanSeek && source is not SharpCompressStream)
|
||||
{
|
||||
source.Position += advanceAmount;
|
||||
return;
|
||||
}
|
||||
|
||||
var array = ArrayPool<byte>.Shared.Rent(Constants.BufferSize);
|
||||
try
|
||||
{
|
||||
while (advanceAmount > 0)
|
||||
{
|
||||
var toRead = (int)Math.Min(array.Length, advanceAmount);
|
||||
var read = await source
|
||||
.ReadAsync(array, 0, toRead, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (read <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
advanceAmount -= read;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(array);
|
||||
}
|
||||
}
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
public bool ReadFully(byte[] buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
source.ReadExactly(buffer);
|
||||
return true;
|
||||
}
|
||||
catch (EndOfStreamException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ReadFully(Span<byte> buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
source.ReadExactly(buffer);
|
||||
return true;
|
||||
}
|
||||
catch (EndOfStreamException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
public bool ReadFully(byte[] buffer)
|
||||
{
|
||||
var total = 0;
|
||||
int read;
|
||||
while ((read = source.Read(buffer, total, buffer.Length - total)) > 0)
|
||||
{
|
||||
total += read;
|
||||
if (total >= buffer.Length)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return (total >= buffer.Length);
|
||||
}
|
||||
|
||||
public bool ReadFully(Span<byte> buffer)
|
||||
{
|
||||
var total = 0;
|
||||
int read;
|
||||
while ((read = source.Read(buffer.Slice(total, buffer.Length - total))) > 0)
|
||||
{
|
||||
total += read;
|
||||
if (total >= buffer.Length)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return (total >= buffer.Length);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Read exactly the requested number of bytes from a stream. Throws EndOfStreamException if not enough data is available.
|
||||
/// </summary>
|
||||
public void ReadExact(byte[] buffer, int offset, int length)
|
||||
{
|
||||
#if LEGACY_DOTNET
|
||||
if (source is null)
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
#else
|
||||
ThrowHelper.ThrowIfNull(source);
|
||||
#endif
|
||||
|
||||
ThrowHelper.ThrowIfNull(buffer);
|
||||
|
||||
if (offset < 0 || offset > buffer.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(offset));
|
||||
}
|
||||
|
||||
if (length < 0 || length > buffer.Length - offset)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(length));
|
||||
}
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
var fetched = source.Read(buffer, offset, length);
|
||||
if (fetched <= 0)
|
||||
{
|
||||
throw new IncompleteArchiveException("Unexpected end of stream.");
|
||||
}
|
||||
|
||||
offset += fetched;
|
||||
length -= fetched;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string TrimNulls(this string source) => source.Replace('\0', ' ').Trim();
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user