use std::io;
use std::path::Path;
use {
Result,
Packet,
Container,
PacketPile,
};
use parse::{
PacketParserBuilder,
PacketParserResult,
PacketParser,
Parse,
Cookie
};
use buffered_reader::BufferedReader;
#[cfg(test)]
#[allow(unused_macros)]
macro_rules! bytes {
( $x:expr ) => { include_bytes!(concat!("../../tests/data/messages/", $x)) };
}
#[cfg(test)]
use std::path::PathBuf;
#[cfg(test)]
fn path_to(artifact: &str) -> PathBuf {
[env!("CARGO_MANIFEST_DIR"), "tests", "data", "messages", artifact]
.iter().collect()
}
#[derive(Debug)]
pub struct PacketPileParser<'a> {
pub 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(data: &'a [u8])
-> Result<PacketPileParser<'a>> {
let bio = Box::new(buffered_reader::Memory::with_cookie(
data, Cookie::default()));
PacketPileParser::from_buffered_reader(bio)
}
}
impl<'a> PacketPileParser<'a> {
fn from_packet_parser(ppr: PacketParserResult<'a>)
-> Result<PacketPileParser<'a>>
{
Ok(PacketPileParser {
pile: PacketPile { top_level: Container::new() },
ppr: ppr,
returned_first: false,
})
}
pub(crate) fn from_buffered_reader(bio: Box<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 = &mut self.pile.top_level;
assert!(position >= 0);
for i in 0..position {
let tmp = container;
let packets_len = tmp.packets.len();
let p = &mut tmp.packets[packets_len - 1];
if p.children.is_none() {
if i == position - 1 {
p.children = Some(Container::new());
} else {
panic!("Internal inconsistency while building message.");
}
}
container = p.children.as_mut().unwrap();
}
container.packets.push(packet);
}
pub fn recurse(&mut self) -> bool {
if self.returned_first {
match self.ppr.take() {
PacketParserResult::Some(pp) => {
match pp.recurse() {
Ok((packet, ppr)) => {
self.insert_packet(
packet,
ppr.last_recursion_depth().unwrap() as isize);
self.ppr = ppr;
}
Err(_) => {
}
}
}
eof @ PacketParserResult::EOF(_) => {
self.ppr = eof;
}
}
} else {
self.returned_first = true;
}
!self.is_done()
}
pub fn next(&mut self) -> bool {
if self.returned_first {
match self.ppr.take() {
PacketParserResult::Some(pp) => {
match pp.next() {
Ok((packet, ppr)) => {
self.insert_packet(
packet,
ppr.last_recursion_depth().unwrap() as isize);
self.ppr = ppr;
}
Err(_) => {
}
}
},
eof @ PacketParserResult::EOF(_) => {
self.ppr = eof
},
}
} else {
self.returned_first = true;
}
!self.is_done()
}
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 message_parser_test() {
let mut count = 0;
let mut mp = PacketPileParser::from_file(path_to("public-key.gpg")).unwrap();
while mp.recurse() {
count += 1;
}
assert_eq!(count, 61);
}
#[cfg(feature = "compression-deflate")]
#[test]
fn message_parser_reader_interface() {
use std::io::Read;
let expected = bytes!("a-cypherpunks-manifesto.txt");
let path = path_to("compressed-data-algo-1.gpg");
let mut mp = PacketPileParser::from_file(path).unwrap();
let mut count = 0;
while mp.recurse() {
let pp = mp.ppr.as_mut().unwrap();
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);
}
}
assert_eq!(count, 2);
}