+124
src/cartridge_header.rs
+124
src/cartridge_header.rs
···
1
+
use crate::NINTENDO_LOGO;
2
+
use crate::enums::{
3
+
CGBFlag, CartridgeHeaderAddress, CartridgeType, DestinationCode, Error, RamSize, RomSize,
4
+
};
5
+
6
+
pub struct CartridgeHeader {
7
+
//Should be 80 bytes (0x014F(335) - 0x0100(256)) + 1 to include the last address
8
+
pub buffer: [u8; 80],
9
+
pub title: [char; 16],
10
+
pub manufacturer_code: [char; 4],
11
+
pub cgb_flag: CGBFlag,
12
+
// https://gbdev.io/pandocs/The_Cartridge_Header.html#01440145--new-licensee-code
13
+
pub license_code: [char; 2],
14
+
pub support_gb: bool,
15
+
pub cart_type: CartridgeType,
16
+
pub rom_size: RomSize,
17
+
pub ram_size: RamSize,
18
+
// If None uses new license code which is just license_code
19
+
// https://gbdev.io/pandocs/The_Cartridge_Header.html#014b--old-licensee-code
20
+
pub old_licensee_code: Option<u8>,
21
+
pub destination_code: DestinationCode,
22
+
pub version: u8,
23
+
pub header_checksum: u8,
24
+
pub global_checksum: u16,
25
+
}
26
+
27
+
impl CartridgeHeader {
28
+
fn bytes_to_chars<const N: usize>(bytes: &[u8], break_on_null: bool) -> [char; N] {
29
+
let mut chars = [0x000 as char; N];
30
+
for (i, byte) in bytes.iter().enumerate() {
31
+
if break_on_null && *byte == 0x00 {
32
+
break;
33
+
}
34
+
chars[i] = *byte as char;
35
+
}
36
+
chars
37
+
}
38
+
39
+
pub fn parse(rom_bytes: &[u8]) -> Result<Self, Error> {
40
+
let start = CartridgeHeaderAddress::CartridgeHeaderStart as usize;
41
+
let end = start + 80;
42
+
let header_buffer: &[u8] = rom_bytes[start..end]
43
+
.try_into()
44
+
.map_err(|_| Error::CartridgeReadError)?;
45
+
46
+
//Checks if the Nintendo logo matches the device's version. Early anti piracy feature. Neat to take note of
47
+
let nintendo_logo_from_rom = &rom_bytes[CartridgeHeaderAddress::NintendoLogoStart as usize
48
+
..CartridgeHeaderAddress::NintendoLogoEnd as usize + 1];
49
+
for (i, true_logo_byte) in NINTENDO_LOGO.iter().enumerate() {
50
+
let rom_byte = nintendo_logo_from_rom[i];
51
+
if rom_byte != *true_logo_byte {
52
+
return Err(Error::CartridgeReadError);
53
+
}
54
+
}
55
+
56
+
let title = &rom_bytes[CartridgeHeaderAddress::TitleStart as usize
57
+
..CartridgeHeaderAddress::TitleEnd as usize + 1];
58
+
let title_chars = Self::bytes_to_chars::<16>(title, true);
59
+
60
+
let manufacturer_code = &rom_bytes[CartridgeHeaderAddress::ManufacturerCodeStart as usize
61
+
..CartridgeHeaderAddress::ManufacturerCodeEnd as usize + 1];
62
+
let man_code_chars = Self::bytes_to_chars::<4>(manufacturer_code, false);
63
+
64
+
let cgb_flag_byte = rom_bytes[0x0143];
65
+
let cgb_flag = match cgb_flag_byte {
66
+
0x80 => CGBFlag::SupportsColorBackwardCompatiable,
67
+
0xC0 => CGBFlag::ColorOnly,
68
+
_ => CGBFlag::NotSet,
69
+
};
70
+
71
+
let license_code = &rom_bytes[CartridgeHeaderAddress::NewLicenseStart as usize
72
+
..CartridgeHeaderAddress::NewLicenseEnd as usize + 1];
73
+
let license_code_chars = Self::bytes_to_chars::<2>(license_code, false);
74
+
75
+
// https://gbdev.io/pandocs/The_Cartridge_Header.html#0146--sgb-flag
76
+
let sgb_flag = rom_bytes[CartridgeHeaderAddress::SgbFlag as usize] == 0x03;
77
+
78
+
let cart_type =
79
+
CartridgeType::from_byte(rom_bytes[CartridgeHeaderAddress::CartType as usize]);
80
+
81
+
let rom_size = RomSize::from_byte(rom_bytes[CartridgeHeaderAddress::RomSize as usize]);
82
+
let ram_size = RamSize::from_byte(rom_bytes[CartridgeHeaderAddress::RamSize as usize]);
83
+
84
+
let mut old_licensee_code = None;
85
+
if !sgb_flag {
86
+
old_licensee_code = Some(rom_bytes[CartridgeHeaderAddress::OldLicenseeCode as usize])
87
+
}
88
+
89
+
let destination_code =
90
+
DestinationCode::from_byte(rom_bytes[CartridgeHeaderAddress::DestinationCode as usize]);
91
+
92
+
let version = rom_bytes[CartridgeHeaderAddress::MaskRomVersion as usize];
93
+
let header_checksum = rom_bytes[CartridgeHeaderAddress::HeaderChecksum as usize];
94
+
let global_checksum = u16::from_le_bytes([
95
+
rom_bytes[CartridgeHeaderAddress::GlobalChecksumStart as usize],
96
+
rom_bytes[CartridgeHeaderAddress::CartridgeHeaderEnd as usize],
97
+
]);
98
+
99
+
Ok(Self {
100
+
buffer: header_buffer
101
+
.try_into()
102
+
.map_err(|_| Error::CartridgeReadError)?,
103
+
title: title_chars,
104
+
manufacturer_code: man_code_chars,
105
+
cgb_flag,
106
+
license_code: license_code_chars,
107
+
support_gb: sgb_flag,
108
+
cart_type,
109
+
rom_size,
110
+
ram_size,
111
+
old_licensee_code,
112
+
destination_code,
113
+
version,
114
+
header_checksum,
115
+
global_checksum,
116
+
})
117
+
}
118
+
119
+
fn print_test(&self) {
120
+
for byte in self.buffer.iter() {
121
+
print!("{} ", *byte as char);
122
+
}
123
+
}
124
+
}
+2
-118
src/main.rs
+2
-118
src/main.rs
···
1
+
mod cartridge_header;
1
2
mod enums;
2
3
4
+
use crate::cartridge_header::CartridgeHeader;
3
5
use crate::enums::CartridgeHeaderAddress::OldLicenseeCode;
4
6
use crate::enums::{
5
7
CGBFlag, CartridgeHeaderAddress, CartridgeType, DestinationCode, Error, RamSize, RomSize,
···
27
29
28
30
// const ROM_NAME: &str = "OtherLegallyObtainedRom.gb";
29
31
const ROM_NAME: &str = "LegallyObtainedRom.gb";
30
-
31
-
struct CartridgeHeader {
32
-
//Should be 80 bytes (0x014F(335) - 0x0100(256)) + 1 to include the last address
33
-
buffer: [u8; 80],
34
-
title: [char; 16],
35
-
manufacturer_code: [char; 4],
36
-
cgb_flag: CGBFlag,
37
-
// https://gbdev.io/pandocs/The_Cartridge_Header.html#01440145--new-licensee-code
38
-
license_code: [char; 2],
39
-
support_gb: bool,
40
-
cart_type: CartridgeType,
41
-
rom_size: RomSize,
42
-
ram_size: RamSize,
43
-
old_licensee_code: Option<u8>,
44
-
destination_code: DestinationCode,
45
-
version: u8,
46
-
header_checksum: u8,
47
-
global_checksum: u16,
48
-
}
49
-
50
-
impl CartridgeHeader {
51
-
fn bytes_to_chars<const N: usize>(bytes: &[u8], break_on_null: bool) -> [char; N] {
52
-
let mut chars = [0x000 as char; N];
53
-
for (i, byte) in bytes.iter().enumerate() {
54
-
if break_on_null && *byte == 0x00 {
55
-
break;
56
-
}
57
-
chars[i] = *byte as char;
58
-
}
59
-
chars
60
-
}
61
-
62
-
fn parse(rom_bytes: &[u8]) -> Result<Self, Error> {
63
-
let start = CartridgeHeaderAddress::CartridgeHeaderStart as usize;
64
-
let end = start + 80;
65
-
let header_buffer: &[u8] = rom_bytes[start..end]
66
-
.try_into()
67
-
.map_err(|_| Error::CartridgeReadError)?;
68
-
69
-
//Checks if the Nintendo logo matches the device's version. Early anti piracy feature. Neat to take note of
70
-
let nintendo_logo_from_rom = &rom_bytes[CartridgeHeaderAddress::NintendoLogoStart as usize
71
-
..CartridgeHeaderAddress::NintendoLogoEnd as usize + 1];
72
-
for (i, true_logo_byte) in NINTENDO_LOGO.iter().enumerate() {
73
-
let rom_byte = nintendo_logo_from_rom[i];
74
-
if rom_byte != *true_logo_byte {
75
-
return Err(Error::CartridgeReadError);
76
-
}
77
-
}
78
-
79
-
let title = &rom_bytes[CartridgeHeaderAddress::TitleStart as usize
80
-
..CartridgeHeaderAddress::TitleEnd as usize + 1];
81
-
let title_chars = Self::bytes_to_chars::<16>(title, true);
82
-
83
-
let manufacturer_code = &rom_bytes[CartridgeHeaderAddress::ManufacturerCodeStart as usize
84
-
..CartridgeHeaderAddress::ManufacturerCodeEnd as usize + 1];
85
-
let man_code_chars = Self::bytes_to_chars::<4>(manufacturer_code, false);
86
-
87
-
let cgb_flag_byte = rom_bytes[0x0143];
88
-
let cgb_flag = match cgb_flag_byte {
89
-
0x80 => CGBFlag::SupportsColorBackwardCompatiable,
90
-
0xC0 => CGBFlag::ColorOnly,
91
-
_ => CGBFlag::NotSet,
92
-
};
93
-
94
-
let license_code = &rom_bytes[CartridgeHeaderAddress::NewLicenseStart as usize
95
-
..CartridgeHeaderAddress::NewLicenseEnd as usize + 1];
96
-
let license_code_chars = Self::bytes_to_chars::<2>(license_code, false);
97
-
98
-
// https://gbdev.io/pandocs/The_Cartridge_Header.html#0146--sgb-flag
99
-
let sgb_flag = rom_bytes[CartridgeHeaderAddress::SgbFlag as usize] == 0x03;
100
-
101
-
let cart_type =
102
-
CartridgeType::from_byte(rom_bytes[CartridgeHeaderAddress::CartType as usize]);
103
-
104
-
let rom_size = RomSize::from_byte(rom_bytes[CartridgeHeaderAddress::RomSize as usize]);
105
-
let ram_size = RamSize::from_byte(rom_bytes[CartridgeHeaderAddress::RamSize as usize]);
106
-
107
-
let mut old_licensee_code = None;
108
-
if !sgb_flag {
109
-
old_licensee_code = Some(rom_bytes[CartridgeHeaderAddress::OldLicenseeCode as usize])
110
-
}
111
-
112
-
let destination_code =
113
-
DestinationCode::from_byte(rom_bytes[CartridgeHeaderAddress::DestinationCode as usize]);
114
-
115
-
let version = rom_bytes[CartridgeHeaderAddress::MaskRomVersion as usize];
116
-
let header_checksum = rom_bytes[CartridgeHeaderAddress::HeaderChecksum as usize];
117
-
let global_checksum = u16::from_le_bytes([
118
-
rom_bytes[CartridgeHeaderAddress::GlobalChecksumStart as usize],
119
-
rom_bytes[CartridgeHeaderAddress::CartridgeHeaderEnd as usize],
120
-
]);
121
-
122
-
Ok(Self {
123
-
buffer: header_buffer
124
-
.try_into()
125
-
.map_err(|_| Error::CartridgeReadError)?,
126
-
title: title_chars,
127
-
manufacturer_code: man_code_chars,
128
-
cgb_flag,
129
-
license_code: license_code_chars,
130
-
support_gb: sgb_flag,
131
-
cart_type,
132
-
rom_size,
133
-
ram_size,
134
-
old_licensee_code,
135
-
destination_code,
136
-
version,
137
-
header_checksum,
138
-
global_checksum,
139
-
})
140
-
}
141
-
142
-
fn print_test(&self) {
143
-
for byte in self.buffer.iter() {
144
-
print!("{} ", *byte as char);
145
-
}
146
-
}
147
-
}
148
32
149
33
fn main() -> std::io::Result<()> {
150
34
let mut rom_file = File::open(ROM_NAME)?;