use super::entries::Entries;
use crate::error::{analyze_result, Result};
use crate::libarchive;
use crate::LendingIterator;
use log::{debug, error};
use std::slice;
pub(crate) struct BlockReader {
_entries: Entries, block_reader: BlockReaderBorrowed,
}
impl BlockReader {
pub fn new(entries: Entries) -> Self {
let block_reader = BlockReaderBorrowed::from(&entries);
BlockReader {
_entries: entries,
block_reader,
}
}
}
#[cfg(not(feature = "lending_iter"))]
impl Iterator for BlockReader {
type Item = Result<Box<[u8]>>;
fn next(&mut self) -> Option<Result<Box<[u8]>>> {
Iterator::next(&mut self.block_reader)
}
}
#[cfg(feature = "lending_iter")]
impl LendingIterator for BlockReader {
type Item<'me> = Result<&'me [u8]>;
fn next(&mut self) -> Option<Self::Item<'_>> {
crate::LendingIterator::next(&mut self.block_reader)
}
}
pub(crate) struct BlockReaderBorrowed {
archive: *mut libarchive::archive,
ended: bool,
}
unsafe impl Send for BlockReaderBorrowed {}
impl From<&Entries> for BlockReaderBorrowed {
fn from(entries: &Entries) -> Self {
Self {
archive: entries.archive,
ended: false,
}
}
}
impl BlockReaderBorrowed {
pub(crate) fn read_block(&mut self) -> Result<&[u8]> {
if self.ended {
return Ok(&[]);
}
let mut buf = std::ptr::null();
let mut offset = 0;
let mut size = 0;
match unsafe {
libarchive::archive_read_data_block(self.archive, &mut buf, &mut size, &mut offset)
} {
libarchive::ARCHIVE_EOF => {
debug!("archive_read_data_block: reaches eof");
self.ended = true;
Ok(&[])
}
result => match analyze_result(result, self.archive) {
Ok(()) => {
if buf.is_null() {
Ok(&[])
} else {
let content = unsafe { slice::from_raw_parts(buf as *const u8, size) };
Ok(content)
}
}
Err(error) => {
error!("archive_read_data_block error: {error:?}");
self.ended = true;
Err(error)
}
},
}
}
}
impl Iterator for BlockReaderBorrowed {
type Item = Result<Box<[u8]>>;
fn next(&mut self) -> Option<Result<Box<[u8]>>> {
match self.read_block() {
Ok(&[]) => None,
block => Some(block.map(Box::from)),
}
}
}
impl LendingIterator for BlockReaderBorrowed {
type Item<'me> = Result<&'me [u8]>;
fn next(&mut self) -> Option<Self::Item<'_>> {
match self.read_block() {
Ok(&[]) => None,
block => Some(block),
}
}
}