diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..ebfc1ed --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "sepatch" +version = "0.1.0" diff --git a/src/main.rs b/src/main.rs index 4e25371..e6a8ffe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use std::{fs, io::{self, BufRead, BufReader, Write}, fmt::format}; +use std::{fs, io::{self, BufRead, BufReader, Write}}; fn main() { let args : Vec = std::env::args().collect(); @@ -13,6 +13,10 @@ fn main() { return; } }; + if let Err(e) = verify_code(&codes) { + println!("verify code error: {}", e.to_string()); + return; + } if let Err(e) = apply_code(args[1].as_str(), &codes) { println!("apply code error: {}", e.to_string()); } @@ -22,7 +26,7 @@ fn read_codes(code_file : &str) -> io::Result> { let file = fs::File::open(code_file).expect("cannot open patch_code"); let reader = BufReader::new(file); let mut codes = Vec::new(); - let mut lines = 0u32; + let mut lines = 1u32; for line in reader.lines() { if let Ok(l) = line { let r_str = l.as_str(); @@ -35,31 +39,218 @@ fn read_codes(code_file : &str) -> io::Result> { codes.push((lines, val2.unwrap())); } } // else skip + lines += 1; } } Ok(codes) } -fn verify_code(codes : Vec<(u32, u32)>) -> Result<(), String> { - let pos = 0usize; - while pos < codes.len() { +fn verify_code(codes : &Vec<(u32, u32)>) -> Result<(), String> { + let mut pos = 0usize; + let max_len = codes.len(); + let mut search_code = false; + while pos < max_len { + let line = codes[pos].0; let first_code = codes[pos].1; - let op_code = first_code >> 28; - let mut search_code = false; + let op_code = (first_code >> 28) as u8; match op_code { 0x0 | 0x1 |0x2 => { - return Err(format!("{}", 123)); + if search_code { + if first_code & 0xf000000 != 0x8000000 { + return Err(format!("wrong code at line {}: need search code after search", line)); + } + search_code = false + } + if pos + 2 > max_len { + return Err(format!("wrong code at line {}: unexpected end", line)); + } + pos += 2; + } + 0x4 => { + if search_code { + if first_code & 0xf000000 != 0x8000000 { + return Err(format!("wrong code at line {}: need search code after search", line)); + } + search_code = false + } + if pos + 4 > max_len { + return Err(format!("wrong code at line {}: unexpected end", line)); + } + pos += 4; + } + 0x5 => { + if search_code { + return Err(format!("wrong code at line {}: need search code after search", line)); + } + if pos + 4 > max_len { + return Err(format!("wrong code at line {}: unexpected end", line)); + } + pos += 4; + } + 0x8 => { + if search_code { + return Err(format!("wrong code at line {}: need search code after search", line)); + } + let search_bytes = (first_code & 0xffff) as usize; + if search_bytes == 0 { + return Err(format!("wrong code at line {}: search length should not be 0", line)); + } + let code_len = ((search_bytes - 1) / 4 + 1) * 2; + if pos + code_len > max_len { + return Err(format!("wrong code at line {}: unexpected end", line)); + } + search_code = true; + pos += code_len; + } + 0xa => { + if search_code { + return Err(format!("wrong code at line {}: need search code after search", line)); + } + if pos + 1 >= max_len { + return Err(format!("wrong code at line {}: unexpected end", line)); + } + let write_bytes = codes[pos + 1].1 as usize; + if write_bytes == 0 { + return Err(format!("wrong code at line {}: write length should not be 0", line)); + } + if write_bytes > 320 { + return Err(format!("wrong code at line {}: write length should not exceed 320", line)); + } + let code_len = ((write_bytes - 1) / 8 + 1) * 2 + 2; + if pos + code_len > max_len { + return Err(format!("wrong code at line {}: unexpected end", line)); + } + pos += code_len; + } + _ => { + return Err(format!("unknown code at line {}", line)); } - _ => (), } - pos += 1; + } Ok(()) } -fn apply_code(patch_file : &str, codes : &Vec<(u32, u32)>) -> io::Result<()> { - let data = fs::read(patch_file)?; - let mut write_file = fs::OpenOptions::new().write(true).truncate(true).open(patch_file)?; - write_file.write(data.as_slice())?; +fn apply_code(patch_file : &str, codes : &Vec<(u32, u32)>) -> Result<(), String> { + let fn_map_err = |e : io::Error| format!("apply code error: {}", e.to_string()); + let mut data = fs::read(patch_file).map_err(fn_map_err)?; + let mut pos = 0usize; + let max_code_len = codes.len(); + let max_data_len = data.len(); + let mut search_addr : Option = None; + while pos < max_code_len { + let line = codes[pos].0; + let first_code = codes[pos].1; + let op_code = (first_code >> 28) as u8; + match op_code { + 0x0 => { + let val = codes[pos + 1].1 as u8; + let addr = if let Some(saddr) = search_addr { + search_addr = None; + (codes[pos].1 & 0xffffff) + saddr + } else { + codes[pos].1 & 0xfffffff + } as usize; + if addr >= max_data_len { + return Err(format!("apply code error at line {}: address overflow", line)); + } + data[addr] = val; + pos += 2; + } + 0x1 => { + let val = codes[pos + 1].1 as u16; + let addr = if let Some(saddr) = search_addr { + search_addr = None; + (codes[pos].1 & 0xffffff) + saddr + } else { + codes[pos].1 & 0xfffffff + } as usize; + if addr + 1 >= max_data_len { + return Err(format!("apply code error at line {}: address overflow", line)); + } + data[addr] = (val & 0xff) as u8; + data[addr + 1] = ((val >> 8) & 0xff) as u8; + pos += 2; + } + 0x2 => { + let val = codes[pos + 1].1; + let addr = if let Some(saddr) = search_addr { + search_addr = None; + (codes[pos].1 & 0xffffff) + saddr + } else { + codes[pos].1 & 0xfffffff + } as usize; + if addr + 3 >= max_data_len { + return Err(format!("apply code error at line {}: address overflow", line)); + } + data[addr] = (val & 0xff) as u8; + data[addr + 1] = ((val >> 8) & 0xff) as u8; + data[addr + 2] = ((val >> 16) & 0xff) as u8; + data[addr + 3] = ((val >> 24) & 0xff) as u8; + pos += 2; + } + 0x4 => { + let mut val = codes[pos + 1].1; + let mut addr = if let Some(saddr) = search_addr { + search_addr = None; + (codes[pos].1 & 0xffffff) + saddr + } else { + codes[pos].1 & 0xfffffff + } as usize; + let mut count = (codes[pos + 2].1 & 0xfff0000) >> 16; + let addr_diff = codes[pos + 2].1 & 0xffff; + let val_diff = codes[pos + 3].1; + while count != 0 { + if codes[pos].1 & 0xf000000 == 0x1000000 { + if addr >= max_data_len { + return Err(format!("apply code error at line {}: address overflow", line)); + } + data[addr] = (val & 0xff) as u8; + } else if codes[pos].1 & 0xf000000 == 0x2000000 { + if addr + 1 >= max_data_len { + return Err(format!("apply code error at line {}: address overflow", line)); + } + data[addr] = (val & 0xff) as u8; + data[addr + 1] = ((val >> 8) & 0xff) as u8; + } else { + if addr + 3 >= max_data_len { + return Err(format!("apply code error at line {}: address overflow", line)); + } + data[addr] = (val & 0xff) as u8; + data[addr + 1] = ((val >> 8) & 0xff) as u8; + data[addr + 2] = ((val >> 16) & 0xff) as u8; + data[addr + 3] = ((val >> 24) & 0xff) as u8; + } + count -= 1; + addr += addr_diff as usize; + val += val_diff; + } + pos += 4; + } + 0x5 | 0x8 => { + return Err(format!("apply code error at line {}: not supported", line)); + } + 0xa => { + let mut addr = (codes[pos].1 & 0xfffffff) as usize; + let write_bytes = codes[pos + 1].1 as usize; + if addr + write_bytes>= max_data_len { + return Err(format!("apply code error at line {}: address overflow", line)); + } + let mut bytes = 0; + while bytes < write_bytes { + let offset = pos + 2 + (bytes / 4); + let shift = (3 - (bytes % 4)) * 8; + data[addr] = ((codes[offset].1 >> shift) & 0xff) as u8; + bytes += 1; + addr += 1; + } + let code_len = ((write_bytes - 1) / 8 + 1) * 2 + 2; + pos += code_len; + } + _ => () + } + } + let mut write_file = fs::OpenOptions::new().write(true).truncate(true).open(patch_file).map_err(fn_map_err)?; + write_file.write(data.as_slice()).map_err(fn_map_err)?; Ok(()) }