use crate::error::{PageError, Result};
use crate::header::PageHeader;
use crate::paginate::paginate;
use crate::Page;
use std::fmt::{Debug, Formatter};
use std::io::{Read, Seek, Write};
pub struct Packets {
content: Vec<u8>,
packet_sizes: Vec<u64>,
}
impl Packets {
pub fn read<R>(data: &mut R) -> Result<Self>
where
R: Read + Seek,
{
Self::read_count(data, -1)
}
#[allow(clippy::read_zero_byte_vec)]
pub fn read_count<R>(data: &mut R, count: isize) -> Result<Self>
where
R: Read + Seek,
{
let mut content = Vec::new();
let mut packet_sizes = Vec::new();
if count == 0 || count < -1 {
return Ok(Self {
content,
packet_sizes,
});
}
let mut read = 0;
let mut packet_size = 0_u64;
let mut packet_bytes_already_read = None;
let mut current_packet_content;
'outer: loop {
if let Ok(header) = PageHeader::read(data) {
for i in header.segments {
packet_size += u64::from(i);
if i < 255 {
if count != -1 {
read += 1;
}
let byte_count_to_read = Self::get_byte_count_to_read(
packet_size,
&mut packet_bytes_already_read,
);
current_packet_content = vec![0; byte_count_to_read as usize];
data.read_exact(&mut current_packet_content)?;
packet_sizes.push(packet_size);
packet_size = 0;
packet_bytes_already_read = None;
content.append(&mut current_packet_content);
if read == count {
break 'outer;
}
}
}
if packet_size != 0 {
let byte_count_to_read =
Self::get_byte_count_to_read(packet_size, &mut packet_bytes_already_read);
current_packet_content = vec![0; byte_count_to_read as usize];
data.read_exact(&mut current_packet_content)?;
content.append(&mut current_packet_content);
}
continue;
}
break;
}
if count != -1 && packet_sizes.len() != count as usize {
return Err(PageError::NotEnoughData);
}
Ok(Self {
content,
packet_sizes,
})
}
fn get_byte_count_to_read(
packet_size: u64,
packet_bytes_already_read: &mut Option<u64>,
) -> u64 {
let byte_count_to_read;
match packet_bytes_already_read {
Some(already_read_bytes_count) => {
byte_count_to_read = packet_size - *already_read_bytes_count;
*packet_bytes_already_read = Some(*already_read_bytes_count + byte_count_to_read);
},
None => {
byte_count_to_read = packet_size;
*packet_bytes_already_read = Some(packet_size);
},
};
byte_count_to_read
}
pub fn len(&self) -> usize {
self.packet_sizes.len()
}
pub fn is_empty(&self) -> bool {
self.packet_sizes.is_empty()
}
pub fn get(&self, idx: usize) -> Option<&[u8]> {
if idx >= self.content.len() {
return None;
}
let start_pos = match idx {
0 => 0,
other => self.packet_sizes[other - 1] as usize,
};
if let Some(packet_size) = self.packet_sizes.get(idx) {
return Some(&self.content[start_pos..start_pos + *packet_size as usize]);
}
None
}
pub fn set(&mut self, idx: usize, content: impl Into<Vec<u8>>) -> bool {
if idx >= self.packet_sizes.len() {
return false;
}
let start_pos = match idx {
0 => 0,
other => self.packet_sizes[other - 1] as usize,
};
let content = content.into();
let content_size = content.len();
let end_pos = start_pos + self.packet_sizes[idx] as usize;
self.content.splice(start_pos..end_pos, content);
self.packet_sizes[idx] = content_size as u64;
true
}
pub fn iter(&self) -> PacketsIter<'_> {
<&Self as IntoIterator>::into_iter(self)
}
pub fn paginate(&self, stream_serial: u32, abgp: u64, flags: u8) -> Result<Vec<Page>> {
let mut packets = Vec::new();
let mut pos = 0;
for packet_size in self.packet_sizes.iter().copied() {
packets.push(&self.content[pos..pos + packet_size as usize]);
pos += packet_size as usize;
}
paginate(packets, stream_serial, abgp, flags)
}
pub fn write_to<W>(
&self,
writer: &mut W,
stream_serial: u32,
abgp: u64,
flags: u8,
) -> Result<usize>
where
W: Write,
{
let paginated = self.paginate(stream_serial, abgp, flags)?;
let num_pages = paginated.len();
for mut page in paginated {
page.gen_crc();
writer.write_all(&page.as_bytes())?;
}
Ok(num_pages)
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct PacketsIter<'a> {
content: &'a [u8],
packet_sizes: &'a [u64],
cap: usize,
}
impl<'a> Iterator for PacketsIter<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<Self::Item> {
if self.cap == 0 {
return None;
}
let packet_size = self.packet_sizes[0];
self.cap -= 1;
self.packet_sizes = &self.packet_sizes[1..];
let (ret, remaining) = self.content.split_at(packet_size as usize);
self.content = remaining;
Some(ret)
}
}
impl<'a> IntoIterator for &'a Packets {
type Item = &'a [u8];
type IntoIter = PacketsIter<'a>;
fn into_iter(self) -> Self::IntoIter {
PacketsIter {
content: &self.content,
packet_sizes: &self.packet_sizes,
cap: self.packet_sizes.len(),
}
}
}
impl Debug for Packets {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Packets")
.field("total_bytes", &self.content.len())
.field("count", &self.packet_sizes.len())
.finish()
}
}