1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// SPDX-License-Identifier: LGPL-2.1-or-later OR GPL-2.0-or-later OR MPL-2.0
// SPDX-FileCopyrightText: 2024 Gabriel Marcano <gabemarcano@yahoo.com>
use crateCart;
use crateError;
use crateNCCHPartitionEntry;
use Read;
use Seek;
use SeekFrom;
use str;
/// Trims null and whitespace characters (in that order) from the given string.
/*
#[allow(clippy::cast_possible_truncation)]
const fn scale_5bits_to_8bits(data: u16) -> u8 {
((data & 0x1F) * 0xFF / 0x1F) as u8
}
struct RGBAPixel(u8, u8, u8, u8);
impl<T: Read + Seek> Cart<T> {
/// Computes the checksum of the 3DS header.
///
/// # Errors
/// Returns [`Error::Io`] if there are any issues reading or seeking the underlying data.
pub fn header_checksum(&mut self) -> Result<u16, Error> {
let crc = Crc::<u16>::new(&crc::CRC_16_MODBUS);
self.io.seek(SeekFrom::Start(0))?;
//let mut checksum = 0u8;
let mut data = [0u8; 0x15E];
// It's faster to read in the entire header
self.io.read_exact(&mut data)?;
Ok(crc.checksum(&data))
}
/// Returns the 3DS icon a 32x32 RGBA8888 image.
///
/// # Errors
/// Returns [`Error::Io`] if there are any issues reading or seeking the underlying data.
pub fn extract_rgba_icon(&mut self) -> Result<Vec<u8>, Error> {
let width = 32;
let height = 32;
let tile_w = 8;
let tile_h = 8;
let mut index = 0;
let mut output = vec![0u8; width * height * 4];
let exefs_offset =
(self.header.ncch[0].1.exefs_offset + self.header.ncsd.partition_table[0].offset) * 0x200;
self.io.seek(SeekFrom::Start(exefs_offset.into()))?;
let mut exefs_header = [0u8; 0x200];
self.io.read_exact(&mut exefs_header);
let mut cipher = self.header.ncch[0].1.exefs_ctr();
cipher.apply_keystream(&mut exefs_header);
println!("{exefs_header:02X?}");
/*
let icon_offset = self.io.read_u32::<LittleEndian>()?;
self.io
.seek(SeekFrom::Start(u64::from(icon_offset + 0x20)))?;
let mut bitmap = vec![0u8; 0x200];
self.io.read_exact(&mut bitmap)?;
let mut palette = vec![0u16; 0x10];
self.io.read_u16_into::<LittleEndian>(&mut palette)?;
// 8x8 tiles
for y in (0..height).step_by(tile_h) {
for x in (0..width).step_by(tile_w) {
// Iterate through each pixel in the tile
for ty in 0..tile_h {
for tx in 0..tile_w {
let pixel: u8 = (bitmap[index] >> (4 * (tx % 2))) & 0xF;
if (tx % 2) == 1 {
index += 1;
}
let pixel = if pixel == 0 {
RGBAPixel(0xFF, 0xFF, 0xFF, 0)
} else {
let color16 = palette[usize::from(pixel)];
RGBAPixel(
scale_5bits_to_8bits(color16),
scale_5bits_to_8bits(color16 >> 5),
scale_5bits_to_8bits(color16 >> 10),
0xFF,
)
};
output[4 * ((y + ty) * 32 + (x + tx))] = pixel.0;
output[4 * ((y + ty) * 32 + (x + tx)) + 1] = pixel.1;
output[4 * ((y + ty) * 32 + (x + tx)) + 2] = pixel.2;
output[4 * ((y + ty) * 32 + (x + tx)) + 3] = pixel.3;
}
}
}
}*/
Ok(vec![])
}
}*/
// FIXME need to implement 3DS unit tests