2021-10-20 22:40:03 +02:00

93 lines
2.9 KiB
C#

using System;
using System.IO;
using System.Linq;
using System.Text;
namespace AnotherReplayReader.ReplayFile
{
internal enum ReplayFooterOption
{
SeekToFooter,
CurrentlyAtFooter,
}
internal sealed class ReplayFooter
{
public const uint Terminator = 0x7FFFFFFF;
public static readonly byte[] FooterString = Encoding.ASCII.GetBytes("RA3 REPLAY FOOTER");
private readonly byte[] _data;
public uint FinalTimeCode { get; }
public TimeSpan ReplayLength => TimeSpan.FromSeconds(FinalTimeCode / Replay.FrameRate);
public ReplayFooter(BinaryReader reader, ReplayFooterOption option)
{
var currentPosition = reader.BaseStream.Position;
reader.BaseStream.Seek(-4, SeekOrigin.End);
var footerLength = reader.ReadInt32();
if (option == ReplayFooterOption.SeekToFooter)
{
currentPosition = reader.BaseStream.Length - footerLength;
}
reader.BaseStream.Seek(currentPosition, SeekOrigin.Begin);
var footer = reader.ReadBytes(footerLength);
if (footer.Length != footerLength || reader.BaseStream.Position != reader.BaseStream.Length)
{
throw new InvalidDataException("Invalid footer");
}
using var footerStream = new MemoryStream(footer);
using var footerReader = new BinaryReader(footerStream);
var footerString = footerReader.ReadBytes(17);
if (!footerString.SequenceEqual(FooterString))
{
throw new InvalidDataException("Invalid footer, no footer string");
}
FinalTimeCode = footerReader.ReadUInt32();
_data = footerReader.ReadBytes(footer.Length - 25);
if (footerReader.ReadInt32() != footerLength)
{
throw new InvalidDataException();
}
}
public ReplayFooter(uint finalTimeCode)
{
FinalTimeCode = finalTimeCode;
_data = new byte[] { 0x02, 0x1A, 0x00, 0x00, 0x00 };
}
public float[]? TryGetKillDeathRatios()
{
if (_data.Length < 24)
{
return null;
}
var ratios = new float[6];
using var stream = new MemoryStream(_data, _data.Length - 24, 24);
using var reader = new BinaryReader(stream);
for (var i = 0; i < ratios.Length; ++i)
{
ratios[i] = reader.ReadSingle();
}
return ratios;
}
public void WriteTo(BinaryWriter writer)
{
writer.Write(Terminator);
writer.Write(FooterString);
writer.Write(FinalTimeCode);
writer.Write(_data);
writer.Write(FooterString.Length + _data.Length + 8);
}
}
}