165 lines
5.2 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|