using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using BizHawk.Common.BufferExtensions;
using BizHawk.Common.IOExtensions;
namespace BizHawk.Emulation.Cores.Nintendo.NES
{
///
/// at least it's not iNES 2.0...
///
public class Unif
{
private Dictionary Chunks { get; } = new Dictionary();
private void TryAdd(Stream s, string key)
{
if (!Chunks.TryGetValue(key, out var data))
{
return;
}
s.Write(data, 0, data.Length);
}
public Unif(Stream s)
{
var br = new BinaryReader(s, Encoding.ASCII);
if (!Encoding.ASCII.GetBytes("UNIF")
.SequenceEqual(br.ReadBytes(4)))
{
throw new Exception("Missing \"UNIF\" header mark!");
}
int ver = br.ReadInt32();
Console.WriteLine("Processing Version {0} UNIF...", ver);
br.ReadBytes(32 - 4 - 4);
while (br.PeekChar() > 0)
{
string chunkId = Encoding.ASCII.GetString(br.ReadBytes(4));
int length = br.ReadInt32();
byte[] chunkData = br.ReadBytes(length);
Chunks.Add(chunkId, chunkData);
}
var prgs = new MemoryStream();
var chrs = new MemoryStream();
for (int i = 0; i < 16; i++)
{
TryAdd(prgs, $"PRG{i:X1}");
TryAdd(chrs, $"CHR{i:X1}");
}
prgs.Close();
chrs.Close();
Prg = prgs.ToArray();
Chr = chrs.ToArray();
Cart.PrgSize = (short)(Prg.Length / 1024);
Cart.ChrSize = (short)(Chr.Length / 1024);
if (Chunks.TryGetValue("MIRR", out var tmp))
{
switch (tmp[0])
{
case 0: // h mirror
Cart.PadH = 0;
Cart.PadV = 1;
break;
case 1: // v mirror
Cart.PadH = 1;
Cart.PadV = 0;
break;
}
}
if (Chunks.TryGetValue("MAPR", out tmp))
{
Cart.BoardType = new BinaryReader(new MemoryStream(tmp)).ReadStringUtf8NullTerminated();
}
Cart.BoardType = Cart.BoardType.TrimEnd('\0');
Cart.BoardType = "UNIF_" + Cart.BoardType;
if (Chunks.TryGetValue("BATR", out _))
{
// apparently, this chunk just existing means battery is yes
Cart.WramBattery = true;
}
// is there any way using System.Security.Cryptography.SHA1 to compute the hash of
// prg concatenated with chr? i couldn't figure it out, so this implementation is dumb
{
var ms = new MemoryStream();
ms.Write(Prg, 0, Prg.Length);
ms.Write(Chr, 0, Chr.Length);
ms.Close();
var all = ms.ToArray();
Cart.Sha1 = "sha1:" + all.HashSHA1(0, all.Length);
}
// other code will expect this
if (Chr.Length == 0)
{
Chr = null;
}
}
public CartInfo Cart { get; } = new CartInfo();
public byte[] Prg { get; }
public byte[] Chr { get; }
}
}