1use crate::util::{read_u32le, read_u8};
2use crate::RpnExpr;
3use std::convert::TryInto;
4use std::fmt::{self, Display, Formatter};
5use std::io::{self, Read};
6
7#[derive(Debug)]
10pub struct Patch {
11 source_file_id: u32,
12 line_no: u32,
13 offset: u32,
14 pc_section_id: u32,
15 pc_offset: u32,
16 patch_type: PatchType,
17 expr: RpnExpr,
18}
19impl Patch {
20 pub(crate) fn read_from(mut input: impl Read) -> Result<Self, io::Error> {
21 let source_file_id = read_u32le(&mut input)?;
22 let line_no = read_u32le(&mut input)?;
23 let offset = read_u32le(&mut input)?;
24 let pc_section_id = read_u32le(&mut input)?;
25 let pc_offset = read_u32le(&mut input)?;
26 let patch_type = PatchType::try_from(read_u8(&mut input)?)?;
27
28 let expr_size = read_u32le(&mut input)?.try_into().unwrap();
29 let mut expr = vec![0; expr_size];
30 input.read_exact(&mut expr)?;
31 let expr = RpnExpr::from_bytes(expr);
32
33 Ok(Self {
34 source_file_id,
35 line_no,
36 offset,
37 pc_section_id,
38 pc_offset,
39 patch_type,
40 expr,
41 })
42 }
43
44 pub fn source(&self) -> (u32, u32) {
47 (self.source_file_id, self.line_no)
48 }
49
50 pub fn offset(&self) -> u32 {
52 self.offset
53 }
54
55 pub fn patch_type(&self) -> PatchType {
57 self.patch_type
58 }
59
60 pub fn pc_section_id(&self) -> u32 {
62 self.pc_section_id
63 }
64
65 pub fn pc_offset(&self) -> u32 {
73 self.pc_offset
74 }
75
76 pub fn expr(&self) -> &RpnExpr {
78 &self.expr
79 }
80}
81
82#[derive(Debug, PartialEq, Eq, Clone, Copy)]
84pub enum PatchType {
85 Byte,
86 Word,
87 Long,
88 JrOfs,
89}
90impl PatchType {
91 fn try_from(byte: u8) -> Result<Self, io::Error> {
92 use PatchType::*;
93
94 Ok(match byte {
95 0 => Byte,
96 1 => Word,
97 2 => Long,
98 3 => JrOfs,
99 _ => {
100 return Err(io::Error::new(
101 io::ErrorKind::InvalidData,
102 "Invalid patch type",
103 ))
104 }
105 })
106 }
107
108 pub fn name(&self) -> &'static str {
110 use PatchType::*;
111
112 match self {
113 Byte => "byte",
114 Word => "word",
115 Long => "long",
116 JrOfs => "jr",
117 }
118 }
119
120 pub fn size(&self) -> u8 {
122 use PatchType::*;
123
124 match self {
125 Byte => 1,
126 Word => 2,
127 Long => 4,
128 JrOfs => 1,
129 }
130 }
131}
132impl Display for PatchType {
133 fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
134 write!(fmt, "{}", self.name())
135 }
136}