|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Buffers;
using System.Diagnostics;
using System.IO;
using System.Text;
using Microsoft.Build.Shared;
namespace Microsoft.Build.Logging
{
internal static class StreamExtensions
{
private static bool CheckIsSkipNeeded(long bytesCount)
{
if (bytesCount is < 0 or > int.MaxValue)
{
throw new ArgumentOutOfRangeException(nameof(bytesCount), ResourceUtilities.FormatResourceStringStripCodeAndKeyword("Binlog_StreamUtils_UnsupportedSkipOffset",
bytesCount));
}
return bytesCount > 0;
}
public static long SkipBytes(this Stream stream, long bytesCount)
{
if (!CheckIsSkipNeeded(bytesCount))
{
return 0;
}
byte[] buffer = ArrayPool<byte>.Shared.Rent(4096);
using var _ = new CleanupScope(() => ArrayPool<byte>.Shared.Return(buffer));
return SkipBytes(stream, bytesCount, buffer);
}
public static long SkipBytes(this Stream stream, long bytesCount, byte[] buffer)
{
if (!CheckIsSkipNeeded(bytesCount))
{
return 0;
}
long totalRead = 0;
while (totalRead < bytesCount)
{
int read = stream.Read(buffer, 0, (int)Math.Min(bytesCount - totalRead, buffer.Length));
if (read == 0)
{
throw new InvalidDataException("Unexpected end of stream.");
}
totalRead += read;
}
return totalRead;
}
public static byte[] ReadToEnd(this Stream stream)
{
MemoryStream ms = stream.TryGetLength(out long length) && length <= int.MaxValue ? new((int)length) : new();
stream.CopyTo(ms);
byte[] buffer = ms.GetBuffer();
return buffer.Length == ms.Length ? buffer : ms.ToArray();
}
public static bool TryGetLength(this Stream stream, out long length)
{
try
{
if (stream.CanSeek)
{
length = stream.Length;
return true;
}
}
catch (NotSupportedException)
{
}
length = 0;
return false;
}
public static Stream ToReadableSeekableStream(this Stream stream)
{
return TransparentReadStream.EnsureSeekableStream(stream);
}
/// <summary>
/// Creates bounded read-only, forward-only view over an underlying stream.
/// </summary>
/// <param name="stream"></param>
/// <param name="length"></param>
/// <returns></returns>
public static Stream Slice(this Stream stream, long length)
{
return new SubStream(stream, length);
}
}
}
|