NdsForge.NET 1.0.1
Read, validate, edit, compare, and build Nintendo DS and DSi images from .NET
Loading...
Searching...
No Matches
NdsImageValidator.cs
1namespace NdsForge;
2
6internal static class NdsImageValidator
7{
12 public static NdsValidationResult Validate(NdsImage image, NdsValidationOptions options)
13 {
14 var diagnostics = new List<NdsDiagnostic>();
15 ValidateChecksum(
16 diagnostics, "NDS1001", "header", image.Header.HeaderCrc,
17 image.Header.RawData.Span[..0x15E], new(0, 0x160));
18 ValidateChecksum(
19 diagnostics, "NDS1002", "Nintendo logo", image.Header.NintendoLogoCrc,
20 image.Header.RawData.Span.Slice(0xC0, 156), new(0xC0, 156));
21
22 ValidateRegion(diagnostics, image.Length, "NDS1101", "ARM9 program", image.Header.Arm9.Data);
23 ValidateRegion(diagnostics, image.Length, "NDS1102", "ARM7 program", image.Header.Arm7.Data);
24 ValidateRegion(diagnostics, image.Length, "NDS1103", "filename table", image.Header.FileNameTable);
25 ValidateRegion(diagnostics, image.Length, "NDS1104", "file allocation table", image.Header.FileAllocationTable);
26 ValidateRegion(diagnostics, image.Length, "NDS1105", "ARM9 overlay table", image.Header.Arm9OverlayTable);
27 ValidateRegion(diagnostics, image.Length, "NDS1106", "ARM7 overlay table", image.Header.Arm7OverlayTable);
28 if (image.Header.Arm9i is not null)
29 {
30 ValidateRegion(diagnostics, image.Length, "NDS1107", "ARM9i program", image.Header.Arm9i.Data);
31 }
32
33 if (image.Header.Arm7i is not null)
34 {
35 ValidateRegion(diagnostics, image.Length, "NDS1108", "ARM7i program", image.Header.Arm7i.Data);
36 }
37
38 ValidateOverlays(diagnostics, image.Arm9Overlays);
39 ValidateOverlays(diagnostics, image.Arm7Overlays);
40 if (image.Banner is not null)
41 {
42 diagnostics.AddRange(image.Banner.ValidateCrcs(image.Header.BannerOffset));
43 }
44
45 NdsSecureAreaValidator.Validate(image, diagnostics, options.SecureAreaKeyTable);
46 NdsDsiIntegrityValidator.Validate(image, diagnostics, options);
47
48 return new NdsValidationResult(diagnostics);
49 }
50
58 private static void ValidateChecksum(
59 List<NdsDiagnostic> diagnostics,
60 string code,
61 string name,
62 ushort stored,
63 ReadOnlySpan<byte> data,
64 NdsRegion region)
65 {
66 ushort calculated = NdsChecksums.ComputeCrc16(data);
67 if (stored != calculated)
68 {
69 diagnostics.Add(new(
70 code,
72 $"The stored {name} CRC is 0x{stored:X4}, but the calculated value is 0x{calculated:X4}.",
73 region));
74 }
75 }
76
83 private static void ValidateRegion(
84 List<NdsDiagnostic> diagnostics,
85 long imageLength,
86 string code,
87 string name,
88 NdsRegion region)
89 {
90 if (region.Offset < 0 || region.Length < 0 || region.Offset > imageLength - region.Length)
91 {
92 diagnostics.Add(new(
93 code,
95 $"The {name} region at 0x{region.Offset:X} with length 0x{region.Length:X} is outside the 0x{imageLength:X}-byte image.",
96 region));
97 }
98 }
99
103 private static void ValidateOverlays(List<NdsDiagnostic> diagnostics, IEnumerable<NdsOverlay> overlays)
104 {
105 foreach (NdsOverlay overlay in overlays)
106 {
107 if (overlay.Data is null)
108 {
109 diagnostics.Add(new(
110 "NDS1201",
112 $"{overlay.Processor} overlay {overlay.Id} references missing FAT file ID {overlay.FileId}."));
113 }
114
115 if (overlay.StaticInitializerEnd < overlay.StaticInitializerStart)
116 {
117 diagnostics.Add(new(
118 "NDS1202",
120 $"{overlay.Processor} overlay {overlay.Id} has a reversed static-initializer range."));
121 }
122 }
123 }
124}
NdsDiagnosticSeverity
Indicates the impact of a validation finding.