diff --git a/.gitignore b/.gitignore index 3bc6b6f..fbf1ddc 100644 --- a/.gitignore +++ b/.gitignore @@ -73,3 +73,4 @@ docs/_build/ .python-version /tests/files/* +.agentbridge diff --git a/build.rs b/build.rs index 7ff7f38..00c44fe 100644 --- a/build.rs +++ b/build.rs @@ -167,7 +167,7 @@ impl DeMangler { return Err(Error::msg(format!( "conflicting mangled symbols for {} in {}: {}, {}", demangled, - a_file.to_str().unwrap(), + a_file.to_string_lossy(), existing_mangled, mangled ))); diff --git a/src/error.rs b/src/error.rs index ae60410..cca7e59 100644 --- a/src/error.rs +++ b/src/error.rs @@ -31,4 +31,8 @@ pub enum Error { UnknownDataType(i32), #[error("unknown pixel type: {0}")] UnknownPixelType(i32), + #[error("wrong attachment type: {0}")] + InvalidAttachmentType(String), + #[error("raw data is malformed")] + MalformedData, } diff --git a/src/functions.rs b/src/functions.rs index bcc4798..0066f43 100644 --- a/src/functions.rs +++ b/src/functions.rs @@ -463,7 +463,7 @@ impl SubBlock { /// /// \\returns An error-code indicating success or failure of the operation. pub fn get_raw_data(&self, tp: RawDataType, size: i32) -> Result<(i32, Vec), Error> { - let mut data = Vec::::with_capacity(size as usize); + let mut data = vec![0u8; size as usize]; let size = Box::into_raw(Box::new(size as c_ulong)); lib_czi_error(unsafe { libCZI_SubBlockGetRawData(**self, tp as c_int, size, data.as_mut_ptr() as *mut c_void) @@ -510,7 +510,7 @@ impl Attachment { /// /// \\returns An error-code indicating success or failure of the operation. pub fn get_raw_data(&self, size: i32) -> Result<(i32, Vec), Error> { - let mut data = Vec::::with_capacity(size as usize); + let mut data = vec![0u8; size as usize]; let size = Box::into_raw(Box::new(size as c_ulong)); lib_czi_error(unsafe { libCZI_AttachmentGetRawData(**self, size, data.as_mut_ptr() as *mut c_void) @@ -518,6 +518,17 @@ impl Attachment { Ok((unsafe { *Box::from_raw(size) as i32 }, data)) } + /// convenience method that extracts some types of data + pub fn get_data(&self) -> Result { + let (n, _) = self.get_raw_data(0)?; + let (_, data) = self.get_raw_data(n)?; + Ok(match self.get_info()?.get_content_file_type()?.as_str() { + "CZTIMS" | "CZFOC" => AttachmentData::from_float(data.as_slice())?, + "CZEXP" | "CZHWS" | "CZMVM" | "CZFBMX" => AttachmentData::from_xml(data.as_slice())?, + _ => AttachmentData::Unknown(data), + }) + } + /// Release the specified attachment object. /// /// \\param attachment_object The attachment object to be released. diff --git a/src/interop.rs b/src/interop.rs index 5fe5b1c..91b3e2e 100644 --- a/src/interop.rs +++ b/src/interop.rs @@ -293,7 +293,7 @@ impl ExternalOutputStreamStruct { } } -/// This structure gather the information needed to create a reader object. +/// This structure gathers the information needed to create a reader object. impl ReaderOpenInfo { pub fn new(stream: &InputStream) -> Self { Self(ReaderOpenInfoInterop { @@ -706,25 +706,27 @@ impl AttachmentInfo { pub fn get_guid(&self) -> [u8; 16] { self.0.guid } - pub fn get_content_file_type(&self) -> [u8; 9] { - self.0.content_file_type - } + pub fn get_name(&self) -> Result { - Ok( - CStr::from_bytes_until_nul(&self.0.name.iter().map(|&i| i as u8).collect::>())? - .to_str()? - .to_string(), - ) + if self.0.name_overflow { + Ok( + unsafe { CString::from_raw(self.0.name_in_case_of_overflow as *mut c_char) } + .to_string_lossy() + .to_string(), + ) + } else { + Ok(CStr::from_bytes_until_nul( + &self.0.name.iter().map(|&i| i as u8).collect::>(), + )? + .to_string_lossy() + .to_string()) + } } - pub fn get_name_overflow(&self) -> bool { - self.0.name_overflow - } - pub fn get_name_in_case_of_overflow(&self) -> Result { - Ok( - unsafe { CString::from_raw(self.0.name_in_case_of_overflow as *mut c_char) } - .to_str()? - .to_string(), - ) + + pub fn get_content_file_type(&self) -> Result { + Ok(CStr::from_bytes_until_nul(&self.0.content_file_type)? + .to_string_lossy() + .to_string()) } } @@ -1041,10 +1043,10 @@ impl AccessorOptions { pub fn get_use_visibility_check_optimization(&self) -> bool { self.0.use_visibility_check_optimization } - pub fn get_additional_parameters(&self) -> Result { - Ok(unsafe { CStr::from_ptr(self.0.additional_parameters) } - .to_str()? - .to_string()) + pub fn get_additional_parameters(&self) -> String { + unsafe { CStr::from_ptr(self.0.additional_parameters) } + .to_string_lossy() + .to_string() } pub fn set_background_color_r(&mut self, back_ground_color_r: f32) { self.0.back_ground_color_r = back_ground_color_r diff --git a/src/lib.rs b/src/lib.rs index a23f09c..03bb908 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ pub mod sys; pub use functions::*; pub use handle::*; pub use interop::*; -pub use misc::{Dimension, PixelType, RawDataType}; +pub use misc::{AttachmentData, Dimension, PixelType, RawDataType}; #[cfg(test)] mod tests { diff --git a/src/misc.rs b/src/misc.rs index 87dd359..fa20490 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -1,4 +1,5 @@ use crate::error::Error; +use std::ffi::CStr; use std::mem::MaybeUninit; pub fn lib_czi_error(code: std::ffi::c_int) -> Result<(), Error> { @@ -14,7 +15,71 @@ pub fn lib_czi_error(code: std::ffi::c_int) -> Result<(), Error> { } } -#[derive(Clone, Debug)] +/// container for some types of attachment data +pub enum AttachmentData { + Float(Vec), + Xml(String), + Unknown(Vec), +} + +impl AttachmentData { + pub fn attachment_type(&self) -> &str { + match self { + Self::Float(_) => "float", + Self::Xml(_) => "xml", + Self::Unknown(_) => "unknown", + } + } + + pub(crate) fn from_float(raw: &[u8]) -> Result { + if raw.len() < 8 { + Err(Error::MalformedData) + } else { + let number = u32::from_le_bytes(raw[4..8].try_into().unwrap()) as usize; + if raw.len() < 8 * number + 8 { + Err(Error::MalformedData) + } else { + let mut data = Vec::with_capacity(number); + for i in 0..number { + data.push(f64::from_le_bytes( + raw[8 + 8 * i..16 + 8 * i].try_into().unwrap(), + )); + } + Ok(Self::Float(data)) + } + } + } + + pub(crate) fn from_xml(raw: &[u8]) -> Result { + Ok(Self::Xml( + CStr::from_bytes_until_nul(raw)? + .to_string_lossy() + .to_string(), + )) + } + + pub fn try_into_float(&self) -> Result, Error> { + if let AttachmentData::Float(data) = self { + Ok(data.clone()) + } else { + Err(Error::InvalidAttachmentType( + self.attachment_type().to_string(), + )) + } + } + + pub fn try_into_xml(&self) -> Result { + if let AttachmentData::Xml(data) = self { + Ok(data.clone()) + } else { + Err(Error::InvalidAttachmentType( + self.attachment_type().to_string(), + )) + } + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub enum Dimension { /// The Z-dimension. Z = 1, @@ -48,6 +113,10 @@ impl Dimension { } dimensions } + + pub fn is_valid(&self, v: u32) -> bool { + v & (*self as u32).pow(2) > 0 + } } impl TryFrom for Dimension {