BizHawk/BizHawk.Emulation.DiscSystem/DiscTypes.cs

171 lines
4.3 KiB
C#

using System;
namespace BizHawk.Emulation.DiscSystem
{
/// <summary>
/// Represents a TOC entry discovered in the Q subchannel data of the lead-in track by the reader. These are stored redundantly.
/// It isn't clear whether we need anything other than the SubchannelQ data, so I abstracted this in case we need it.
/// </summary>
public class RawTOCEntry
{
public SubchannelQ QData;
}
public enum DiscInterface
{
BizHawk, MednaDisc, LibMirage
}
public enum SessionFormat
{
None = -1,
Type00_CDROM_CDDA = 0x00,
Type10_CDI = 0x10,
Type20_CDXA = 0x20
}
/// <summary>
/// encapsulates a 2 digit BCD number as used various places in the CD specs
/// </summary>
public struct BCD2
{
/// <summary>
/// The raw BCD value. you can't do math on this number! but you may be asked to supply it to a game program.
/// The largest number it can logically contain is 99
/// </summary>
public byte BCDValue;
/// <summary>
/// The derived decimal value. you can do math on this! the largest number it can logically contain is 99.
/// </summary>
public int DecimalValue
{
get => (BCDValue & 0xF) + ((BCDValue >> 4) & 0xF) * 10;
set => BCDValue = IntToBCD(value);
}
/// <summary>
/// makes a BCD2 from a decimal number. don't supply a number > 99 or you might not like the results
/// </summary>
public static BCD2 FromDecimal(int d)
{
return new BCD2 { DecimalValue = d };
}
public static BCD2 FromBCD(byte b)
{
return new BCD2 { BCDValue = b };
}
public static int BCDToInt(byte n)
{
var bcd = new BCD2 { BCDValue = n };
return bcd.DecimalValue;
}
public static byte IntToBCD(int n)
{
int tens = Math.DivRem(n, 10, out var ones);
return (byte)((tens << 4) | ones);
}
public override string ToString()
{
return BCDValue.ToString("X2");
}
}
public static class MSF
{
public static int ToInt(int m, int s, int f)
{
return m * 60 * 75 + s * 75 + f;
}
}
/// <summary>
/// todo - rename to MSF? It can specify durations, so maybe it should be not suggestive of timestamp
/// TODO - can we maybe use BCD2 in here
/// </summary>
public struct Timestamp
{
/// <summary>
/// Checks if the string is a legit MSF. It's strict.
/// </summary>
public static bool IsMatch(string str)
{
return new Timestamp(str).Valid;
}
/// <summary>
/// creates a timestamp from a string in the form mm:ss:ff
/// </summary>
public Timestamp(string str)
{
if (str.Length != 8) goto BOGUS;
if (str[0] < '0' || str[0] > '9') goto BOGUS;
if (str[1] < '0' || str[1] > '9') goto BOGUS;
if (str[2] != ':') goto BOGUS;
if (str[3] < '0' || str[3] > '9') goto BOGUS;
if (str[4] < '0' || str[4] > '9') goto BOGUS;
if (str[5] != ':') goto BOGUS;
if (str[6] < '0' || str[6] > '9') goto BOGUS;
if (str[7] < '0' || str[7] > '9') goto BOGUS;
MIN = (byte)((str[0] - '0') * 10 + (str[1] - '0'));
SEC = (byte)((str[3] - '0') * 10 + (str[4] - '0'));
FRAC = (byte)((str[6] - '0') * 10 + (str[7] - '0'));
Valid = true;
Negative = false;
return;
BOGUS:
MIN = SEC = FRAC = 0;
Valid = false;
Negative = false;
return;
}
/// <summary>
/// The string representation of the MSF
/// </summary>
public string Value => !Valid ? "--:--:--" : $"{(Negative ? '-' : '+')}{MIN:D2}:{SEC:D2}:{FRAC:D2}";
public readonly byte MIN, SEC, FRAC;
public readonly bool Valid, Negative;
/// <summary>
/// The fully multiplied out flat-address Sector number
/// </summary>
public int Sector => MIN * 60 * 75 + SEC * 75 + FRAC;
/// <summary>
/// creates timestamp from the supplied MSF
/// </summary>
public Timestamp(int m, int s, int f)
{
MIN = (byte)m;
SEC = (byte)s;
FRAC = (byte)f;
Valid = true;
Negative = false;
}
/// <summary>
/// creates timestamp from supplied SectorNumber
/// </summary>
public Timestamp(int SectorNumber)
{
if (SectorNumber < 0)
{
SectorNumber = -SectorNumber;
Negative = true;
}
else Negative = false;
MIN = (byte)(SectorNumber / (60 * 75));
SEC = (byte)((SectorNumber / 75) % 60);
FRAC = (byte)(SectorNumber % 75);
Valid = true;
}
public override string ToString() => Value;
}
}