BizHawk/BizHawk.Emulation.Cores/Computers/Commodore64/Media/G64.cs

143 lines
4.6 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
{
public static class G64
{
public static Disk Read(byte[] source)
{
using (var mem = new MemoryStream(source))
{
var reader = new BinaryReader(mem);
var id = new string(reader.ReadChars(8));
var trackDatas = new List<byte[]>();
var trackLengths = new List<int>();
var trackNumbers = new List<int>();
var trackDensities = new List<int>();
if (id == @"GCR-1541")
{
reader.ReadByte(); // version
int trackCount = reader.ReadByte();
reader.ReadInt16(); // max track size in bytes
var trackOffsetTable = new int[trackCount];
var trackSpeedTable = new int[trackCount];
for (var i = 0; i < trackCount; i++)
{
trackOffsetTable[i] = reader.ReadInt32();
}
for (var i = 0; i < trackCount; i++)
{
trackSpeedTable[i] = reader.ReadInt32();
}
for (var i = 0; i < trackCount; i++)
{
if (trackOffsetTable[i] > 0)
{
mem.Position = trackOffsetTable[i];
int trackLength = reader.ReadInt16();
var trackData = reader.ReadBytes(trackLength);
trackDatas.Add(trackData);
trackLengths.Add(trackLength * 8);
trackDensities.Add(trackSpeedTable[i]);
trackNumbers.Add(i);
}
}
if (trackSpeedTable.Any(ts => ts > 3 || ts < 0))
{
throw new Exception("Byte-level speeds are not yet supported in the G64 loader.");
}
return new Disk(trackDatas, trackNumbers, trackDensities, 84) {WriteProtected = true};
}
return new Disk(84) {WriteProtected = false};
}
}
public static byte[] Write(IList<byte[]> trackData, IList<int> trackNumbers, IList<int> trackDensities)
{
const byte version = 0;
const byte trackCount = 84;
const int headerLength = 0xC;
const byte dataFillerValue = 0xFF;
var trackMaxLength = (ushort)Math.Max(7928, trackData.Max(d => d.Length));
using (var mem = new MemoryStream())
{
var writer = new BinaryWriter(mem);
// header ID
writer.Write("GCR-1541".ToCharArray());
// version #
writer.Write(version);
// tracks in the image
writer.Write(trackCount);
// maximum track size in bytes
writer.Write(trackMaxLength);
// combine track data
var offsets = new List<int>();
var densities = new List<int>();
using (var trackMem = new MemoryStream())
{
var trackMemWriter = new BinaryWriter(trackMem);
for (var i = 0; i < trackCount; i++)
{
if (trackNumbers.Contains(i))
{
var trackIndex = trackNumbers.IndexOf(i);
offsets.Add((int)trackMem.Length);
densities.Add(trackDensities[trackIndex]);
var data = trackData[trackIndex];
var buffer = Enumerable.Repeat(dataFillerValue, trackMaxLength).ToArray();
var dataBytes = data.Select(d => unchecked((byte)d)).ToArray();
Array.Copy(dataBytes, buffer, dataBytes.Length);
trackMemWriter.Write((ushort)dataBytes.Length);
trackMemWriter.Write(buffer);
}
else
{
offsets.Add(-1);
densities.Add(0);
}
}
trackMemWriter.Flush();
// offset table
foreach (var offset in offsets.Select(o => o >= 0 ? o + headerLength + trackCount * 8 : 0))
{
writer.Write(offset);
}
// speed zone data
foreach (var density in densities)
{
writer.Write(density);
}
// track data
writer.Write(trackMem.ToArray());
}
writer.Flush();
return mem.ToArray();
}
}
}
}