From 663225b7a25b36ab93fb008c20ddb316879f22fb Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sat, 10 May 2025 20:00:43 -0400 Subject: [Rust] Move `BinaryReader` and `BinaryWriter` into `binary_view` module Both of these are associated directly to a `BinaryView` and only exist as accessors onto it. --- rust/src/binary_reader.rs | 175 ----------------------------------------- rust/src/binary_view.rs | 7 +- rust/src/binary_view/reader.rs | 175 +++++++++++++++++++++++++++++++++++++++++ rust/src/binary_view/writer.rs | 151 +++++++++++++++++++++++++++++++++++ rust/src/binary_writer.rs | 151 ----------------------------------- rust/src/lib.rs | 2 - 6 files changed, 332 insertions(+), 329 deletions(-) delete mode 100644 rust/src/binary_reader.rs create mode 100644 rust/src/binary_view/reader.rs create mode 100644 rust/src/binary_view/writer.rs delete mode 100644 rust/src/binary_writer.rs (limited to 'rust/src') diff --git a/rust/src/binary_reader.rs b/rust/src/binary_reader.rs deleted file mode 100644 index e96e552a..00000000 --- a/rust/src/binary_reader.rs +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2022-2025 Vector 35 Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! A convenience class for reading binary data - -use binaryninjacore_sys::*; -use std::fmt::Debug; - -use crate::binary_view::{BinaryView, BinaryViewBase}; -use crate::Endianness; - -use crate::rc::Ref; -use std::io::{ErrorKind, Read, Seek, SeekFrom}; - -pub struct BinaryReader { - view: Ref, - handle: *mut BNBinaryReader, -} - -impl BinaryReader { - pub fn new(view: &BinaryView) -> Self { - let handle = unsafe { BNCreateBinaryReader(view.handle) }; - Self { - view: view.to_owned(), - handle, - } - } - - pub fn new_with_opts(view: &BinaryView, options: &BinaryReaderOptions) -> Self { - let mut reader = Self::new(view); - if let Some(endianness) = options.endianness { - reader.set_endianness(endianness); - } - // Set the virtual base before we seek. - if let Some(virtual_base) = options.virtual_base { - reader.set_virtual_base(virtual_base); - } - if let Some(address) = options.address { - reader.seek_to_offset(address); - } - reader - } - - pub fn endianness(&self) -> Endianness { - unsafe { BNGetBinaryReaderEndianness(self.handle) } - } - - pub fn set_endianness(&mut self, endianness: Endianness) { - unsafe { BNSetBinaryReaderEndianness(self.handle, endianness) } - } - - pub fn virtual_base(&self) -> u64 { - unsafe { BNGetBinaryReaderVirtualBase(self.handle) } - } - - pub fn set_virtual_base(&mut self, virtual_base_addr: u64) { - unsafe { BNSetBinaryReaderVirtualBase(self.handle, virtual_base_addr) } - } - - /// Prefer using [crate::binary_reader::BinaryReader::seek] over this. - pub fn seek_to_offset(&mut self, offset: u64) { - unsafe { BNSeekBinaryReader(self.handle, offset) } - } - - /// Prefer using [crate::binary_reader::BinaryReader::seek] over this. - pub fn seek_to_relative_offset(&mut self, offset: i64) { - unsafe { BNSeekBinaryReaderRelative(self.handle, offset) } - } - - pub fn offset(&self) -> u64 { - unsafe { BNGetReaderPosition(self.handle) } - } - - /// Are we at the end of the file? - pub fn is_eof(&self) -> bool { - unsafe { BNIsEndOfFile(self.handle) } - } -} - -impl Debug for BinaryReader { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("BinaryReader") - .field("offset", &self.offset()) - .field("virtual_base", &self.virtual_base()) - .field("endianness", &self.endianness()) - .finish() - } -} - -impl Seek for BinaryReader { - /// Seek to the specified position. - fn seek(&mut self, pos: SeekFrom) -> std::io::Result { - match pos { - SeekFrom::Current(offset) => self.seek_to_relative_offset(offset), - SeekFrom::Start(offset) => self.seek_to_offset(offset), - SeekFrom::End(end_offset) => { - // We do NOT need to add the image base here as - // the reader (unlike the writer) can set the virtual base. - let offset = - self.view - .len() - .checked_add_signed(end_offset) - .ok_or(std::io::Error::new( - ErrorKind::Other, - "Seeking from end overflowed", - ))?; - self.seek_to_offset(offset); - } - }; - - Ok(self.offset()) - } -} - -impl Read for BinaryReader { - fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - let len = buf.len(); - - let result = unsafe { BNReadData(self.handle, buf.as_mut_ptr() as *mut _, len) }; - - if !result { - Err(std::io::Error::new(ErrorKind::Other, "Read out of bounds")) - } else { - Ok(len) - } - } -} - -impl Drop for BinaryReader { - fn drop(&mut self) { - unsafe { BNFreeBinaryReader(self.handle) } - } -} - -unsafe impl Sync for BinaryReader {} -unsafe impl Send for BinaryReader {} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] -pub struct BinaryReaderOptions { - endianness: Option, - virtual_base: Option, - address: Option, -} - -impl BinaryReaderOptions { - pub fn new() -> Self { - Self::default() - } - - pub fn with_endianness(mut self, endian: Endianness) -> Self { - self.endianness = Some(endian); - self - } - - pub fn with_virtual_base(mut self, virtual_base_addr: u64) -> Self { - self.virtual_base = Some(virtual_base_addr); - self - } - - pub fn with_address(mut self, address: u64) -> Self { - self.address = Some(address); - self - } -} diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs index 65bab463..1aa97891 100644 --- a/rust/src/binary_view.rs +++ b/rust/src/binary_view.rs @@ -26,7 +26,6 @@ use binaryninjacore_sys::*; use crate::architecture::{Architecture, CoreArchitecture}; use crate::base_detection::BaseAddressDetection; use crate::basic_block::BasicBlock; -use crate::binary_view::memory_map::MemoryMap; use crate::component::Component; use crate::confidence::Conf; use crate::data_buffer::DataBuffer; @@ -66,6 +65,12 @@ use std::{result, slice}; // TODO : general reorg of modules related to bv pub mod memory_map; +pub mod reader; +pub mod writer; + +pub use memory_map::MemoryMap; +pub use reader::BinaryReader; +pub use writer::BinaryWriter; pub type Result = result::Result; pub type BinaryViewEventType = BNBinaryViewEventType; diff --git a/rust/src/binary_view/reader.rs b/rust/src/binary_view/reader.rs new file mode 100644 index 00000000..7b49f28d --- /dev/null +++ b/rust/src/binary_view/reader.rs @@ -0,0 +1,175 @@ +// Copyright 2022-2025 Vector 35 Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! A convenience class for reading binary data + +use binaryninjacore_sys::*; +use std::fmt::Debug; + +use crate::binary_view::{BinaryView, BinaryViewBase}; +use crate::Endianness; + +use crate::rc::Ref; +use std::io::{ErrorKind, Read, Seek, SeekFrom}; + +pub struct BinaryReader { + view: Ref, + handle: *mut BNBinaryReader, +} + +impl BinaryReader { + pub fn new(view: &BinaryView) -> Self { + let handle = unsafe { BNCreateBinaryReader(view.handle) }; + Self { + view: view.to_owned(), + handle, + } + } + + pub fn new_with_opts(view: &BinaryView, options: &BinaryReaderOptions) -> Self { + let mut reader = Self::new(view); + if let Some(endianness) = options.endianness { + reader.set_endianness(endianness); + } + // Set the virtual base before we seek. + if let Some(virtual_base) = options.virtual_base { + reader.set_virtual_base(virtual_base); + } + if let Some(address) = options.address { + reader.seek_to_offset(address); + } + reader + } + + pub fn endianness(&self) -> Endianness { + unsafe { BNGetBinaryReaderEndianness(self.handle) } + } + + pub fn set_endianness(&mut self, endianness: Endianness) { + unsafe { BNSetBinaryReaderEndianness(self.handle, endianness) } + } + + pub fn virtual_base(&self) -> u64 { + unsafe { BNGetBinaryReaderVirtualBase(self.handle) } + } + + pub fn set_virtual_base(&mut self, virtual_base_addr: u64) { + unsafe { BNSetBinaryReaderVirtualBase(self.handle, virtual_base_addr) } + } + + /// Prefer using [crate::reader::BinaryReader::seek] over this. + pub fn seek_to_offset(&mut self, offset: u64) { + unsafe { BNSeekBinaryReader(self.handle, offset) } + } + + /// Prefer using [crate::reader::BinaryReader::seek] over this. + pub fn seek_to_relative_offset(&mut self, offset: i64) { + unsafe { BNSeekBinaryReaderRelative(self.handle, offset) } + } + + pub fn offset(&self) -> u64 { + unsafe { BNGetReaderPosition(self.handle) } + } + + /// Are we at the end of the file? + pub fn is_eof(&self) -> bool { + unsafe { BNIsEndOfFile(self.handle) } + } +} + +impl Debug for BinaryReader { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("BinaryReader") + .field("offset", &self.offset()) + .field("virtual_base", &self.virtual_base()) + .field("endianness", &self.endianness()) + .finish() + } +} + +impl Seek for BinaryReader { + /// Seek to the specified position. + fn seek(&mut self, pos: SeekFrom) -> std::io::Result { + match pos { + SeekFrom::Current(offset) => self.seek_to_relative_offset(offset), + SeekFrom::Start(offset) => self.seek_to_offset(offset), + SeekFrom::End(end_offset) => { + // We do NOT need to add the image base here as + // the reader (unlike the writer) can set the virtual base. + let offset = + self.view + .len() + .checked_add_signed(end_offset) + .ok_or(std::io::Error::new( + ErrorKind::Other, + "Seeking from end overflowed", + ))?; + self.seek_to_offset(offset); + } + }; + + Ok(self.offset()) + } +} + +impl Read for BinaryReader { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + let len = buf.len(); + + let result = unsafe { BNReadData(self.handle, buf.as_mut_ptr() as *mut _, len) }; + + if !result { + Err(std::io::Error::new(ErrorKind::Other, "Read out of bounds")) + } else { + Ok(len) + } + } +} + +impl Drop for BinaryReader { + fn drop(&mut self) { + unsafe { BNFreeBinaryReader(self.handle) } + } +} + +unsafe impl Sync for BinaryReader {} +unsafe impl Send for BinaryReader {} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct BinaryReaderOptions { + endianness: Option, + virtual_base: Option, + address: Option, +} + +impl BinaryReaderOptions { + pub fn new() -> Self { + Self::default() + } + + pub fn with_endianness(mut self, endian: Endianness) -> Self { + self.endianness = Some(endian); + self + } + + pub fn with_virtual_base(mut self, virtual_base_addr: u64) -> Self { + self.virtual_base = Some(virtual_base_addr); + self + } + + pub fn with_address(mut self, address: u64) -> Self { + self.address = Some(address); + self + } +} diff --git a/rust/src/binary_view/writer.rs b/rust/src/binary_view/writer.rs new file mode 100644 index 00000000..176a54d8 --- /dev/null +++ b/rust/src/binary_view/writer.rs @@ -0,0 +1,151 @@ +// Copyright 2022-2025 Vector 35 Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! A convenience class for writing binary data + +use binaryninjacore_sys::*; +use std::fmt::Debug; + +use crate::binary_view::{BinaryView, BinaryViewBase, BinaryViewExt}; +use crate::Endianness; + +use crate::rc::Ref; +use std::io::{ErrorKind, Seek, SeekFrom, Write}; + +pub struct BinaryWriter { + view: Ref, + handle: *mut BNBinaryWriter, +} + +impl BinaryWriter { + pub fn new(view: &BinaryView) -> Self { + let handle = unsafe { BNCreateBinaryWriter(view.handle) }; + Self { + view: view.to_owned(), + handle, + } + } + + pub fn new_with_opts(view: &BinaryView, options: &BinaryWriterOptions) -> Self { + let mut writer = Self::new(view); + if let Some(endianness) = options.endianness { + writer.set_endianness(endianness); + } + if let Some(address) = options.address { + writer.seek_to_offset(address); + } + writer + } + + pub fn endianness(&self) -> Endianness { + unsafe { BNGetBinaryWriterEndianness(self.handle) } + } + + pub fn set_endianness(&mut self, endianness: Endianness) { + unsafe { BNSetBinaryWriterEndianness(self.handle, endianness) } + } + + pub fn seek_to_offset(&mut self, offset: u64) { + unsafe { BNSeekBinaryWriter(self.handle, offset) } + } + + pub fn seek_to_relative_offset(&mut self, offset: i64) { + unsafe { BNSeekBinaryWriterRelative(self.handle, offset) } + } + + pub fn offset(&self) -> u64 { + unsafe { BNGetWriterPosition(self.handle) } + } +} + +impl Debug for BinaryWriter { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("BinaryWriter") + .field("offset", &self.offset()) + .field("endianness", &self.endianness()) + .finish() + } +} + +impl Seek for BinaryWriter { + /// Seek to the specified position. + fn seek(&mut self, pos: SeekFrom) -> std::io::Result { + match pos { + SeekFrom::Current(offset) => self.seek_to_relative_offset(offset), + SeekFrom::Start(offset) => self.seek_to_offset(offset), + SeekFrom::End(end_offset) => { + let view_end = self.view.original_image_base() + self.view.len(); + let offset = view_end + .checked_add_signed(end_offset) + .ok_or(std::io::Error::new( + ErrorKind::Other, + "Seeking from end overflowed", + ))?; + self.seek_to_offset(offset); + } + }; + + Ok(self.offset()) + } +} + +impl Write for BinaryWriter { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + let len = buf.len(); + let result = unsafe { BNWriteData(self.handle, buf.as_ptr() as *mut _, len) }; + if !result { + Err(std::io::Error::new( + std::io::ErrorKind::Other, + "write out of bounds", + )) + } else { + Ok(len) + } + } + + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} + +impl Drop for BinaryWriter { + fn drop(&mut self) { + unsafe { BNFreeBinaryWriter(self.handle) } + } +} + +unsafe impl Sync for BinaryWriter {} +unsafe impl Send for BinaryWriter {} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct BinaryWriterOptions { + endianness: Option, + address: Option, +} + +impl BinaryWriterOptions { + pub fn new() -> Self { + Self::default() + } + + pub fn with_endianness(mut self, endian: Endianness) -> Self { + self.endianness = Some(endian); + self + } + + pub fn with_address(mut self, address: u64) -> Self { + self.address = Some(address); + self + } +} diff --git a/rust/src/binary_writer.rs b/rust/src/binary_writer.rs deleted file mode 100644 index 176a54d8..00000000 --- a/rust/src/binary_writer.rs +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2022-2025 Vector 35 Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! A convenience class for writing binary data - -use binaryninjacore_sys::*; -use std::fmt::Debug; - -use crate::binary_view::{BinaryView, BinaryViewBase, BinaryViewExt}; -use crate::Endianness; - -use crate::rc::Ref; -use std::io::{ErrorKind, Seek, SeekFrom, Write}; - -pub struct BinaryWriter { - view: Ref, - handle: *mut BNBinaryWriter, -} - -impl BinaryWriter { - pub fn new(view: &BinaryView) -> Self { - let handle = unsafe { BNCreateBinaryWriter(view.handle) }; - Self { - view: view.to_owned(), - handle, - } - } - - pub fn new_with_opts(view: &BinaryView, options: &BinaryWriterOptions) -> Self { - let mut writer = Self::new(view); - if let Some(endianness) = options.endianness { - writer.set_endianness(endianness); - } - if let Some(address) = options.address { - writer.seek_to_offset(address); - } - writer - } - - pub fn endianness(&self) -> Endianness { - unsafe { BNGetBinaryWriterEndianness(self.handle) } - } - - pub fn set_endianness(&mut self, endianness: Endianness) { - unsafe { BNSetBinaryWriterEndianness(self.handle, endianness) } - } - - pub fn seek_to_offset(&mut self, offset: u64) { - unsafe { BNSeekBinaryWriter(self.handle, offset) } - } - - pub fn seek_to_relative_offset(&mut self, offset: i64) { - unsafe { BNSeekBinaryWriterRelative(self.handle, offset) } - } - - pub fn offset(&self) -> u64 { - unsafe { BNGetWriterPosition(self.handle) } - } -} - -impl Debug for BinaryWriter { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("BinaryWriter") - .field("offset", &self.offset()) - .field("endianness", &self.endianness()) - .finish() - } -} - -impl Seek for BinaryWriter { - /// Seek to the specified position. - fn seek(&mut self, pos: SeekFrom) -> std::io::Result { - match pos { - SeekFrom::Current(offset) => self.seek_to_relative_offset(offset), - SeekFrom::Start(offset) => self.seek_to_offset(offset), - SeekFrom::End(end_offset) => { - let view_end = self.view.original_image_base() + self.view.len(); - let offset = view_end - .checked_add_signed(end_offset) - .ok_or(std::io::Error::new( - ErrorKind::Other, - "Seeking from end overflowed", - ))?; - self.seek_to_offset(offset); - } - }; - - Ok(self.offset()) - } -} - -impl Write for BinaryWriter { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - let len = buf.len(); - let result = unsafe { BNWriteData(self.handle, buf.as_ptr() as *mut _, len) }; - if !result { - Err(std::io::Error::new( - std::io::ErrorKind::Other, - "write out of bounds", - )) - } else { - Ok(len) - } - } - - fn flush(&mut self) -> std::io::Result<()> { - Ok(()) - } -} - -impl Drop for BinaryWriter { - fn drop(&mut self) { - unsafe { BNFreeBinaryWriter(self.handle) } - } -} - -unsafe impl Sync for BinaryWriter {} -unsafe impl Send for BinaryWriter {} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] -pub struct BinaryWriterOptions { - endianness: Option, - address: Option, -} - -impl BinaryWriterOptions { - pub fn new() -> Self { - Self::default() - } - - pub fn with_endianness(mut self, endian: Endianness) -> Self { - self.endianness = Some(endian); - self - } - - pub fn with_address(mut self, address: u64) -> Self { - self.address = Some(address); - self - } -} diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 1b02da0d..80baae43 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -32,9 +32,7 @@ pub mod architecture; pub mod background_task; pub mod base_detection; pub mod basic_block; -pub mod binary_reader; pub mod binary_view; -pub mod binary_writer; pub mod calling_convention; pub mod collaboration; pub mod command; -- cgit v1.3.1