use std::io;
use std::path::Path;
use crate::{
Result,
Packet,
PacketPile,
};
use crate::parse::{
PacketParserBuilder,
PacketParserResult,
PacketParser,
Parse,
Cookie
};
use buffered_reader::BufferedReader;
#[derive(Debug)]
pub struct PacketPileParser<'a> {
ppr: PacketParserResult<'a>,
returned_first: bool,
pile: PacketPile,
}
impl<'a> PacketParserBuilder<'a> {
pub fn into_packet_pile_parser(self) -> Result<PacketPileParser<'a>>
where Self: 'a {
PacketPileParser::from_packet_parser(self.finalize()?)
}
}
impl<'a> Parse<'a, PacketPileParser<'a>> for PacketPileParser<'a> {
fn from_reader<R: io::Read + 'a>(reader: R)
-> Result<PacketPileParser<'a>> {
let bio = Box::new(buffered_reader::Generic::with_cookie(
reader, None, Cookie::default()));
PacketPileParser::from_buffered_reader(bio)
}
fn from_file<P: AsRef<Path>>(path: P)
-> Result<PacketPileParser<'a>> {
PacketPileParser::from_buffered_reader(
Box::new(buffered_reader::File::with_cookie(path, Cookie::default())?))
}
fn from_bytes<D: AsRef<[u8]> + ?Sized>(data: &'a D)
-> Result<PacketPileParser<'a>> {
let bio = Box::new(buffered_reader::Memory::with_cookie(
data.as_ref(), Cookie::default()));
PacketPileParser::from_buffered_reader(bio)
}
}
impl<'a> PacketPileParser<'a> {
fn from_packet_parser(ppr: PacketParserResult<'a>)
-> Result<PacketPileParser<'a>>
{
Ok(PacketPileParser {
pile: Default::default(),
ppr: ppr,
returned_first: false,
})
}
pub(crate) fn from_buffered_reader(bio: Box<dyn BufferedReader<Cookie> + 'a>)
-> Result<PacketPileParser<'a>> {
Self::from_packet_parser(PacketParser::from_buffered_reader(bio)?)
}
fn insert_packet(&mut self, packet: Packet, position: isize) {
let mut container = self.pile.top_level_mut();
assert!(position >= 0);
for i in 0..position {
let tmp = container;
let packets_len = tmp.children_ref().expect("is a container").len();
let p = &mut tmp.children_mut()
.expect("is a container")
[packets_len - 1];
if p.children().expect("is a container").next().is_none() {
assert!(i == position - 1,
"Internal inconsistency while building message.");
}
container = p.container_mut().unwrap();
}
container.children_mut().unwrap().push(packet);
}
pub fn recurse(&mut self) -> Result<&mut PacketParserResult<'a>> {
if self.returned_first {
match self.ppr.take() {
PacketParserResult::Some(pp) => {
let (packet, ppr) = pp.recurse()?;
self.insert_packet(
packet,
ppr.last_recursion_depth().unwrap() as isize);
self.ppr = ppr;
}
eof @ PacketParserResult::EOF(_) => {
self.ppr = eof;
}
}
} else {
self.returned_first = true;
}
Ok(&mut self.ppr)
}
pub fn next(&mut self) -> Result<&mut PacketParserResult<'a>> {
if self.returned_first {
match self.ppr.take() {
PacketParserResult::Some(pp) => {
let (packet, ppr) = pp.next()?;
self.insert_packet(
packet,
ppr.last_recursion_depth().unwrap() as isize);
self.ppr = ppr;
},
eof @ PacketParserResult::EOF(_) => {
self.ppr = eof
},
}
} else {
self.returned_first = true;
}
Ok(&mut self.ppr)
}
pub fn recursion_depth(&self) -> Option<u8> {
if let PacketParserResult::Some(ref pp) = self.ppr {
Some(pp.recursion_depth() as u8)
} else {
None
}
}
pub fn is_done(&self) -> bool {
self.ppr.is_none()
}
pub fn finish(self) -> PacketPile {
return self.pile;
}
}
#[test]
fn test_recurse() -> Result<()> {
let mut count = 0;
let mut ppp =
PacketPileParser::from_bytes(crate::tests::key("public-key.gpg"))?;
let mut ppr = ppp.recurse().unwrap();
while ppr.is_some() {
count += 1;
ppr = ppp.recurse().unwrap();
}
assert_eq!(count, 61);
Ok(())
}
#[test]
fn test_next() -> Result<()> {
let mut count = 0;
let mut ppp =
PacketPileParser::from_bytes(crate::tests::key("public-key.gpg"))?;
let mut ppr = ppp.recurse().unwrap();
while ppr.is_some() {
count += 1;
ppr = ppp.next().unwrap();
}
assert_eq!(count, 61);
Ok(())
}
#[cfg(feature = "compression-deflate")]
#[test]
fn message_parser_reader_interface() {
use std::io::Read;
let expected = crate::tests::manifesto();
let mut ppp = PacketPileParser::from_bytes(
crate::tests::message("compressed-data-algo-1.gpg")).unwrap();
let mut count = 0;
let mut ppr = ppp.recurse().unwrap();
while let Some(pp) = ppr.as_mut() {
count += 1;
if let Packet::Literal(_) = pp.packet {
assert_eq!(count, 2);
for i in 0..expected.len() {
let mut buf = [0u8; 1];
let r = pp.read(&mut buf).unwrap();
assert_eq!(r, 1);
assert_eq!(buf[0], expected[i]);
}
let mut buf = [0u8; 1];
let r = pp.read(&mut buf).unwrap();
assert_eq!(r, 0);
}
ppr = ppp.recurse().unwrap();
}
assert_eq!(count, 2);
}