NdsForge.NET 1.0.1
Read, validate, edit, compare, and build Nintendo DS and DSi images from .NET
Loading...
Searching...
No Matches
NdsDsiBuildMetadata.cs
1namespace NdsForge;
2
7public sealed class NdsDsiBuildMetadata
8{
10 private byte[] _extensionTemplate = new byte[0xE80];
12 private byte[] _memoryBankSettings = CreateDefaultMemoryBankSettings();
14 private byte[] _ageRatings = Enumerable.Repeat((byte)0x80, 0x10).ToArray();
16 private NdsProcessor? _modcryptArea1Anchor;
18 private NdsProcessor? _modcryptArea2Anchor;
20 private long _modcryptArea1RelativeOffset;
22 private long _modcryptArea2RelativeOffset;
24 private NdsRegion _modcryptArea1;
26 private NdsRegion _modcryptArea2;
27
29 public byte DsiFlags { get; set; } = 0x01;
30
32 public uint RegionFlags { get; set; } = uint.MaxValue;
33
35 public uint AccessControl { get; set; }
36
38 public uint ScfgExtMask { get; set; }
39
41 public byte ApplicationFlags { get; set; }
42
44 public uint Arm7DeviceListAddress { get; set; }
45
47 public ulong TitleId { get; set; }
48
50 public uint PublicSaveSize { get; set; }
51
53 public uint PrivateSaveSize { get; set; }
54
57 {
58 get => _modcryptArea1;
59 set
60 {
61 _modcryptArea1 = value;
62 _modcryptArea1Anchor = null;
63 _modcryptArea1RelativeOffset = 0;
64 }
65 }
66
69 {
70 get => _modcryptArea2;
71 set
72 {
73 _modcryptArea2 = value;
74 _modcryptArea2Anchor = null;
75 _modcryptArea2RelativeOffset = 0;
76 }
77 }
78
81
86 public NdsDsiDigestOptions? Digests { get; set; }
87
95 {
96 ArgumentNullException.ThrowIfNull(header);
97 var metadata = new NdsDsiBuildMetadata
98 {
99 _extensionTemplate = header.RawData.ToArray(),
100 _memoryBankSettings = header.MemoryBankSettings.ToArray(),
101 _ageRatings = header.AgeRatings.ToArray(),
102 RegionFlags = header.RegionFlags,
104 ScfgExtMask = header.ScfgExtMask,
107 TitleId = header.TitleId,
112 };
113 return metadata;
114 }
115
119 public NdsDsiBuildMetadata SetMemoryBankSettings(ReadOnlySpan<byte> settings)
120 {
121 if (settings.Length != 0x30)
122 {
123 throw new ArgumentException("DSi memory-bank settings must contain exactly 48 bytes.", nameof(settings));
124 }
125
126 _memoryBankSettings = settings.ToArray();
127 return this;
128 }
129
133 public NdsDsiBuildMetadata SetAgeRatings(ReadOnlySpan<byte> ratings)
134 {
135 if (ratings.Length != 0x10)
136 {
137 throw new ArgumentException("DSi age ratings must contain exactly sixteen bytes.", nameof(ratings));
138 }
139
140 _ageRatings = ratings.ToArray();
141 return this;
142 }
143
145 internal ReadOnlyMemory<byte> ExtensionTemplate => _extensionTemplate;
146
148 internal ReadOnlyMemory<byte> MemoryBankSettings => _memoryBankSettings;
149
151 internal ReadOnlyMemory<byte> AgeRatings => _ageRatings;
152
155 internal void AnchorModcryptAreas(IEnumerable<NdsProgram> programs)
156 {
157 NdsProgram[] candidates = programs.ToArray();
158 (_modcryptArea1Anchor, _modcryptArea1RelativeOffset) = FindAnchor(ModcryptArea1, candidates);
159 (_modcryptArea2Anchor, _modcryptArea2RelativeOffset) = FindAnchor(ModcryptArea2, candidates);
160 }
161
167 internal NdsRegion ResolveModcryptArea(NdsRegion area, bool first, NdsImageBuildLayout layout)
168 {
169 NdsProcessor? anchor = first ? _modcryptArea1Anchor : _modcryptArea2Anchor;
170 long relativeOffset = first ? _modcryptArea1RelativeOffset : _modcryptArea2RelativeOffset;
171 if (anchor is null)
172 {
173 return area;
174 }
175
176 NdsRegion program = anchor switch
177 {
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}."),
183 };
184 return new(checked(program.Offset + relativeOffset), area.Length);
185 }
186
191 private static (NdsProcessor? Anchor, long RelativeOffset) FindAnchor(
192 NdsRegion area,
193 IReadOnlyList<NdsProgram> programs)
194 {
195 if (area.IsEmpty)
196 {
197 return (null, 0);
198 }
199
200 NdsProgram? program = programs.FirstOrDefault(candidate =>
201 area.Offset >= candidate.Data.Offset && area.Offset < candidate.Data.End);
202 return program is null
203 ? (null, 0)
204 : (program.Processor, area.Offset - program.Data.Offset);
205 }
206
209 private static byte[] CreateDefaultMemoryBankSettings() =>
210 [
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,
216 ];
217}
Supplies DSi-only execution, service, storage, and policy metadata while retaining unmodeled extensio...
static NdsDsiBuildMetadata FromHeader(NdsDsiHeader header)
Copies all 0xE80 extension bytes from a parsed header, then initializes typed properties from the sam...
uint PrivateSaveSize
Requests private writable save bytes without allocating those bytes inside the ROM image.
uint AccessControl
Controls service and hardware capabilities requested from the DSi execution environment.
byte ApplicationFlags
Preserves the application-policy byte at extended-header offset 0x1BF.
NdsDsiBuildMetadata SetMemoryBankSettings(ReadOnlySpan< byte > settings)
Copies the exact MBK and WRAM register image stored at header offsets 0x180-0x1AF.
NdsDsiBuildMetadata SetAgeRatings(ReadOnlySpan< byte > ratings)
Copies the sixteen raw authority slots without guessing territory-specific flag interpretation.
NdsRegion ModcryptArea2
Declares the second modcrypt-transformed image interval, or an empty region when modcrypt is unused.
NdsRegion ModcryptArea1
Declares the first modcrypt-transformed image interval, or an empty region when modcrypt is unused.
ulong TitleId
Identifies the title to DSi services and save storage; it is independent from the four-byte game code...
byte DsiFlags
Preserves common-header DSi behavior flags separately from the application flags in the extension.
uint RegionFlags
Defines the DSi territories in which system software may expose the title; all bits set is homebrew-f...
uint PublicSaveSize
Requests public writable save bytes without allocating those bytes inside the ROM image.
NdsDsiIntegrityOptions Integrity
Determines whether authentication fields are cleared or computed under an explicitly named key policy...
uint Arm7DeviceListAddress
Points ARM7i services to their runtime device-list structure rather than to a cartridge region.
uint ScfgExtMask
Limits which SCFG_EXT hardware-configuration bits the application may change at runtime.
NdsDsiDigestOptions? Digests
Enables hierarchical content authentication when non-null. Building tables requires the same explicit...
Configures the optional DSi hierarchical HMAC-SHA1 tables that cover common NTR content and DSi-mode ...
Projects DSi security, digest, memory, title, and save metadata while preserving the complete extensi...
uint PublicSaveSize
Declares public writable storage bytes requested by DSi software, not an embedded ROM region.
ReadOnlyMemory< byte > MemoryBankSettings
Gets raw global, ARM9, ARM7, and WRAM memory-bank settings.
ReadOnlyMemory< byte > AgeRatings
Preserves sixteen territory-specific rating bytes because their flags and authorities vary by slot.
uint ScfgExtMask
Preserves the SCFG_EXT mask controlling which DSi hardware configuration bits software may change.
uint PrivateSaveSize
Declares private writable storage bytes requested by DSi software, not an embedded ROM region.
uint Arm7DeviceListAddress
Identifies the runtime ARM7 address of the DSi device-list structure used during service initializati...
uint RegionFlags
Gets permitted DSi region flags.
uint AccessControl
Gets DSi access-control flags.
ReadOnlyMemory< byte > RawData
Preserves bytes 0x180-0xFFF, including reserved and cryptographic fields not yet interpreted.
byte ApplicationFlags
Gets DSi application flags.
NdsRegion ModcryptArea1
Locates the first optional region transformed by DSi modcrypt when corresponding flags enable it.
ulong TitleId
Combines low and high words into the platform title identifier used by DSi services and save storage.
NdsRegion ModcryptArea2
Locates the second optional region transformed by DSi modcrypt when corresponding flags enable it.
Defines which DSi authentication fields a build can honestly produce. Component HMACs use caller-sele...
static NdsDsiIntegrityOptions Unauthenticated
Uses zeroed HMAC and signature fields for a clearly unauthenticated DSi image.
Describes an executable program region and its runtime addresses.
Definition NdsProgram.cs:13
Identifies a bounded range of bytes in an image.
Definition NdsRegion.cs:11
NdsProcessor
Identifies a processor and execution mode.