BililiveRecorder/BililiveRecorder.Flv/StreamExtensions.cs

131 lines
4.3 KiB
C#
Raw Permalink Normal View History

2021-02-08 16:51:19 +08:00
using System;
using System.IO;
2021-05-12 22:38:39 +08:00
using System.Runtime.CompilerServices;
2021-02-08 16:51:19 +08:00
using System.Threading;
using System.Threading.Tasks;
namespace BililiveRecorder.Flv
{
internal static class StreamExtensions
{
private const int BUFFER_SIZE = 4 * 1024;
private static readonly ThreadLocal<byte[]> t_buffer = new ThreadLocal<byte[]>(() => new byte[BUFFER_SIZE]);
internal static async Task<int> SkipBytesAsync(this Stream stream, int length)
{
if (length < 0) { throw new ArgumentOutOfRangeException("length must be non-negative"); }
if (length == 0) { return 0; }
if (null == stream) { throw new ArgumentNullException(nameof(stream)); }
if (!stream.CanRead) { throw new ArgumentException("cannot read stream", nameof(stream)); }
if (stream.CanSeek)
{
if (stream.Length - stream.Position >= length)
{
stream.Position += length;
return length;
}
return 0;
}
var buffer = t_buffer.Value!;
var total = 0;
while (length > BUFFER_SIZE)
{
var read = await stream.ReadAsync(buffer, 0, BUFFER_SIZE);
total += read;
if (read != BUFFER_SIZE) { return total; }
length -= BUFFER_SIZE;
}
total += await stream.ReadAsync(buffer, 0, length);
return total;
}
internal static async Task<bool> CopyBytesAsync(this Stream from, Stream to, long length)
{
if (null == from) { throw new ArgumentNullException(nameof(from)); }
if (null == to) { throw new ArgumentNullException(nameof(to)); }
if (length < 0) { throw new ArgumentOutOfRangeException("length must be non-negative"); }
if (length == 0) { return true; }
if (!from.CanRead) { throw new ArgumentException("cannot read stream", nameof(from)); }
if (!to.CanWrite) { throw new ArgumentException("cannot write stream", nameof(to)); }
var buffer = t_buffer.Value!;
while (length > BUFFER_SIZE)
{
if (BUFFER_SIZE != await from.ReadAsync(buffer, 0, BUFFER_SIZE))
{
return false;
}
await to.WriteAsync(buffer, 0, BUFFER_SIZE);
length -= BUFFER_SIZE;
}
if (length != await from.ReadAsync(buffer, 0, (int)length))
{
return false;
}
await to.WriteAsync(buffer, 0, (int)length);
return true;
}
internal static async Task<bool> CopyBytesAsync(this Stream stream, byte[] target)
{
if (null == stream) { throw new ArgumentNullException(nameof(stream)); }
if (null == target) { throw new ArgumentNullException(nameof(target)); }
if (!stream.CanRead) { throw new ArgumentException("cannot read stream", nameof(stream)); }
if (target.Length < 1) return true;
var head = 0;
while (head < target.Length)
{
var read = await stream.ReadAsync(target, head, target.Length - head);
head += read;
if (read == 0)
return false;
}
return true;
}
internal static byte[] ToBE(this byte[] b)
{
if (BitConverter.IsLittleEndian)
{
Array.Reverse(b);
}
return b;
}
2021-05-12 22:38:39 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2021-02-08 16:51:19 +08:00
internal static void Write(this Stream stream, byte[] bytes) => stream.Write(bytes, 0, bytes.Length);
internal static bool SequenceEqual(this Stream self, Stream? other)
{
if (self is null)
throw new ArgumentNullException(nameof(self));
if (self == other)
return true;
if (self.Length != (other?.Length ?? -1))
return false;
self.Seek(0, SeekOrigin.Begin);
other!.Seek(0, SeekOrigin.Begin);
int b;
while ((b = self.ReadByte()) != -1)
if (b != other!.ReadByte())
return false;
return true;
}
}
}