use crate::error::{self, check, Result};
use crate::ffi;
use std::ffi::CString;
use std::ptr;
use super::armor_type::ArmorType;
use super::input::Input;
pub struct Output {
handle: ffi::rnp_output_t,
}
#[derive(Clone, Copy, Debug, Default)]
pub struct OutputFileFlags(pub u32);
impl OutputFileFlags {
pub const OVERWRITE: Self = Self(ffi::RNP_OUTPUT_FILE_OVERWRITE as u32);
pub const RANDOM: Self = Self(ffi::RNP_OUTPUT_FILE_RANDOM as u32);
pub fn bits(self) -> u32 {
self.0
}
}
impl std::ops::BitOr for OutputFileFlags {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
Self(self.0 | rhs.0)
}
}
impl Output {
pub fn to_memory() -> Result<Self> {
Self::to_memory_with_max(0)
}
pub fn to_memory_with_max(max_alloc: usize) -> Result<Self> {
let mut handle: ffi::rnp_output_t = ptr::null_mut();
unsafe {
check(ffi::rnp_output_to_memory(&mut handle, max_alloc))?;
}
if handle.is_null() {
return Err(error::Error::NullPointer);
}
Ok(Output { handle })
}
pub fn to_null() -> Result<Self> {
let mut handle: ffi::rnp_output_t = ptr::null_mut();
unsafe {
check(ffi::rnp_output_to_null(&mut handle))?;
}
if handle.is_null() {
return Err(error::Error::NullPointer);
}
Ok(Output { handle })
}
pub fn to_path(path: &str) -> Result<Self> {
let c = CString::new(path).map_err(|_| error::Error::PathNul)?;
let mut handle: ffi::rnp_output_t = ptr::null_mut();
unsafe {
check(ffi::rnp_output_to_path(&mut handle, c.as_ptr()))?;
}
if handle.is_null() {
return Err(error::Error::NullPointer);
}
Ok(Output { handle })
}
pub fn to_file(path: &str, flags: OutputFileFlags) -> Result<Self> {
let c = CString::new(path).map_err(|_| error::Error::PathNul)?;
let mut handle: ffi::rnp_output_t = ptr::null_mut();
unsafe {
check(ffi::rnp_output_to_file(&mut handle, c.as_ptr(), flags.bits()))?;
}
if handle.is_null() {
return Err(error::Error::NullPointer);
}
Ok(Output { handle })
}
pub fn to_stdout() -> Result<Self> {
let mut handle: ffi::rnp_output_t = ptr::null_mut();
unsafe {
check(ffi::rnp_output_to_stdout(&mut handle))?;
}
if handle.is_null() {
return Err(error::Error::NullPointer);
}
Ok(Output { handle })
}
pub fn to_armor(base: &Output, ty: ArmorType) -> Result<Self> {
let mut handle: ffi::rnp_output_t = ptr::null_mut();
let c = CString::new(ty.as_str()).unwrap();
unsafe {
check(ffi::rnp_output_to_armor(base.handle, &mut handle, c.as_ptr()))?;
}
if handle.is_null() {
return Err(error::Error::NullPointer);
}
Ok(Output { handle })
}
pub fn write(&mut self, bytes: &[u8]) -> Result<usize> {
let mut written: usize = 0;
unsafe {
check(ffi::rnp_output_write(
self.handle,
bytes.as_ptr() as *const _,
bytes.len(),
&mut written,
))?;
}
Ok(written)
}
pub fn finish(&mut self) -> Result<()> {
unsafe { check(ffi::rnp_output_finish(self.handle)) }
}
pub fn set_armor_line_length(&mut self, line_len: usize) -> Result<()> {
unsafe { check(ffi::rnp_output_armor_set_line_length(self.handle, line_len)) }
}
pub fn pipe(&mut self, input: &Input) -> Result<()> {
unsafe { check(ffi::rnp_output_pipe(input.as_ptr(), self.handle)) }
}
pub fn into_bytes(self) -> Result<Vec<u8>> {
let mut buf: *mut u8 = ptr::null_mut();
let mut len: usize = 0;
unsafe {
let get = check(ffi::rnp_output_memory_get_buf(
self.handle,
&mut buf,
&mut len,
true, ));
if get.is_err() {
return get.map(|_| Vec::new());
}
if buf.is_null() || len == 0 {
Ok(Vec::new())
} else {
let v = std::slice::from_raw_parts(buf, len).to_vec();
ffi::rnp_buffer_destroy(buf as *mut _);
Ok(v)
}
}
}
pub(crate) fn as_ptr(&self) -> ffi::rnp_output_t {
self.handle
}
}
impl Drop for Output {
fn drop(&mut self) {
if !self.handle.is_null() {
unsafe {
let _ = ffi::rnp_output_destroy(self.handle);
}
self.handle = ptr::null_mut();
}
}
}