use std::convert::TryFrom;
use std::io;
use std::ops::{Deref, DerefMut};
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>,
pile: PacketPile,
}
assert_send_and_sync!(PacketPileParser<'_>);
impl<'a> Deref for PacketPileParser<'a> {
type Target = PacketParserResult<'a>;
fn deref(&self) -> &Self::Target {
&self.ppr
}
}
impl<'a> DerefMut for PacketPileParser<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.ppr
}
}
impl<'a> TryFrom<PacketParserBuilder<'a>> for PacketPileParser<'a> {
type Error = anyhow::Error;
fn try_from(ppb: PacketParserBuilder<'a>) -> Result<PacketPileParser<'a>> {
Self::from_packet_parser(ppb.build()?)
}
}
impl<'a> Parse<'a, PacketPileParser<'a>> for PacketPileParser<'a> {
fn from_reader<R: io::Read + 'a + Send + Sync>(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 + Send + Sync>(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,
})
}
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<()> {
match self.ppr.take() {
PacketParserResult::Some(pp) => {
let recursion_depth = pp.recursion_depth();
let (packet, ppr) = pp.recurse()?;
self.insert_packet(
packet,
recursion_depth as isize);
self.ppr = ppr;
}
eof @ PacketParserResult::EOF(_) => {
self.ppr = eof;
}
}
Ok(())
}
pub fn next(&mut self) -> Result<()> {
match self.ppr.take() {
PacketParserResult::Some(pp) => {
let recursion_depth = pp.recursion_depth();
let (packet, ppr) = pp.next()?;
self.insert_packet(
packet,
recursion_depth as isize);
self.ppr = ppr;
},
eof @ PacketParserResult::EOF(_) => {
self.ppr = eof
},
}
Ok(())
}
pub fn recursion_depth(&self) -> Option<isize> {
if let PacketParserResult::Some(ref pp) = self.ppr {
Some(pp.recursion_depth())
} else {
None
}
}
pub fn is_done(&self) -> bool {
self.ppr.is_eof()
}
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"))?;
while ppp.is_some() {
count += 1;
ppp.recurse().unwrap();
}
assert_eq!(count, 61);
let pp = ppp.finish();
assert_eq!(pp.children().count(), 61);
Ok(())
}
#[test]
fn test_next() -> Result<()> {
let mut count = 0;
let mut ppp =
PacketPileParser::from_bytes(crate::tests::key("public-key.gpg"))?;
while ppp.is_some() {
count += 1;
ppp.next().unwrap();
}
assert_eq!(count, 61);
let pp = ppp.finish();
assert_eq!(pp.children().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;
while let Ok(pp) = ppp.as_mut() {
if let Packet::Literal(_) = pp.packet {
assert_eq!(count, 1);
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);
}
ppp.recurse().unwrap();
count += 1;
}
assert_eq!(count, 2);
}