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::{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::other("Seeking from end overflowed"))?;
92 self.seek_to_offset(offset);
93 }
94 };
95
96 Ok(self.offset())
97 }
98}
99
100impl Write for BinaryWriter {
101 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
102 let len = buf.len();
103 let result = unsafe { BNWriteData(self.handle, buf.as_ptr() as *mut _, len) };
104 if !result {
105 Err(std::io::Error::other("write out of bounds"))
106 } else {
107 Ok(len)
108 }
109 }
110
111 fn flush(&mut self) -> std::io::Result<()> {
112 Ok(())
113 }
114}
115
116impl Drop for BinaryWriter {
117 fn drop(&mut self) {
118 unsafe { BNFreeBinaryWriter(self.handle) }
119 }
120}
121
122unsafe impl Sync for BinaryWriter {}
123unsafe impl Send for BinaryWriter {}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
126pub struct BinaryWriterOptions {
127 endianness: Option<Endianness>,
128 address: Option<u64>,
129}
130
131impl BinaryWriterOptions {
132 pub fn new() -> Self {
133 Self::default()
134 }
135
136 pub fn with_endianness(mut self, endian: Endianness) -> Self {
137 self.endianness = Some(endian);
138 self
139 }
140
141 pub fn with_address(mut self, address: u64) -> Self {
142 self.address = Some(address);
143 self
144 }
145}