Start working on support for Real numbers.
This commit is contained in:
@@ -2,18 +2,21 @@ use crate::ber::length::{Length, LengthReaderError, LengthWriterError};
|
|||||||
use crate::ber::tag::{Tag, TagClass, TagForm, TagReaderError, TagSerializationError, BasicTagType};
|
use crate::ber::tag::{Tag, TagClass, TagForm, TagReaderError, TagSerializationError, BasicTagType};
|
||||||
use crate::lift_error;
|
use crate::lift_error;
|
||||||
use crate::number::Number;
|
use crate::number::Number;
|
||||||
|
use crate::real::Real;
|
||||||
use crate::util::BufferReader;
|
use crate::util::BufferReader;
|
||||||
|
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Boolean(TagClass, TagForm, bool),
|
Boolean(TagClass, TagForm, bool),
|
||||||
Integer(TagClass, TagForm, Number),
|
Integer(TagClass, TagForm, Number),
|
||||||
Null(TagClass, TagForm),
|
Null(TagClass, TagForm),
|
||||||
|
Real(TagClass, TagForm, Real),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ValueReaderError {
|
pub enum ValueReaderError {
|
||||||
LengthIncompatible,
|
LengthIncompatible,
|
||||||
LengthTooBig,
|
LengthTooBig,
|
||||||
NotEnoughData,
|
NotEnoughData,
|
||||||
|
InvalidFormat(BasicTagType),
|
||||||
TagReaderProblem(TagReaderError),
|
TagReaderProblem(TagReaderError),
|
||||||
LengthReaderError(LengthReaderError),
|
LengthReaderError(LengthReaderError),
|
||||||
}
|
}
|
||||||
@@ -34,7 +37,7 @@ impl Value {
|
|||||||
pub fn read<I: Iterator<Item = u8>>(it: &mut I) -> Result<Value, ValueReaderError> {
|
pub fn read<I: Iterator<Item = u8>>(it: &mut I) -> Result<Value, ValueReaderError> {
|
||||||
let tag = Tag::read(it)?;
|
let tag = Tag::read(it)?;
|
||||||
let length = Length::read(&tag, it)?;
|
let length = Length::read(&tag, it)?;
|
||||||
let bytes: Vec<u8> = match length.read_buffer(it) {
|
let mut bytes: Vec<u8> = match length.read_buffer(it) {
|
||||||
None => return Err(ValueReaderError::NotEnoughData),
|
None => return Err(ValueReaderError::NotEnoughData),
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
};
|
};
|
||||||
@@ -56,6 +59,73 @@ impl Value {
|
|||||||
Ok(Value::Integer(c, f, res))
|
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)
|
unimplemented!("Cannot parse tag {:?}", tag)
|
||||||
}
|
}
|
||||||
@@ -89,6 +159,10 @@ impl Value {
|
|||||||
Tag::Simple(*c, *f, BasicTagType::Null).write(buffer)?;
|
Tag::Simple(*c, *f, BasicTagType::Null).write(buffer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value::Real(c, f, r) => {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ extern crate alloc;
|
|||||||
mod ber;
|
mod ber;
|
||||||
mod bitstring;
|
mod bitstring;
|
||||||
mod number;
|
mod number;
|
||||||
|
mod real;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
use chrono::{DateTime, TimeZone, Utc};
|
use chrono::{DateTime, TimeZone, Utc};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
|
use core::ops::{Neg, ShlAssign};
|
||||||
use crate::ber::length::ConversionError;
|
use crate::ber::length::ConversionError;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use quickcheck::{quickcheck, Arbitrary, Gen};
|
use quickcheck::{quickcheck, Arbitrary, Gen};
|
||||||
@@ -184,3 +185,17 @@ impl<'a> TryFrom<&'a Number> for usize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ShlAssign<usize> for Number {
|
||||||
|
fn shl_assign(&mut self, amt: usize) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for Number {
|
||||||
|
type Output = Number;
|
||||||
|
|
||||||
|
fn neg(self) -> Number {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/real.rs
Normal file
23
src/real.rs
Normal file
@@ -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,
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user