feyris-tan ef86554f9a Import
2025-05-12 22:09:16 +02:00

165 lines
5.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.DsmCc.Message;
using skyscraper5.Dvb.DataBroadcasting.Biop;
namespace skyscraper5.Dvb.DataBroadcasting
{
internal class ModuleInfoStream : Stream
{
public ModuleInfoStream(ModuleInfo mi, bool allowDispose)
{
this.myModule = mi;
this.myModuleLength = mi.Blocks.Select(x => x.BlockData.Length).Sum();
this.allowDispose = allowDispose;
}
private bool allowDispose;
private ModuleInfo myModule;
private long currentPosition;
private long myModuleLength;
public override void Flush()
{
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int GetRequiredBlockId(long position)
{
for (int i = 0; i < myModule.Blocks.Length; i++)
{
if (myModule.Blocks[i].BlockData.Length > position)
{
return i;
}
position -= myModule.Blocks[i].BlockData.Length;
}
throw new ArgumentOutOfRangeException(nameof(position));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int GetOffsetInBlock(long position)
{
for (int i = 0; i < myModule.Blocks.Length; i++)
{
if (myModule.Blocks[i].BlockData.Length > position)
{
return (int)position;
}
position -= myModule.Blocks[i].BlockData.Length;
}
throw new ArgumentOutOfRangeException(nameof(position));
}
public override int Read(byte[] buffer, int offset, int count)
{
if (closed)
{
throw new ObjectDisposedException("This module is already disposed.");
}
if (Position + count > Length)
{
count = (int)(Length - Position);
}
if (Position == Length)
return 0;
int requiredBlockId = GetRequiredBlockId(currentPosition);
int offsetInBlock = GetOffsetInBlock(currentPosition);
int remainingInBlock = myModule.Blocks[requiredBlockId].BlockData.Length - offsetInBlock;
int bytesToCopy = Math.Min(remainingInBlock, count);
int stillNeededToCopy = count - bytesToCopy;
Array.Copy(myModule.Blocks[requiredBlockId].BlockData, offsetInBlock, buffer, offset, bytesToCopy);
Position += bytesToCopy;
int result = bytesToCopy;
offset += bytesToCopy;
count -= bytesToCopy;
while (stillNeededToCopy > 0)
{
requiredBlockId++;
offsetInBlock = 0;
remainingInBlock = myModule.Blocks[requiredBlockId].BlockData.Length - offsetInBlock;
bytesToCopy = Math.Min(remainingInBlock, count);
stillNeededToCopy = count - bytesToCopy;
Array.Copy(myModule.Blocks[requiredBlockId].BlockData, offsetInBlock, buffer, offset, bytesToCopy);
Position += bytesToCopy;
result += bytesToCopy;
offset += bytesToCopy;
count -= bytesToCopy;
}
return result;
}
public override long Seek(long offset, SeekOrigin origin)
{
switch (origin)
{
case SeekOrigin.Begin:
currentPosition = offset;
break;
case SeekOrigin.Current:
currentPosition += offset;
break;
case SeekOrigin.End:
currentPosition = Length + offset;
break;
default:
throw new NotImplementedException(origin.ToString());
}
return currentPosition;
}
public override void SetLength(long value)
{
throw new NotSupportedException("Can't modify the length of a ModuleInfo");
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException("Can't write to a ModuleInfo");
}
public override bool CanRead => true;
public override bool CanSeek => true;
public override bool CanWrite => false;
public override long Length => myModuleLength;
public override long Position
{
get => currentPosition;
set => Seek(value, SeekOrigin.Begin);
}
public override bool CanTimeout => false;
private bool closed;
public override void Close()
{
closed = true;
for (int i = 0; i < myModule.Blocks.Length; i++)
{
if (myModule.Blocks[i] != null)
{
myModule.Blocks[i].ForgetBlock();
myModule.Blocks[i] = null;
}
}
}
}
}