use std::io::Read;
use byteorder::{ReadBytesExt, BigEndian};
use {Error, Result};
const INFORMATION_ELEMENT_HEADER_LENGTH: u16 = 3;
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
pub enum InformationElementType {
MobileOriginatedHeader = 0x01,
MobileOriginatedPayload = 0x02,
MobileOriginatedLocationInformation = 0x03,
MobileTerminatedHeader = 0x41,
MobileTerminatedPayload = 0x42,
MobileTerminatedConfirmationMessage = 0x44,
Unknown,
}
impl From<u8> for InformationElementType {
fn from(n: u8) -> Self {
match n {
0x01 => InformationElementType::MobileOriginatedHeader,
0x02 => InformationElementType::MobileOriginatedPayload,
0x03 => InformationElementType::MobileOriginatedLocationInformation,
0x41 => InformationElementType::MobileTerminatedHeader,
0x42 => InformationElementType::MobileTerminatedPayload,
0x44 => InformationElementType::MobileTerminatedConfirmationMessage,
_ => InformationElementType::Unknown,
}
}
}
impl Default for InformationElementType {
fn default() -> InformationElementType {
InformationElementType::Unknown
}
}
#[derive(Debug, Default)]
pub struct InformationElement {
id: InformationElementType,
length: u16,
contents: Vec<u8>,
}
impl InformationElement {
pub fn read_from<R: Read>(mut readable: R) -> Result<InformationElement> {
let mut information_element: InformationElement = Default::default();
information_element.id = InformationElementType::from(try!(readable.read_u8()));
information_element.length = try!(readable.read_u16::<BigEndian>());
let bytes_read = try!(readable.take(information_element.length as u64)
.read_to_end(&mut information_element.contents));
assert!(!(bytes_read > information_element.length as usize));
if bytes_read < information_element.length as usize {
return Err(Error::Undersized(bytes_read + 3));
}
Ok(information_element)
}
pub fn len(&self) -> u16 {
self.length + INFORMATION_ELEMENT_HEADER_LENGTH
}
pub fn id(&self) -> InformationElementType {
self.id
}
pub fn contents_ref(&self) -> &[u8] {
&self.contents[..]
}
pub fn into_contents(self) -> Vec<u8> {
self.contents
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::{Read, Seek, SeekFrom};
use std::fs::File;
#[test]
fn read_from() {
let mut file = File::open("data/0-mo.sbd").unwrap();
file.seek(SeekFrom::Start(3)).unwrap();
let readable = file.take(31);
InformationElement::read_from(readable).unwrap();
}
#[test]
fn len() {
let mut file = File::open("data/0-mo.sbd").unwrap();
file.seek(SeekFrom::Start(3)).unwrap();
let readable = file.take(31);
let ie = InformationElement::read_from(readable).unwrap();
assert_eq!(31, ie.len());
}
#[test]
fn undersized() {
let mut file = File::open("data/0-mo.sbd").unwrap();
file.seek(SeekFrom::Start(3)).unwrap();
let readable = file.take(30);
assert!(InformationElement::read_from(readable).is_err());
}
}