use std::fmt;
use std::slice;
use std::vec;
use std::io;
use std::path::Path;
use buffered_reader::BufferedReader;
use buffered_reader::BufferedReaderGeneric;
use buffered_reader::BufferedReaderMemory;
use buffered_reader::BufferedReaderFile;
use Result;
use Error;
use Packet;
use packet::{Container, PacketIter};
use PacketPile;
use parse::PacketParserResult;
use parse::PacketParserBuilder;
use parse::Cookie;
#[cfg(test)]
macro_rules! bytes {
( $x:expr ) => { include_bytes!(concat!("../tests/data/messages/", $x)) };
}
#[cfg(test)]
use std::path::PathBuf;
#[cfg(test)]
#[allow(dead_code)]
fn path_to(artifact: &str) -> PathBuf {
[env!("CARGO_MANIFEST_DIR"), "tests", "data", "messages", artifact]
.iter().collect()
}
impl fmt::Debug for PacketPile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("PacketPile")
.field("packets", &self.top_level.packets)
.finish()
}
}
impl PacketPile {
pub fn from_packets(p: Vec<Packet>) -> Self {
PacketPile { top_level: Container { packets: p } }
}
pub fn from_packet(p: Packet) -> Self {
let mut top_level = Vec::with_capacity(1);
top_level.push(p);
Self::from_packets(top_level)
}
pub fn pretty_print(&self) {
self.top_level.pretty_print(0);
}
pub fn path_ref(&self, pathspec: &[usize]) -> Option<&Packet> {
let mut packet : Option<&Packet> = None;
let mut cont = Some(&self.top_level);
for i in pathspec {
if let Some(ref c) = cont.take() {
if *i < c.packets.len() {
let p = &c.packets[*i];
packet = Some(p);
cont = p.children.as_ref();
continue;
}
}
return None;
}
return packet;
}
pub fn path_ref_mut(&mut self, pathspec: &[usize]) -> Option<&mut Packet> {
let mut container = &mut self.top_level;
for (level, &i) in pathspec.iter().enumerate() {
let tmp = container;
if i >= tmp.packets.len() {
return None;
}
let p = &mut tmp.packets[i];
if level == pathspec.len() - 1 {
return Some(p)
}
container = p.children.as_mut().unwrap();
}
None
}
pub fn replace(&mut self, pathspec: &[usize], count: usize,
mut packets: Vec<Packet>)
-> Result<Vec<Packet>>
{
let mut container = &mut self.top_level;
for (level, &i) in pathspec.iter().enumerate() {
let tmp = container;
if level == pathspec.len() - 1 {
if i + count > tmp.packets.len() {
return Err(Error::IndexOutOfRange.into());
}
let old = tmp.packets
.drain(i..i + count)
.collect::<Vec<Packet>>();
assert_eq!(old.len(), count);
let mut tail = tmp.packets
.drain(i..)
.collect::<Vec<Packet>>();
tmp.packets.append(&mut packets);
tmp.packets.append(&mut tail);
return Ok(old)
}
if i >= tmp.packets.len() {
return Err(Error::IndexOutOfRange.into());
}
let p = &mut tmp.packets[i];
if p.children.is_none() {
match p {
Packet::CompressedData(_) | Packet::SEIP(_) => {
p.children = Some(Container::new());
},
_ => {
return Err(Error::IndexOutOfRange.into());
}
}
}
container = p.children.as_mut().unwrap();
}
return Err(Error::IndexOutOfRange.into());
}
pub fn descendants(&self) -> PacketIter {
self.top_level.descendants()
}
pub fn children<'a>(&'a self) -> slice::Iter<'a, Packet> {
self.top_level.children()
}
pub fn into_children(self) -> vec::IntoIter<Packet> {
self.top_level.into_children()
}
pub(crate) fn from_buffered_reader<'a>(bio: Box<'a + BufferedReader<Cookie>>)
-> Result<PacketPile> {
PacketParserBuilder::from_buffered_reader(bio)?
.buffer_unread_content()
.to_packet_pile()
}
pub fn from_reader<'a, R: 'a + io::Read>(reader: R) -> Result<PacketPile> {
let bio = BufferedReaderGeneric::with_cookie(
reader, None, Cookie::default());
PacketPile::from_buffered_reader(Box::new(bio))
}
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<PacketPile> {
PacketPile::from_buffered_reader(
Box::new(BufferedReaderFile::with_cookie(path, Cookie::default())?))
}
pub fn from_bytes(data: &[u8]) -> Result<PacketPile> {
let bio = BufferedReaderMemory::with_cookie(
data, Cookie::default());
PacketPile::from_buffered_reader(Box::new(bio))
}
pub fn from_packet_parser<'a>(ppr: PacketParserResult<'a>)
-> Result<PacketPile>
{
if let PacketParserResult::Some(ref pp) = ppr {
assert_eq!(pp.recursion_depth(), 0);
}
let mut top_level = Container::new();
let mut last_position = 0;
if ppr.is_none() {
return Ok(PacketPile::from_packets(Vec::new()));
}
let mut pp = ppr.unwrap();
'outer: loop {
let (mut packet, mut ppr) = pp.recurse()?;
let mut position = ppr.last_recursion_depth().unwrap() as isize;
let mut relative_position : isize = position - last_position;
assert!(relative_position <= 1);
let mut container = &mut top_level;
for _ in 0..(position - if relative_position > 0 { 1 } else { 0 }) {
let tmp = container;
let packets_len = tmp.packets.len();
let p = &mut tmp.packets[packets_len - 1];
container = p.children.as_mut().unwrap();
}
if relative_position < 0 {
relative_position = 0;
}
loop {
if relative_position == 1 {
let tmp = container;
let i = tmp.packets.len() - 1;
assert!(tmp.packets[i].children.is_none());
tmp.packets[i].children = Some(Container::new());
container = tmp.packets[i].children.as_mut().unwrap();
}
container.packets.push(packet);
if ppr.is_none() {
break 'outer;
}
pp = ppr.unwrap();
last_position = position;
position = pp.recursion_depth() as isize;
relative_position = position - last_position;
if position < last_position {
break;
}
let (packet_, ppr_) = pp.recurse()?;
packet = packet_;
ppr = ppr_;
assert_eq!(position,
ppr.last_recursion_depth().unwrap() as isize);
}
}
return Ok(PacketPile { top_level: top_level });
}
}
impl<'a> PacketParserBuilder<'a> {
pub fn to_packet_pile(self) -> Result<PacketPile> {
PacketPile::from_packet_parser(self.finalize()?)
}
}
#[cfg(test)]
mod message_test {
use super::*;
use constants::CompressionAlgorithm;
use constants::DataFormat::Text;
use packet::Literal;
use packet::CompressedData;
use packet::SEIP;
use packet::Tag;
use parse::PacketParser;
#[test]
fn deserialize_test_1 () {
let pile = PacketPile::from_bytes(bytes!("public-key.gpg")).unwrap();
eprintln!("PacketPile has {} top-level packets.",
pile.children().len());
eprintln!("PacketPile: {:?}", pile);
let mut count = 0;
for (i, p) in pile.descendants().enumerate() {
eprintln!("{}: {:?}", i, p);
count += 1;
}
assert_eq!(count, 61);
}
#[cfg(feature = "compression-deflate")]
#[test]
fn deserialize_test_2 () {
let path = path_to("compressed-data-algo-1.gpg");
let pile = PacketPile::from_file(&path).unwrap();
eprintln!("PacketPile has {} top-level packets.",
pile.children().len());
eprintln!("PacketPile: {:?}", pile);
let mut count = 0;
for (i, p) in pile.descendants().enumerate() {
eprintln!("{}: {:?}", i, p);
count += 1;
}
assert_eq!(count, 2);
}
#[cfg(feature = "compression-deflate")]
#[test]
fn deserialize_test_3 () {
let path = path_to("signed.gpg");
let pile = PacketPile::from_file(&path).unwrap();
eprintln!("PacketPile has {} top-level packets.",
pile.children().len());
eprintln!("PacketPile: {:?}", pile);
let mut count = 0;
for (i, p) in pile.descendants().enumerate() {
count += 1;
eprintln!("{}: {:?}", i, p);
}
assert_eq!(count, 6);
}
#[test]
fn torture() {
let data = bytes!("../keys/dkg.gpg");
let mut ppp = PacketParserBuilder::from_bytes(data).unwrap()
.buffer_unread_content()
.to_packet_pile_parser().unwrap();
while ppp.recurse() {
}
let pile = ppp.finish();
assert_eq!(pile.children().len(), 1450);
let data = bytes!("../keys/lutz.gpg");
let mut ppp = PacketParserBuilder::from_bytes(data).unwrap()
.buffer_unread_content()
.to_packet_pile_parser().unwrap();
while ppp.recurse() {
if let PacketParserResult::Some(ref pp) = ppp.ppr {
eprintln!("{:?}", pp);
} else {
unreachable!();
}
}
let pile = ppp.finish();
pile.pretty_print();
assert_eq!(pile.children().len(), 77);
}
#[cfg(feature = "compression-deflate")]
#[test]
fn compression_quine_test_1 () {
let path = path_to("compression-quine.gpg");
let max_recursion_depth = 128;
let pile = PacketParserBuilder::from_file(path).unwrap()
.max_recursion_depth(max_recursion_depth)
.to_packet_pile().unwrap();
let mut count = 0;
for (i, p) in pile.descendants().enumerate() {
count += 1;
if false {
eprintln!("{}: p: {:?}", i, p);
}
}
assert_eq!(count, 1 + max_recursion_depth);
}
#[cfg(feature = "compression-deflate")]
#[test]
fn compression_quine_test_2 () {
let path = path_to("compression-quine.gpg");
let max_recursion_depth = 255;
let mut ppr : PacketParserResult
= PacketParserBuilder::from_file(path).unwrap()
.max_recursion_depth(max_recursion_depth)
.finalize().unwrap();
let mut count = 0;
loop {
if let PacketParserResult::Some(pp2) = ppr {
count += 1;
let pp2 = pp2.recurse().unwrap().1;
let packet_depth = pp2.last_recursion_depth().unwrap();
assert_eq!(packet_depth, count - 1);
if pp2.is_some() {
assert_eq!(pp2.recursion_depth(), Some(count));
}
ppr = pp2;
} else {
break;
}
}
assert_eq!(count, 1 + max_recursion_depth as isize);
}
#[cfg(feature = "compression-deflate")]
#[test]
fn consume_content_1 () {
use std::io::Read;
let ppr = PacketParserBuilder::from_file(
path_to("compressed-data-algo-1.gpg")).unwrap()
.buffer_unread_content()
.finalize().unwrap();
let mut pp = ppr.unwrap();
if let Packet::CompressedData(_) = pp.packet {
} else {
panic!("Expected a compressed packet!");
}
let mut data = [0u8; 1];
let amount = pp.read(&mut data).unwrap();
assert_eq!(amount, 1);
let (mut packet, ppr) = pp.next().unwrap();
assert!(ppr.is_none());
let mut content = packet.body.take().unwrap();
content.insert(0, data[0]);
let content = &content.into_boxed_slice()[..];
let ppr = PacketParser::from_bytes(content).unwrap();
let pp = ppr.unwrap();
if let Packet::Literal(_) = pp.packet {
} else {
panic!("Expected a literal packet!");
}
let ppr = pp.next().unwrap().1;
assert!(ppr.is_none());
}
#[test]
fn path_ref() {
let mut packets : Vec<Packet> = Vec::new();
let text = [ &b"one"[..], &b"two"[..],
&b"three"[..], &b"four"[..] ].to_vec();
let mut cd = CompressedData::new(CompressionAlgorithm::Uncompressed);
for t in text.iter() {
let mut lit = Literal::new(Text);
lit.set_body(t.to_vec());
cd = cd.push(lit.to_packet())
}
let mut seip = SEIP {
common: Default::default(),
version: 0
};
seip.common.children = Some(Container::new());
seip.common.children.as_mut().unwrap().push(cd.to_packet());
packets.push(Packet::SEIP(seip));
eprintln!("{:#?}", packets);
let mut pile = PacketPile::from_packets(packets);
assert_eq!(pile.path_ref(&[ 0 ]).unwrap().tag(), Tag::SEIP);
assert_eq!(pile.path_ref_mut(&[ 0 ]).unwrap().tag(), Tag::SEIP);
assert_eq!(pile.path_ref(&[ 0, 0 ]).unwrap().tag(),
Tag::CompressedData);
assert_eq!(pile.path_ref_mut(&[ 0, 0 ]).unwrap().tag(),
Tag::CompressedData);
for (i, t) in text.iter().enumerate() {
assert_eq!(pile.path_ref(&[ 0, 0, i ]).unwrap().tag(),
Tag::Literal);
assert_eq!(pile.path_ref_mut(&[ 0, 0, i ]).unwrap().tag(),
Tag::Literal);
assert_eq!(pile.path_ref(&[ 0, 0, i ]).unwrap().body,
Some(t.to_vec()));
assert_eq!(pile.path_ref_mut(&[ 0, 0, i ]).unwrap().body,
Some(t.to_vec()));
}
assert!(pile.path_ref(&[ 0, 0, 4 ]).is_none());
assert!(pile.path_ref_mut(&[ 0, 0, 4 ]).is_none());
assert!(pile.path_ref(&[ 0, 0, 5 ]).is_none());
assert!(pile.path_ref_mut(&[ 0, 0, 5 ]).is_none());
assert!(pile.path_ref(&[ 0, 1 ]).is_none());
assert!(pile.path_ref_mut(&[ 0, 1 ]).is_none());
assert!(pile.path_ref(&[ 0, 2 ]).is_none());
assert!(pile.path_ref_mut(&[ 0, 2 ]).is_none());
assert!(pile.path_ref(&[ 1 ]).is_none());
assert!(pile.path_ref_mut(&[ 1 ]).is_none());
assert!(pile.path_ref(&[ 2 ]).is_none());
assert!(pile.path_ref_mut(&[ 2 ]).is_none());
assert!(pile.path_ref(&[ 0, 1, 0 ]).is_none());
assert!(pile.path_ref_mut(&[ 0, 1, 0 ]).is_none());
assert!(pile.path_ref(&[ 0, 2, 0 ]).is_none());
assert!(pile.path_ref_mut(&[ 0, 2, 0 ]).is_none());
}
#[test]
fn replace() {
let mut one = Literal::new(Text);
one.set_body(b"one".to_vec());
let mut two = Literal::new(Text);
two.set_body(b"two".to_vec());
let mut packets : Vec<Packet> = Vec::new();
packets.push(one.to_packet());
assert!(packets.iter().map(|p| p.tag()).collect::<Vec<Tag>>()
== [ Tag::Literal ]);
let mut pile = PacketPile::from_packets(packets.clone());
pile.replace(
&[ 0 ], 1,
[ two.to_packet()
].to_vec()).unwrap();
let children = pile.into_children().collect::<Vec<Packet>>();
assert_eq!(children.len(), 1, "{:#?}", children);
if let Packet::Literal(ref literal) = children[0] {
assert_eq!(literal.common.body, Some(b"two".to_vec()),
"{:#?}", literal);
} else {
panic!("WTF");
}
let initial
= [ &b"one"[..], &b"two"[..], &b"three"[..], &b"four"[..] ].to_vec();
let inserted
= [ &b"a"[..], &b"b"[..], &b"c"[..] ].to_vec();
let mut packets : Vec<Packet> = Vec::new();
for text in initial.iter() {
let mut lit = Literal::new(Text);
lit.set_body(text.to_vec());
packets.push(lit.to_packet())
}
for start in 0..initial.len() + 1 {
for delete in 0..initial.len() - start + 1 {
for insert in 0..inserted.len() + 1 {
let mut pile = PacketPile::from_packets(packets.clone());
let mut replacement : Vec<Packet> = Vec::new();
for &text in inserted[0..insert].iter() {
let mut lit = Literal::new(Text);
lit.set_body(text.to_vec());
replacement.push(lit.to_packet());
}
pile.replace(&[ start ], delete, replacement).unwrap();
let values = pile
.children()
.map(|p| {
if let Packet::Literal(ref literal) = p {
&literal.common.body.as_ref().unwrap()[..]
} else {
panic!("Expected a literal packet, got: {:?}", p);
}
})
.collect::<Vec<&[u8]>>();
assert_eq!(values.len(), initial.len() - delete + insert);
assert_eq!(values[..start],
initial[..start]);
assert_eq!(values[start..start + insert],
inserted[..insert]);
assert_eq!(values[start + insert..],
initial[start + delete..]);
}
}
}
let initial
= [ &b"one"[..], &b"two"[..], &b"three"[..], &b"four"[..] ].to_vec();
let inserted
= [ &b"a"[..], &b"b"[..], &b"c"[..] ].to_vec();
let mut cd = CompressedData::new(CompressionAlgorithm::Uncompressed);
for l in initial.iter() {
let mut lit = Literal::new(Text);
lit.set_body(l.to_vec());
cd = cd.push(lit.to_packet());
}
for start in 0..initial.len() + 1 {
for delete in 0..initial.len() - start + 1 {
for insert in 0..inserted.len() + 1 {
let mut pile = PacketPile::from_packets(
vec![ cd.clone().to_packet() ]);
let mut replacement : Vec<Packet> = Vec::new();
for &text in inserted[0..insert].iter() {
let mut lit = Literal::new(Text);
lit.set_body(text.to_vec());
replacement.push(lit.to_packet());
}
pile.replace(&[ 0, start ], delete, replacement).unwrap();
let top_level = pile.children().collect::<Vec<&Packet>>();
assert_eq!(top_level.len(), 1);
let values = top_level[0]
.children.as_ref().unwrap().children()
.map(|p| {
if let Packet::Literal(ref literal) = p {
&literal.common.body.as_ref().unwrap()[..]
} else {
panic!("Expected a literal packet, got: {:?}", p);
}
})
.collect::<Vec<&[u8]>>();
assert_eq!(values.len(), initial.len() - delete + insert);
assert_eq!(values[..start],
initial[..start]);
assert_eq!(values[start..start + insert],
inserted[..insert]);
assert_eq!(values[start + insert..],
initial[start + delete..]);
}
}
}
let mut one = Literal::new(Text);
one.set_body(b"one".to_vec());
let mut packets : Vec<Packet> = Vec::new();
packets.push(one.to_packet());
let mut pile = PacketPile::from_packets(packets.clone());
assert!(pile.replace(&[ 1 ], 0, Vec::new()).is_ok());
assert!(pile.replace(&[ 2 ], 0, Vec::new()).is_err());
assert!(pile.replace(&[ 0 ], 2, Vec::new()).is_err());
assert!(pile.replace(&[ 0, 0 ], 0, Vec::new()).is_err());
assert!(pile.replace(&[ 0, 1 ], 0, Vec::new()).is_err());
let mut packets : Vec<Packet> = Vec::new();
packets.push(CompressedData::new(CompressionAlgorithm::Uncompressed)
.to_packet());
let mut pile = PacketPile::from_packets(packets.clone());
assert!(pile.replace(&[ 1 ], 0, Vec::new()).is_ok());
assert!(pile.replace(&[ 2 ], 0, Vec::new()).is_err());
assert!(pile.replace(&[ 0 ], 2, Vec::new()).is_err());
assert!(pile.replace(&[ 0, 0 ], 0, Vec::new()).is_ok());
assert!(pile.replace(&[ 0, 1 ], 0, Vec::new()).is_err());
}
}