ctr_test_tools/TwlBkpCheck/Windows/TWLBackupBlock/HeaderBody.cs
n2460 12cf32bf6b FalsifyTwlBackup:BkpType Legacy に対応。
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-09-30%20-%20paladin.7z/paladin/ctr_test_tools@38 6b0af911-cb57-b745-895f-eec5701120e1
2011-10-27 11:50:55 +00:00

288 lines
9.2 KiB
C#

using System;
using System.IO;
using System.Diagnostics;
namespace TwlBackupBlock
{
/// <summary>
/// ヘッダブロックのデータ本体。
/// </summary>
public class HeaderBody : AbstractBody
{
public const int NORMAL_HEADER_SIZE = 240;
public const int EX_HEADER_SIZE = 256;
public const int LEGACY_HEADER_SIZE = 160;
public const int UNIQUE_ID_SIZE = 32;
public const int HARDWARE_ID_SIZE = 16;
public const int MAX_CONTENTS = 8;
public const int NUM_OF_SECTION = 11;
public const int TMD_RESERVED_SIZE = 62;
public const int RESERVED_SIZE = 13;
// for WithPrivateSave
public const int RESERVED_SIZE_FOR_WPS = 12;
// for Legacy
public const int RESERVED_SIZE_FOR_LEGACY = 4;
public const int NUM_OF_SECTION_LEGACY = 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 readonly UInt32[] contentId;
public readonly UInt16[] contentIndex;
public readonly TmdReserved tmdReserved;
public Byte headerVersion;
public readonly Byte[] reserved;
// for WithPrivateSave
public UInt32 privateSaveForWPS;
public readonly Byte[] reservedForWPS;
// for Legacy
public UInt32 contentIdForLegacy;
public UInt16 contentIndexForLegacy;
private BkpType type;
private int headerSize;
public HeaderBody(byte[] data, BkpType type)
{
this.type = type;
switch (this.type)
{
case BkpType.NORMAL:
headerSize = NORMAL_HEADER_SIZE;
break;
case BkpType.WITH_PRIVATE_SAVE:
headerSize = EX_HEADER_SIZE;
break;
case BkpType.LEGACY:
headerSize = LEGACY_HEADER_SIZE;
break;
}
if (data == null)
{
throw new ArgumentNullException("data");
}
if (data.Length != headerSize)
{
string message = string.Format("data.Length % {0} != 0 (data.Length:{1})", headerSize, data.Length);
throw new ArgumentException("data", message);
}
uniqueId = new Byte[UNIQUE_ID_SIZE];
hardwareId = new Byte[HARDWARE_ID_SIZE];
if (type != BkpType.LEGACY)
{
fileSizes = new UInt32[NUM_OF_SECTION];
contentId = new UInt32[MAX_CONTENTS];
contentIndex = new UInt16[MAX_CONTENTS];
reserved = new Byte[RESERVED_SIZE];
}
else
{
fileSizes = new UInt32[NUM_OF_SECTION_LEGACY];
reserved = new Byte[RESERVED_SIZE_FOR_LEGACY];
}
tmdReserved = new TmdReserved();
if (type == BkpType.WITH_PRIVATE_SAVE)
{
reservedForWPS = new Byte[RESERVED_SIZE_FOR_WPS];
}
SetBytes(data);
}
public override byte this[int index]
{
get
{
if (index < 0 || index >= headerSize)
{
throw new ArgumentException("index");
}
return ReadByte(index);
}
set
{
if (index < 0 || index >= headerSize)
{
throw new ArgumentException("index");
}
WriteByte(index, value);
}
}
public override int Length
{
get
{
return headerSize;
}
}
/// <summary>
/// 指定したバイトを取得します。
/// </summary>
/// <param name="index">取得したいバイトのインデックス。</param>
/// <returns><paramref name="index"/>で指定したバイト</returns>
public byte ReadByte(int index)
{
if (index < 0 || index >= headerSize)
{
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 >= headerSize)
{
throw new ArgumentException("index");
}
// TODO 処理が遅ければ効率化
byte[] bytes = GetBytes();
bytes[index] = b;
SetBytes(bytes);
}
public override byte[] GetBytes()
{
byte[] bytes = new byte[headerSize];
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);
}
if (type != BkpType.LEGACY)
{
foreach (UInt32 e in contentId)
{
bw.Write(e);
}
}
else
{
bw.Write(contentIdForLegacy);
}
if (type != BkpType.LEGACY)
{
foreach (UInt16 e in contentIndex)
{
bw.Write(e);
}
}
bw.Write(tmdReserved.GetBytes());
if (type == BkpType.LEGACY)
{
bw.Write(contentIndexForLegacy);
}
if (type != BkpType.LEGACY)
{
bw.Write(headerVersion);
}
bw.Write(reserved);
if (type == BkpType.WITH_PRIVATE_SAVE)
{
bw.Write(privateSaveForWPS);
bw.Write(reservedForWPS);
}
Debug.Assert(ms.Position == headerSize);
}
return bytes;
}
public override void SetBytes(byte[] bytes)
{
if (bytes == null)
{
throw new ArgumentNullException("bytes");
}
if (bytes.Length != headerSize)
{
string message = string.Format("bytes.Length != {0} (bytes.Length:{1})", headerSize, 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);
if (type != BkpType.LEGACY)
{
br.Read(contentId);
}
else
{
br.Read(ref contentIdForLegacy);
}
if (type != BkpType.LEGACY)
{
br.Read(contentIndex);
}
{
byte[] tmdReservedBytes = new byte[TMD_RESERVED_SIZE];
br.Read(tmdReservedBytes);
tmdReserved.SetBytes(tmdReservedBytes);
}
if (type == BkpType.LEGACY)
{
br.Read(ref contentIndexForLegacy);
}
if (type != BkpType.LEGACY)
{
br.Read(ref headerVersion);
}
br.Read(reserved);
if (type == BkpType.WITH_PRIVATE_SAVE)
{
br.Read(ref privateSaveForWPS);
br.Read(reservedForWPS);
}
Debug.Assert(ms.Position == headerSize);
}
}
public override object Clone()
{
return new HeaderBody(GetBytes(), type);
}
}
}