mirror of
https://github.com/rvtr/ctr_test_tools.git
synced 2025-10-31 13:41:24 -04:00
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-09-30%20-%20paladin.7z/paladin/ctr_test_tools@11 6b0af911-cb57-b745-895f-eec5701120e1
261 lines
8.2 KiB
C#
261 lines
8.2 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Diagnostics;
|
|
|
|
namespace TwlBackupBlock
|
|
{
|
|
/// <summary>
|
|
/// ヘッダブロックのデータ本体。
|
|
/// </summary>
|
|
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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 指定したバイトを取得します。
|
|
/// </summary>
|
|
/// <param name="index">取得したいバイトのインデックス。</param>
|
|
/// <returns><paramref name="index"/>で指定したバイト</returns>
|
|
public byte ReadByte(int index)
|
|
{
|
|
if (index < 0 || index >= HEADER_SIZE)
|
|
{
|
|
throw new ArgumentException("index");
|
|
}
|
|
// TODO 処理が遅ければ効率化
|
|
byte[] bytes = GetBytes();
|
|
return bytes[index];
|
|
}
|
|
|
|
/// <summary>
|
|
/// 指定したバイトを書き換えます。
|
|
/// </summary>
|
|
/// <param name="index">書き換えたいバイトのインデックス。</param>
|
|
/// <param name="b">上書きに使うバイト。</param>
|
|
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());
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// ヘッダブロック中のTMDReserved。
|
|
/// </summary>
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|