binaryninja/binary_view/
writer.rs1use binaryninjacore_sys::*;
18use std::fmt::Debug;
19
20use crate::binary_view::{BinaryView, BinaryViewBase, BinaryViewExt};
21use crate::Endianness;
22
23use crate::rc::Ref;
24use std::io::{ErrorKind, Seek, SeekFrom, Write};
25
26pub struct BinaryWriter {
27 view: Ref<BinaryView>,
28 handle: *mut BNBinaryWriter,
29}
30
31impl BinaryWriter {
32 pub fn new(view: &BinaryView) -> Self {
33 let handle = unsafe { BNCreateBinaryWriter(view.handle) };
34 Self {
35 view: view.to_owned(),
36 handle,
37 }
38 }
39
40 pub fn new_with_opts(view: &BinaryView, options: &BinaryWriterOptions) -> Self {
41 let mut writer = Self::new(view);
42 if let Some(endianness) = options.endianness {
43 writer.set_endianness(endianness);
44 }
45 if let Some(address) = options.address {
46 writer.seek_to_offset(address);
47 }
48 writer
49 }
50
51 pub fn endianness(&self) -> Endianness {
52 unsafe { BNGetBinaryWriterEndianness(self.handle) }
53 }
54
55 pub fn set_endianness(&mut self, endianness: Endianness) {
56 unsafe { BNSetBinaryWriterEndianness(self.handle, endianness) }
57 }
58
59 pub fn seek_to_offset(&mut self, offset: u64) {
60 unsafe { BNSeekBinaryWriter(self.handle, offset) }
61 }
62
63 pub fn seek_to_relative_offset(&mut self, offset: i64) {
64 unsafe { BNSeekBinaryWriterRelative(self.handle, offset) }
65 }
66
67 pub fn offset(&self) -> u64 {
68 unsafe { BNGetWriterPosition(self.handle) }
69 }
70}
71
72impl Debug for BinaryWriter {
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 f.debug_struct("BinaryWriter")
75 .field("offset", &self.offset())
76 .field("endianness", &self.endianness())
77 .finish()
78 }
79}
80
81impl Seek for BinaryWriter {
82 fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
84 match pos {
85 SeekFrom::Current(offset) => self.seek_to_relative_offset(offset),
86 SeekFrom::Start(offset) => self.seek_to_offset(offset),
87 SeekFrom::End(end_offset) => {
88 let view_end = self.view.original_image_base() + self.view.len();
89 let offset = view_end
90 .checked_add_signed(end_offset)
91 .ok_or(std::io::Error::new(
92 ErrorKind::Other,
93 "Seeking from end overflowed",
94 ))?;
95 self.seek_to_offset(offset);
96 }
97 };
98
99 Ok(self.offset())
100 }
101}
102
103impl Write for BinaryWriter {
104 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
105 let len = buf.len();
106 let result = unsafe { BNWriteData(self.handle, buf.as_ptr() as *mut _, len) };
107 if !result {
108 Err(std::io::Error::new(
109 std::io::ErrorKind::Other,
110 "write out of bounds",
111 ))
112 } else {
113 Ok(len)
114 }
115 }
116
117 fn flush(&mut self) -> std::io::Result<()> {
118 Ok(())
119 }
120}
121
122impl Drop for BinaryWriter {
123 fn drop(&mut self) {
124 unsafe { BNFreeBinaryWriter(self.handle) }
125 }
126}
127
128unsafe impl Sync for BinaryWriter {}
129unsafe impl Send for BinaryWriter {}
130
131#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
132pub struct BinaryWriterOptions {
133 endianness: Option<Endianness>,
134 address: Option<u64>,
135}
136
137impl BinaryWriterOptions {
138 pub fn new() -> Self {
139 Self::default()
140 }
141
142 pub fn with_endianness(mut self, endian: Endianness) -> Self {
143 self.endianness = Some(endian);
144 self
145 }
146
147 pub fn with_address(mut self, address: u64) -> Self {
148 self.address = Some(address);
149 self
150 }
151}