241 lines
6.8 KiB
C#
241 lines
6.8 KiB
C#
using skyscraper5.Mpeg2;
|
|
using skyscraper5.Skyscraper;
|
|
using skyscraper5.Skyscraper.IO;
|
|
using skyscraper5.src.InteractionChannel.Model.Descriptors;
|
|
using skyscraper5.src.Skyscraper.Scraper.Storage.Utilities;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace skyscraper5.src.InteractionChannel.Model
|
|
{
|
|
public class Rmt : Validatable
|
|
{
|
|
private static TsDescriptorUnpacker tsDescriptorUnpacker;
|
|
|
|
public Rmt(MemoryStream ms, bool gseMode = false)
|
|
{
|
|
if (tsDescriptorUnpacker == null)
|
|
tsDescriptorUnpacker = TsDescriptorUnpacker.GetInstance();
|
|
|
|
if (!gseMode)
|
|
{
|
|
byte tableId = ms.ReadUInt8();
|
|
if (tableId != 0x41)
|
|
{
|
|
Valid = false;
|
|
return;
|
|
}
|
|
|
|
byte byteA = ms.ReadUInt8();
|
|
bool sectionSyntaxIndicator = (byteA & 0x80) != 1;
|
|
if (!sectionSyntaxIndicator)
|
|
{
|
|
Valid = false;
|
|
return;
|
|
}
|
|
|
|
bool reservedFutureUse = (byteA & 0x40) != 1;
|
|
int reserved = (byteA & 0x30) >> 4;
|
|
|
|
int sectionLength = (byteA & 0x0f);
|
|
sectionLength <<= 8;
|
|
sectionLength += ms.ReadUInt8();
|
|
if (sectionLength != ms.GetAvailableBytes())
|
|
{
|
|
Valid = false;
|
|
return;
|
|
}
|
|
|
|
NetworkId = ms.ReadUInt16BE();
|
|
|
|
byte byteB = ms.ReadUInt8();
|
|
reserved = (byteB & 0xc0) >> 6;
|
|
int versionNumber = (byteB & 0x3e) >> 1;
|
|
bool currentNextIndicator = (byteB & 0x01) != 0;
|
|
|
|
byte sectionNumber = ms.ReadUInt8();
|
|
byte lastSectionNumber = ms.ReadUInt8();
|
|
}
|
|
|
|
byte byteC = ms.ReadUInt8();
|
|
int reservedFutureUseB = (byteC & 0xf0) >> 4;
|
|
int networkDescriptorsLength = (byteC & 0x0f);
|
|
networkDescriptorsLength += ms.ReadUInt8();
|
|
|
|
if (ms.GetAvailableBytes() < networkDescriptorsLength)
|
|
{
|
|
Valid = false;
|
|
return;
|
|
}
|
|
|
|
byte[] networkDescriptors = ms.ReadBytes(networkDescriptorsLength);
|
|
IEnumerable<TsDescriptor> enumerable = tsDescriptorUnpacker.UnpackDescriptors(networkDescriptors, "RMT");
|
|
foreach(TsDescriptor descriptor in enumerable)
|
|
{
|
|
if (!descriptor.Valid)
|
|
{
|
|
Valid = false;
|
|
return;
|
|
}
|
|
if (descriptor.GetDescriptorId() == 0x4a)
|
|
{
|
|
if (Linkages == null)
|
|
Linkages = new List<_0x4a_LinkageDescriptor> ();
|
|
Linkages.Add((_0x4a_LinkageDescriptor)descriptor);
|
|
continue;
|
|
}
|
|
|
|
throw new NotImplementedException(String.Format("Unknown descriptor 0x{0:X2} in RCS Map Table. If this is reproducible, consider submitting a sample of this stream."));
|
|
}
|
|
|
|
byte byteD = ms.ReadUInt8();
|
|
int reservedFutureUseC = (byteD & 0xf0) >> 4;
|
|
int transportStreamLoopLength = (byteD & 0x0f);
|
|
transportStreamLoopLength <<= 8;
|
|
transportStreamLoopLength += ms.ReadUInt8();
|
|
byte[] transportStreamLoop = ms.ReadBytes(transportStreamLoopLength);
|
|
TransportStreams = ReadTransportStreamLoop(transportStreamLoop);
|
|
|
|
Valid = true;
|
|
}
|
|
|
|
private IReadOnlyList<TransportStream> ReadTransportStreamLoop(byte[] transportStreamLoop)
|
|
{
|
|
List<TransportStream> result = new List<TransportStream>();
|
|
|
|
MemoryStream ms = new MemoryStream(transportStreamLoop);
|
|
while (ms.GetAvailableBytes() >= 6)
|
|
{
|
|
TransportStream child = new TransportStream();
|
|
result.Add(child);
|
|
child.TransportStreamId = ms.ReadUInt16BE();
|
|
child.OriginalNetworkId = ms.ReadUInt16BE();
|
|
|
|
byte byteD = ms.ReadUInt8();
|
|
int reservedFutureUseC = (byteD & 0xf0) >> 4;
|
|
int transportDescriptorsLength = (byteD & 0x0f);
|
|
transportDescriptorsLength <<= 8;
|
|
transportDescriptorsLength += ms.ReadUInt8();
|
|
if (transportDescriptorsLength > 0)
|
|
{
|
|
byte[] networkDescriptors = ms.ReadBytes(transportDescriptorsLength);
|
|
IEnumerable<TsDescriptor> enumerable = tsDescriptorUnpacker.UnpackDescriptors(networkDescriptors, "RMT");
|
|
foreach (TsDescriptor descriptor in enumerable)
|
|
{
|
|
if (!descriptor.Valid)
|
|
{
|
|
child.Valid = false;
|
|
return result.AsReadOnly();
|
|
}
|
|
byte id = descriptor.GetDescriptorId();
|
|
switch (id)
|
|
{
|
|
case 0xa8:
|
|
if (child.SatelliteForwardLink != null)
|
|
throw new NotImplementedException("multiple forward links?");
|
|
child.SatelliteForwardLink = (_0xa8_SatelliteForwardLinkDescriptor)descriptor;
|
|
break;
|
|
case 0xa9:
|
|
if (child.SatelliteReturnLink != null)
|
|
throw new NotImplementedException("multiple return links?");
|
|
child.SatelliteReturnLink = (_0xa9_SatelliteReturnLinkDescriptor)descriptor;
|
|
break;
|
|
default:
|
|
throw new NotImplementedException(String.Format("Unknown descriptor 0x{0:X2} in RCS Map Table. If this is reproducible, consider submitting a sample of this stream."));
|
|
}
|
|
}
|
|
}
|
|
child.Valid = true;
|
|
}
|
|
|
|
return result.AsReadOnly();
|
|
}
|
|
|
|
public ushort NetworkId { get; }
|
|
public List<_0x4a_LinkageDescriptor> Linkages { get; }
|
|
public IReadOnlyList<TransportStream> TransportStreams { get; }
|
|
|
|
public class TransportStream : Validatable
|
|
{
|
|
public ushort TransportStreamId { get; internal set; }
|
|
public ushort OriginalNetworkId { get; internal set; }
|
|
public _0xa9_SatelliteReturnLinkDescriptor SatelliteReturnLink { get; internal set; }
|
|
public _0xa8_SatelliteForwardLinkDescriptor SatelliteForwardLink { get; internal set; }
|
|
|
|
public override string ToString()
|
|
{
|
|
return String.Format("ONID {0}, TSID {1}", OriginalNetworkId, TransportStreamId);
|
|
}
|
|
|
|
public DatabaseKeyRmtTransportStream ToKey(ushort networkId)
|
|
{
|
|
return new DatabaseKeyRmtTransportStream(networkId, TransportStreamId, OriginalNetworkId);
|
|
}
|
|
|
|
protected bool Equals(TransportStream other)
|
|
{
|
|
if (this.TransportStreamId != other.TransportStreamId)
|
|
return false;
|
|
if (this.OriginalNetworkId != other.OriginalNetworkId)
|
|
return false;
|
|
if (this.SatelliteForwardLink != null)
|
|
{
|
|
if (other.SatelliteForwardLink != null)
|
|
{
|
|
if (!this.SatelliteForwardLink.Equals(other.SatelliteForwardLink))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (other.SatelliteForwardLink != null)
|
|
return false;
|
|
}
|
|
if (this.SatelliteReturnLink != null)
|
|
{
|
|
if (other.SatelliteReturnLink != null)
|
|
{
|
|
if (!this.SatelliteReturnLink.Equals(other.SatelliteReturnLink))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (other.SatelliteReturnLink != null)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public override bool Equals(object? obj)
|
|
{
|
|
if (ReferenceEquals(null, obj))
|
|
return false;
|
|
if (ReferenceEquals(this, obj))
|
|
return true;
|
|
if (obj.GetType() != this.GetType())
|
|
return false;
|
|
return Equals((TransportStream)obj);
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return HashCode.Combine(TransportStreamId, OriginalNetworkId, SatelliteReturnLink, SatelliteForwardLink);
|
|
}
|
|
}
|
|
}
|
|
}
|