1use std::fmt;
2use std::fs::OpenOptions;
3use std::io;
4use std::io::{BufReader, Read, Write};
5
6mod defines;
7
8pub struct Iso {
9 udf: bool,
10 patched: bool,
11 path: String,
12 data: Vec<u8>,
13}
14
15pub enum ActionResult {
16 PatchOK,
17 UnpatchOK,
18 WriteOK,
19}
20impl Iso {
22 pub fn new(path: &str) -> Result<Iso, io::Error> {
23 let iso_f = OpenOptions::new()
24 .read(true)
25 .write(true)
26 .create(false)
27 .open(path)?;
28 let mut reader = BufReader::new(iso_f);
29 let mut data = [0u8; 500 * 1024]; reader.read_exact(&mut data)?;
31 let data: Vec<u8> = data.to_vec();
32 let mut iso = Iso {
33 udf: false,
34 patched: false,
35 path: path.to_string(),
36 data,
37 };
38 iso.check_iso();
39 Ok(iso)
40 }
41 pub fn check_iso(&mut self) {
42 self.check_udf();
43 self.check_patched();
44 }
45 pub fn check_udf(&mut self) -> bool {
46 self.udf = false;
47 for i in 1..64 {
48 let offset = ((LBA_SIZE * i) + 32768 + 1) as usize;
49 if self.data[offset..offset + 3] == b"NSR".to_owned() {
50 self.udf = true;
51 break;
52 }
53 }
54 return self.udf;
55 }
56
57 pub fn check_patched(&mut self) -> bool {
58 let offset = ((LBA_SIZE * 14) + 25) as usize;
59 self.patched = self.data[offset..offset + 4] == b"+NSR".to_owned();
60 self.patched
61 }
62
63 pub fn patch(&mut self) -> Result<ActionResult, &'static str> {
64 if !self.udf {
65 return Err("No UDF descriptor found. Is this really an ISO?");
66 }
67 if self.patched {
68 return Err("Already patched! Did you want to unpatch?");
69 }
70 self.copy_lba(34, 14);
71 self.copy_lba(50, 15);
72 self.patch_lba(34);
73 self.patch_lba(50);
74 self.write_dvd_data();
75 self.check_iso();
76 Ok(ActionResult::PatchOK)
77 }
78
79 pub fn unpatch(&mut self) -> Result<ActionResult, &'static str> {
80 if !self.udf {
81 return Err("No UDF descriptor found. Is this really an ISO?");
82 }
83 if !self.patched {
84 return Err("File isn't patched! Did you want to patch?");
85 }
86 self.copy_lba(14, 34);
87 self.copy_lba(15, 50);
88 let zeros = vec![0u8; LBA_SIZE as usize];
89 self.write_lba(&zeros, 14);
90 self.write_lba(&zeros, 15);
91 for i in 0..12 {
92 self.write_lba(&zeros, 128 + i);
93 }
94 self.check_iso();
95 Ok(ActionResult::UnpatchOK)
96 }
97 pub fn write(&self) -> Result<ActionResult, io::Error> {
98 let mut iso_f = OpenOptions::new()
99 .read(false)
100 .write(true)
101 .create(false)
102 .open(&self.path)?;
103 iso_f.write_all(&self.data)?;
104 Ok(ActionResult::WriteOK)
105 }
106}
107
108impl Iso {
110 fn patch_lba(&mut self, dst_lba: u64) {
111 let dst_s = (dst_lba * LBA_SIZE) as usize;
112 let dst_e = dst_s + LBA_SIZE as usize;
113 let mut lba = self.data[dst_s..dst_e].to_vec();
114
115 lba[188] = 128;
116 lba[189] = 0;
117
118 let desc_crc_len: u16 = (lba[10] as u16) | ((lba[11] as u16) << 8);
119 let desc: Vec<u8> = lba[16..2048].to_vec();
120 let desc_crc = Self::crc(&desc, desc_crc_len as usize);
121 let desc_crc_bytes = desc_crc.to_le_bytes();
122 lba[8] = desc_crc_bytes[0];
123 lba[9] = desc_crc_bytes[1];
124
125 let mut checksum = 0u8;
126 for i in 0..16 {
127 checksum = checksum.wrapping_add(lba[i]);
128 }
129 checksum = checksum.wrapping_sub(lba[4]);
130 lba[4] = checksum;
131 self.write_lba(&lba, dst_lba);
132 }
133
134 fn write_lba(&mut self, lba: &Vec<u8>, dst_lba: u64) {
135 let dst_s = (dst_lba * LBA_SIZE) as usize;
136 let dst_e = dst_s + (LBA_SIZE as usize);
137 self.data[dst_s..dst_e].copy_from_slice(&lba);
138 }
139
140 fn copy_lba(&mut self, slba: u64, dlba: u64) {
141 let src_start = (LBA_SIZE * slba) as usize;
142 let src_end = src_start + (LBA_SIZE as usize);
143 let lba = self.data[src_start..src_end].to_vec();
144 let dest_start = (LBA_SIZE * dlba) as usize;
145 let dest_end = dest_start + (LBA_SIZE as usize);
146 self.data[dest_start..dest_end].copy_from_slice(&lba[..])
147 }
148
149 fn write_dvd_data(&mut self) {
150 let dst_s = (128 * LBA_SIZE) as usize;
151 let dst_e = dst_s + 12 * (LBA_SIZE as usize);
152 self.data[dst_s..dst_e].copy_from_slice(&defines::DVD_DATA);
153 }
154}
155
156impl Iso {
158 fn crc(block: &[u8], desc_crc_len: usize) -> u16 {
159 let mut crc = 0u16;
160 for i in 0..desc_crc_len {
161 let crc_bytes = crc.to_le_bytes();
162 let crc_h = crc_bytes[0];
163 let crc_l = crc_bytes[1];
164 crc = (crc_h as u16) << 8;
165 let j: usize = (crc_l ^ block[i]).into();
166 crc ^= defines::CRC_LOOKUP[j];
167 }
168 crc
169 }
170}
171
172impl fmt::Display for Iso {
173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 write!(
175 f,
176 "Path:\t{}\nUDF:\t{}\nPatch:\t{}",
177 self.path, self.udf, self.patched
178 )
179 }
180}
181
182const LBA_SIZE: u64 = 2048;