using System; using System.IO; using System.Diagnostics; namespace TwlBackupBlock { /// /// ヘッダブロックのデータ本体。 /// public class HeaderBody : AbstractBody { public const int HEADER_SIZE = 160; public const int UNIQUE_ID_SIZE = 32; public const int HARDWARE_ID_SIZE = 16; public const int NUM_OF_SECTION = 4; public const int TMD_RESERVED_SIZE = 62; public const int RESERVED_SIZE = 4; public UInt32 signature; public UInt16 companyCode; public UInt16 version; public readonly Byte[] uniqueId; public readonly Byte[] hardwareId; public UInt64 titleId; public Int64 requiredSize; public readonly UInt32[] fileSizes; public UInt32 contentId; public readonly TmdReserved tmdReserved; public UInt16 contentIndex; public readonly Byte[] reserved; public HeaderBody(byte[] data) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length != HEADER_SIZE) { string message = string.Format("data.Length % {0} != 0 (data.Length:{1})", HEADER_SIZE, data.Length); throw new ArgumentException("data", message); } uniqueId = new Byte[UNIQUE_ID_SIZE]; hardwareId = new Byte[HARDWARE_ID_SIZE]; fileSizes = new UInt32[NUM_OF_SECTION]; tmdReserved = new TmdReserved(); reserved = new Byte[RESERVED_SIZE]; SetBytes(data); } public override byte this[int index] { get { if (index < 0 || index >= HEADER_SIZE) { throw new ArgumentException("index"); } return ReadByte(index); } set { if (index < 0 || index >= HEADER_SIZE) { throw new ArgumentException("index"); } WriteByte(index, value); } } public override int Length { get { return HEADER_SIZE; } } /// /// 指定したバイトを取得します。 /// /// 取得したいバイトのインデックス。 /// で指定したバイト public byte ReadByte(int index) { if (index < 0 || index >= HEADER_SIZE) { throw new ArgumentException("index"); } // TODO 処理が遅ければ効率化 byte[] bytes = GetBytes(); return bytes[index]; } /// /// 指定したバイトを書き換えます。 /// /// 書き換えたいバイトのインデックス。 /// 上書きに使うバイト。 public void WriteByte(int index, byte b) { if (index < 0 || index >= HEADER_SIZE) { throw new ArgumentException("index"); } // TODO 処理が遅ければ効率化 byte[] bytes = GetBytes(); bytes[index] = b; SetBytes(bytes); } public override byte[] GetBytes() { byte[] bytes = new byte[HEADER_SIZE]; using (var ms = new MemoryStream(bytes)) using (var bw = new BinaryWriter(ms)) { bw.Write(signature); bw.Write(companyCode); bw.Write(version); bw.Write(uniqueId); bw.Write(hardwareId); bw.Write(titleId); bw.Write(requiredSize); foreach (UInt32 e in fileSizes) { bw.Write(e); } bw.Write(contentId); bw.Write(tmdReserved.GetBytes()); bw.Write(contentIndex); bw.Write(reserved); Debug.Assert(ms.Position == HEADER_SIZE); } return bytes; } public override void SetBytes(byte[] bytes) { if (bytes == null) { throw new ArgumentNullException("bytes"); } if (bytes.Length != HEADER_SIZE) { string message = string.Format("bytes.Length != {0} (bytes.Length:{1})", HEADER_SIZE, bytes.Length); throw new ArgumentException("bytes", message); } using (var ms = new MemoryStream(bytes)) using (var br = new ExtBinaryReader(ms)) { br.Read(ref signature); br.Read(ref companyCode); br.Read(ref version); br.Read(uniqueId); br.Read(hardwareId); br.Read(ref titleId); br.Read(ref requiredSize); br.Read(fileSizes); br.Read(ref contentId); { byte[] tmdReservedBytes = new byte[TMD_RESERVED_SIZE]; br.Read(tmdReservedBytes); tmdReserved.SetBytes(tmdReservedBytes); } br.Read(ref contentIndex); br.Read(reserved); Debug.Assert(ms.Position == HEADER_SIZE); } } public override object Clone() { return new HeaderBody(GetBytes()); } } /// /// ヘッダブロック中のTMDReserved。 /// public class TmdReserved { private const int TMD_RESERVED_SIZE = 62; public const int RESERVED8_SIZE = 3; public const int PARENTAL_CONTROL_SIZE = 16; public const int RESERVED_SIZE = 30; public UInt32 publicSaveSize; public UInt32 privateSaveSize; public UInt32 reserved32; public Byte flags; public readonly Byte[] reserved8; public readonly Byte[] parentalControl; public readonly Byte[] reserved; public TmdReserved() { reserved8 = new Byte[RESERVED8_SIZE]; parentalControl = new Byte[PARENTAL_CONTROL_SIZE]; reserved = new Byte[RESERVED_SIZE]; } public byte[] GetBytes() { byte[] bytes = new byte[TMD_RESERVED_SIZE]; using (var ms = new MemoryStream(bytes)) using (var bw = new BinaryWriter(ms)) { bw.Write(publicSaveSize); bw.Write(privateSaveSize); bw.Write(reserved32); bw.Write(flags); bw.Write(reserved8); bw.Write(parentalControl); bw.Write(reserved); Debug.Assert(ms.Position == TMD_RESERVED_SIZE); } return bytes; } public void SetBytes(byte[] bytes) { if (bytes == null) { throw new ArgumentNullException("bytes"); } if (bytes.Length != TMD_RESERVED_SIZE) { string message = string.Format("bytes.Length != {0} (bytes.Length:{1})", TMD_RESERVED_SIZE, bytes.Length); throw new ArgumentException("bytes", message); } using (var ms = new MemoryStream(bytes)) using (var br = new ExtBinaryReader(ms)) { br.Read(ref publicSaveSize); br.Read(ref privateSaveSize); br.Read(ref reserved32); br.Read(ref flags); br.Read(reserved8); br.Read(parentalControl); br.Read(reserved); Debug.Assert(ms.Position == TMD_RESERVED_SIZE); } } } }