1use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
2use crc::crc32;
3
4use std::io;
5use std::io::{Cursor, Read, Write};
6use std::mem;
7
8#[repr(u8)]
9#[derive(Clone, Copy, Debug, PartialEq)]
10pub enum RecordType {
11 Zero = 1,
12 Full = 2,
13
14 First = 3,
15 Middle = 4,
16 Last = 5,
17}
18
19impl RecordType {
20 pub fn from_u8(i: u8) -> Option<RecordType> {
21 if i >= RecordType::Zero as u8 && i <= RecordType::Last as u8 {
22 return Some(unsafe { mem::transmute(i) });
23 }
24 None
25 }
26}
27
28pub const BLOCK_SIZE: i64 = 32768;
30pub const HEADER_SIZE: usize = 7;
32
33#[derive(Clone, Debug, PartialEq)]
54pub struct Record {
55 pub crc: u32,
56 pub size: u16,
57 pub record_type: RecordType,
58 pub payload: Vec<u8>,
59}
60
61impl Record {
62 pub fn new(record_type: RecordType, payload: Vec<u8>) -> Record {
63 let crc = crc32::checksum_ieee(&payload[..]);
64 Record {
65 crc: crc,
66 size: payload.len() as u16,
67 record_type: record_type,
68 payload: payload,
69 }
70 }
71
72 pub fn read<R: Read>(reader: &mut R) -> io::Result<Record> {
73 let mut buf = [0; HEADER_SIZE];
74 reader.read_exact(&mut buf)?;
75
76 let record_type = match RecordType::from_u8(buf[0]) {
77 Some(rt) => rt,
78 None => return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid record type")),
79 };
80
81 let mut rdr = Cursor::new(buf[1..5].to_vec());
82 let crc = rdr.read_u32::<BigEndian>()?;
83
84 rdr = Cursor::new(buf[5..7].to_vec());
85 let size = rdr.read_u16::<BigEndian>()?;
86
87 let mut payload = vec![0; size as usize];
88 reader.read_exact(&mut payload)?;
89
90 let payload_crc = crc32::checksum_ieee(&payload[..]);
91 if payload_crc != crc {
92 return Err(io::Error::new(io::ErrorKind::InvalidData,
93 "CRC checksum failed, possibly corrupted record data"));
94 }
95
96 Ok(Record {
97 crc: crc,
98 size: size,
99 record_type: record_type,
100 payload: payload,
101 })
102 }
103
104 pub fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
105 let record_type = self.record_type as u8;
106
107 let mut wtr = Vec::new();
108 wtr.write_u32::<BigEndian>(self.crc)?;
109 let (crc1, crc2, crc3, crc4) = (wtr[0], wtr[1], wtr[2], wtr[3]);
110
111 wtr = Vec::new();
112 wtr.write_u16::<BigEndian>(self.size)?;
113 let (size1, size2) = (wtr[0], wtr[1]);
114
115 writer.write(&[record_type, crc1, crc2, crc3, crc4, size1, size2])?;
116 writer.write(&self.payload)?;
117 writer.flush()?;
118
119 Ok(())
120 }
121}