diff --git a/src/ber/value.rs b/src/ber/value.rs index 89abbf5..cf5d85b 100644 --- a/src/ber/value.rs +++ b/src/ber/value.rs @@ -2,18 +2,21 @@ use crate::ber::length::{Length, LengthReaderError, LengthWriterError}; use crate::ber::tag::{Tag, TagClass, TagForm, TagReaderError, TagSerializationError, BasicTagType}; use crate::lift_error; use crate::number::Number; +use crate::real::Real; use crate::util::BufferReader; pub enum Value { Boolean(TagClass, TagForm, bool), Integer(TagClass, TagForm, Number), Null(TagClass, TagForm), + Real(TagClass, TagForm, Real), } pub enum ValueReaderError { LengthIncompatible, LengthTooBig, NotEnoughData, + InvalidFormat(BasicTagType), TagReaderProblem(TagReaderError), LengthReaderError(LengthReaderError), } @@ -34,7 +37,7 @@ impl Value { pub fn read>(it: &mut I) -> Result { let tag = Tag::read(it)?; let length = Length::read(&tag, it)?; - let bytes: Vec = match length.read_buffer(it) { + let mut bytes: Vec = match length.read_buffer(it) { None => return Err(ValueReaderError::NotEnoughData), Some(x) => x, }; @@ -56,6 +59,73 @@ impl Value { Ok(Value::Integer(c, f, res)) } + Tag::Simple(c, f, BasicTagType::Real) => { + if bytes.len() == 0 { + return Err(ValueReaderError::InvalidFormat(BasicTagType::Real)); + } + + let leader = bytes.remove(0); // has the handy side-effect of making bytes by the + // actual value. + + if leader == 0b01000000 { + return Ok(Value::Real(c, f, Real::PositiveInfinity)); + } + + if leader == 0b01000001 { + return Ok(Value::Real(c, f, Real::NegativeInfinity)); + } + + if leader >> 6 == 0b00 { + match String::from_utf8(bytes) { + Err(_) => return Err(ValueReaderError::InvalidFormat(BasicTagType::Real)), + Ok(v) => { + let has_e = v.chars().any(|c| (c == 'e') || (c == 'E')); + let has_p = v.chars().any(|c| (c == '.')); + let nr = leader & 0b00111111; + + match nr { + 0b01 if !has_e && !has_p => return Ok(Value::Real(c, f, Real::ISO6093(v))), + 0b10 if !has_e && has_p => return Ok(Value::Real(c, f, Real::ISO6093(v))), + 0b11 if has_e && has_p => return Ok(Value::Real(c, f, Real::ISO6093(v))), + _ => return Err(ValueReaderError::InvalidFormat(BasicTagType::Real)), + } + } + } + } + + if (leader >> 7) == 0 { + return Err(ValueReaderError::InvalidFormat(BasicTagType::Real)); + } + + let positive = (leader >> 6) & 1 == 0; + let mant_shift = ((leader >> 2) & 0b11) as usize; + let exp_shift = match (leader >> 4) & 0b11 { + 0b00 => 0, + 0b01 => 2, + 0b10 => 3, + _ => return Err(ValueReaderError::InvalidFormat(BasicTagType::Real)), + } as usize; + let explen = match leader & 0b11 { + 0 => 1, + 1 => 2, + 2 => 3, + 3 => bytes.remove(0), + _ => panic!("Mathematics has failed us.") + } as usize; + + let mut exponent = Number::from_bytes(&bytes[0..explen]); + let mut mantissa = Number::from_bytes(&bytes[explen..]); + + exponent <<= exp_shift; + mantissa <<= mant_shift; + + if !positive { + mantissa = -mantissa; + } + + Ok(Value::Real(c, f, Real::new(exponent, mantissa))) + } + _ => unimplemented!("Cannot parse tag {:?}", tag) } @@ -89,6 +159,10 @@ impl Value { Tag::Simple(*c, *f, BasicTagType::Null).write(buffer)?; Ok(()) } + + Value::Real(c, f, r) => { + unimplemented!() + } } } } diff --git a/src/lib.rs b/src/lib.rs index 355971e..29b2de5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,7 @@ extern crate alloc; mod ber; mod bitstring; mod number; +mod real; mod util; use chrono::{DateTime, TimeZone, Utc}; diff --git a/src/number.rs b/src/number.rs index 6f72b39..d2b2122 100644 --- a/src/number.rs +++ b/src/number.rs @@ -1,4 +1,5 @@ use core::convert::TryFrom; +use core::ops::{Neg, ShlAssign}; use crate::ber::length::ConversionError; #[cfg(test)] use quickcheck::{quickcheck, Arbitrary, Gen}; @@ -184,3 +185,17 @@ impl<'a> TryFrom<&'a Number> for usize { } } } + +impl ShlAssign for Number { + fn shl_assign(&mut self, amt: usize) { + unimplemented!() + } +} + +impl Neg for Number { + type Output = Number; + + fn neg(self) -> Number { + unimplemented!() + } +} \ No newline at end of file diff --git a/src/real.rs b/src/real.rs new file mode 100644 index 0000000..5b37695 --- /dev/null +++ b/src/real.rs @@ -0,0 +1,23 @@ +use crate::number::Number; + +pub enum Real { + PositiveInfinity, + NegativeInfinity, + ISO6093(String), + Binary(RealNumber), +} + +impl Real { + pub fn new(exponent: Number, mantissa: Number) -> Real { + Real::Binary(RealNumber{ + exponent, + mantissa, + }) + } +} + +pub struct RealNumber { + exponent: Number, + mantissa: Number, +} +