21 if (image.Length < 0x200)
23 throw new InvalidDataException(
"A legacy ARM7 hook requires at least a complete 512-byte DS header.");
28 throw new ArgumentException(
"A legacy ARM7 hook payload cannot be empty.", nameof(hook));
31 byte[] originalHeader = image[..0x200].ToArray();
32 RestoreHeaderBackupIfPresent(image, originalHeader);
33 uint arm7Offset = ReadUInt32(originalHeader, 0x30);
34 uint arm7Entry = ReadUInt32(originalHeader, 0x34);
35 uint arm7Ram = ReadUInt32(originalHeader, 0x38);
36 uint arm7Size = ReadUInt32(originalHeader, 0x3C);
37 uint usedSize = ReadUInt32(originalHeader, 0x80);
38 if ((ulong)arm7Offset + arm7Size > (ulong)image.Length || usedSize > image.Length)
40 throw new InvalidDataException(
"The source ARM7 region or declared used size lies outside the image.");
43 int alignedHookSize = checked((hook.Length + 3) & ~3);
44 uint newArm7Offset = Align(checked(usedSize + 0x100u), 0x200);
45 uint hookOffset = checked(newArm7Offset + arm7Size);
46 uint headerBackupOffset = checked(hookOffset + (uint)alignedHookSize);
47 uint newUsedSize = checked(headerBackupOffset + 0x200u);
48 int outputLength = checked((
int)Math.Max(image.Length, (
long)newUsedSize + 4));
49 var output =
new byte[outputLength];
51 byte[] relocatedArm7 = image.Slice(checked((
int)arm7Offset), checked((
int)arm7Size)).ToArray();
52 var alignedHook =
new byte[alignedHookSize];
53 hook.CopyTo(alignedHook);
54 int logicalLength = image.Length;
56 NdsLegacyCrc32.ReplacePreservingCrc(output, ref logicalLength, checked((
int)newArm7Offset), relocatedArm7);
57 NdsLegacyCrc32.ReplacePreservingCrc(output, ref logicalLength, checked((
int)hookOffset), alignedHook);
58 NdsLegacyCrc32.ReplacePreservingCrc(output, ref logicalLength, checked((
int)headerBackupOffset), originalHeader);
59 byte[] patchedHeader = CreatePatchedHeader(
62 checked(arm7Ram + arm7Size + (uint)alignedHookSize),
63 checked(arm7Entry + arm7Size),
65 checked(arm7Size + (uint)alignedHookSize + 0x200u),
67 NdsLegacyCrc32.ReplacePreservingCrc(output, ref logicalLength, 0, patchedHeader, checked((
int)newUsedSize));
68 uint resultCrc = NdsLegacyCrc32.Calculate(output);
72 new(newArm7Offset, checked(arm7Size + (uint)alignedHookSize + 0x200u)),
73 new(hookOffset, alignedHookSize),
74 new(headerBackupOffset, 0x200),
136 private static void WriteUInt32(Span<byte> data,
int offset, uint value) => BinaryPrimitives.WriteUInt32LittleEndian(data[offset..], value);