10 private byte[] _extensionTemplate =
new byte[0xE80];
12 private byte[] _memoryBankSettings = CreateDefaultMemoryBankSettings();
14 private byte[] _ageRatings = Enumerable.Repeat((
byte)0x80, 0x10).ToArray();
20 private long _modcryptArea1RelativeOffset;
22 private long _modcryptArea2RelativeOffset;
58 get => _modcryptArea1;
61 _modcryptArea1 = value;
62 _modcryptArea1Anchor =
null;
63 _modcryptArea1RelativeOffset = 0;
70 get => _modcryptArea2;
73 _modcryptArea2 = value;
74 _modcryptArea2Anchor =
null;
75 _modcryptArea2RelativeOffset = 0;
96 ArgumentNullException.ThrowIfNull(header);
99 _extensionTemplate = header.
RawData.ToArray(),
121 if (settings.Length != 0x30)
123 throw new ArgumentException(
"DSi memory-bank settings must contain exactly 48 bytes.", nameof(settings));
126 _memoryBankSettings = settings.ToArray();
135 if (ratings.Length != 0x10)
137 throw new ArgumentException(
"DSi age ratings must contain exactly sixteen bytes.", nameof(ratings));
140 _ageRatings = ratings.ToArray();
145 internal ReadOnlyMemory<byte> ExtensionTemplate => _extensionTemplate;
148 internal ReadOnlyMemory<byte> MemoryBankSettings => _memoryBankSettings;
151 internal ReadOnlyMemory<byte> AgeRatings => _ageRatings;
155 internal void AnchorModcryptAreas(IEnumerable<NdsProgram> programs)
158 (_modcryptArea1Anchor, _modcryptArea1RelativeOffset) = FindAnchor(
ModcryptArea1, candidates);
159 (_modcryptArea2Anchor, _modcryptArea2RelativeOffset) = FindAnchor(
ModcryptArea2, candidates);
167 internal NdsRegion ResolveModcryptArea(NdsRegion area,
bool first, NdsImageBuildLayout layout)
169 NdsProcessor? anchor = first ? _modcryptArea1Anchor : _modcryptArea2Anchor;
170 long relativeOffset = first ? _modcryptArea1RelativeOffset : _modcryptArea2RelativeOffset;
176 NdsRegion program = anchor
switch
178 NdsProcessor.Arm9 => layout.Arm9,
179 NdsProcessor.Arm7 => layout.Arm7,
180 NdsProcessor.Arm9i => layout.Arm9i!.Value,
181 NdsProcessor.Arm7i => layout.Arm7i!.Value,
182 _ =>
throw new InvalidDataException($
"Unsupported modcrypt Program anchor {anchor}."),
184 return new(checked(program.Offset + relativeOffset), area.Length);
191 private static (
NdsProcessor? Anchor,
long RelativeOffset) FindAnchor(
193 IReadOnlyList<NdsProgram> programs)
200 NdsProgram? program = programs.FirstOrDefault(candidate =>
201 area.Offset >= candidate.Data.Offset && area.Offset < candidate.Data.End);
202 return program is
null
204 : (program.Processor, area.Offset - program.Data.Offset);
209 private static byte[] CreateDefaultMemoryBankSettings() =>
211 0x81, 0x85, 0x89, 0x8D, 0x80, 0x84, 0x88, 0x8C, 0x90, 0x94, 0x98, 0x9C,
212 0x80, 0x84, 0x88, 0x8C, 0x90, 0x94, 0x98, 0x9C,
213 0x00, 0x00, 0x00, 0x00, 0x40, 0x37, 0xC0, 0x07, 0x00, 0x37, 0x40, 0x07,
214 0x00, 0x30, 0x40, 0x00, 0x40, 0x37, 0xC0, 0x07, 0x00, 0x37, 0x40, 0x07,
215 0x0F, 0x00, 0x00, 0x03,