1use crate::error::{Error, Result};
4use goblin::container::Ctx;
5use scroll::ctx::{SizeWith, TryIntoCtx};
6
7#[derive(Debug)]
9pub(crate) struct Location {
10 pub offset: usize,
12
13 pub size: usize,
15
16 pub ctx: Ctx,
18}
19
20#[derive(Debug)]
22pub struct Rooted<T> {
23 pub value: T,
24 location: Location,
25}
26
27impl<T> Rooted<T> {
28 pub(crate) fn new(location: Location, value: T) -> Self {
29 Self { value, location }
30 }
31
32 pub fn patch_with<U>(&self, value: U) -> Result<Patch>
34 where
35 U: TryIntoCtx<Ctx, [u8], Error = goblin::error::Error> + SizeWith<Ctx>,
36 {
37 Patch::from_ctx(&self.location, value)
38 }
39
40 pub fn patch_with_bytes(&self, value: &[u8]) -> Result<Patch> {
42 Patch::from_bytes(&self.location, value)
43 }
44}
45
46impl<T> std::ops::Deref for Rooted<T> {
47 type Target = T;
48
49 fn deref(&self) -> &Self::Target {
50 &self.value
51 }
52}
53
54#[derive(Debug)]
56pub struct Patch {
57 offset: usize,
58 data: Vec<u8>,
59}
60
61impl Patch {
62 fn from_ctx<T>(location: &Location, data: T) -> Result<Self>
63 where
64 T: TryIntoCtx<Ctx, [u8], Error = goblin::error::Error> + SizeWith<Ctx>,
65 {
66 let size = T::size_with(&location.ctx);
67 if size > location.size {
68 return Err(Error::PatchTooBig);
69 }
70 let mut buf = vec![0u8; size];
71 data.try_into_ctx(&mut buf, location.ctx)?;
72 Ok(Self {
73 offset: location.offset,
74 data: buf,
75 })
76 }
77
78 fn from_bytes(location: &Location, data: &[u8]) -> Result<Self> {
79 if data.len() > location.size {
80 return Err(Error::PatchTooBig);
81 }
82 Ok(Self {
83 offset: location.offset,
84 data: data.to_vec(),
85 })
86 }
87
88 pub fn apply(&self, data: &mut [u8]) {
90 data[self.offset..(self.offset + self.data.len())].clone_from_slice(&self.data);
91 }
92}