199 lines
5.1 KiB
Rust
199 lines
5.1 KiB
Rust
|
/*
|
||
|
* Functionality for parsing and writing basic data types
|
||
|
*/
|
||
|
use nom;
|
||
|
use nom::{IResult};
|
||
|
use byteorder::BigEndian;
|
||
|
//use std::io::Write;
|
||
|
use std::io;
|
||
|
|
||
|
|
||
|
pub type OWResult = Result<usize, io::Error>;
|
||
|
|
||
|
/*
|
||
|
* Parse functions
|
||
|
*/
|
||
|
//pub fn parse_byte_as_bits(input: &[u8]) -> IResult<&[u8], (u8, u8, u8, u8, u8, u8, u8, u8)> {
|
||
|
// nom::bits::bits(nom::sequence::tuple((
|
||
|
// nom::bits::complete::take::<_, _, _, CustomError<_>>(1_usize),
|
||
|
// nom::bits::complete::take::<_, _, _, CustomError<_>>(1_usize),
|
||
|
// nom::bits::complete::take::<_, _, _, CustomError<_>>(1_usize),
|
||
|
// nom::bits::complete::take::<_, _, _, CustomError<_>>(1_usize),
|
||
|
// nom::bits::complete::take::<_, _, _, CustomError<_>>(1_usize),
|
||
|
// nom::bits::complete::take::<_, _, _, CustomError<_>>(1_usize),
|
||
|
// nom::bits::complete::take::<_, _, _, CustomError<_>>(1_usize),
|
||
|
// nom::bits::complete::take::<_, _, _, CustomError<_>>(1_usize),
|
||
|
// )))(input)
|
||
|
//}
|
||
|
|
||
|
|
||
|
pub fn parse_int2(input: &[u8]) -> IResult<&[u8], i16> {
|
||
|
nom::number::streaming::be_i16(input)?
|
||
|
}
|
||
|
|
||
|
pub fn parse_int4(input: &[u8]) -> IResult<&[u8], i32> {
|
||
|
nom::number::streaming::be_i32(input)?
|
||
|
}
|
||
|
|
||
|
pub fn decode_real8(int: u64) -> f64 {
|
||
|
// Convert GDS REAL8 to IEEE float64
|
||
|
let neg = int & 0x8000_0000_0000_0000;
|
||
|
let exp = (int >> 56) & 0x7f;
|
||
|
let mut mant = (int & 0x00ff_ffff_ffff_ffff) as f64;
|
||
|
if neg != 0 {
|
||
|
mant *= -1
|
||
|
}
|
||
|
mant * 2_f64.powi(4 * (exp - 64) - 56)
|
||
|
}
|
||
|
|
||
|
pub fn parse_real8(input: &[u8]) -> IResult<&[u8], f64> {
|
||
|
let data = nom::number::streaming::be_u64(input)?;
|
||
|
IResult::Ok(decode_real8(data))
|
||
|
}
|
||
|
|
||
|
|
||
|
pub fn parse_datetime(input: &[u8]) -> IResult<&[u8], [u16; 6]> {
|
||
|
let mut buf = [0_u16; 6];
|
||
|
let mut parts = nom::multi::fill(parse_int2, &mut buf)(input);
|
||
|
parts[0] += 1900; // Year is from 1900
|
||
|
IResult::Ok(parts)
|
||
|
}
|
||
|
|
||
|
|
||
|
pub fn parse_bitarray(input: &[u8]) -> IResult<&[u8], [bool; 16]> {
|
||
|
let bits = [false; 16];
|
||
|
let (input, val) = parse_int2(input)?;
|
||
|
for ii in 0..16 {
|
||
|
bits[ii] = ((val >> (16 - 1 - ii)) & 0x01) == 1;
|
||
|
}
|
||
|
bits
|
||
|
}
|
||
|
|
||
|
|
||
|
pub fn parse_ascii(input: &[u8], length: usize) -> IResult<&[u8], Vec<u8>> {
|
||
|
let last = input[length - 1];
|
||
|
let true_length = if last == '\0' { length - 1 } else { length };
|
||
|
let vec = input[..true_length].to_vec();
|
||
|
IResult::Ok((input[length..], vec))
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Pack functions
|
||
|
*/
|
||
|
|
||
|
pub fn pack_bitarray(bits: &[bool; 16]) -> u16 {
|
||
|
let mut int: u16 = 0;
|
||
|
for ii in 0..16 {
|
||
|
int |= (bits[ii] as u16) << (16 - 1 - ii);
|
||
|
}
|
||
|
int
|
||
|
}
|
||
|
|
||
|
|
||
|
pub fn pack_int2(buf: &mut [u8], int: i16) {
|
||
|
BigEndian::write_i16(&mut buf, int)
|
||
|
}
|
||
|
|
||
|
pub fn pack_int4(buf: &mut [u8], int: i32) {
|
||
|
BigEndian::write_i32(&mut buf, int)
|
||
|
}
|
||
|
|
||
|
pub fn pack_real8(buf: &mut [u8], fnum: f64) {
|
||
|
BigEndian::write_u64(&mut buf, encode_real8(fnum))
|
||
|
}
|
||
|
|
||
|
pub fn pack_ascii(buf: &mut [u8], data: &[u8]) -> usize {
|
||
|
let len = data.len();
|
||
|
buf[..len].copy_from_slice(data);
|
||
|
if len % 2 == 1 {
|
||
|
buf[len] = '\0';
|
||
|
len + 1
|
||
|
} else {
|
||
|
len
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
pub fn pack_datetime(buf: &mut [u8], date: &[u16; 6]) {
|
||
|
assert!(buf.len() >= 6 * 2);
|
||
|
let year = date[0] - 1900;
|
||
|
pack_int2(&mut buf, year);
|
||
|
for ii in 1..6 {
|
||
|
pack_int2(&mut buf[(2 * ii)..], date[ii]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
pub fn encode_real8(fnum: f64) -> u64 {
|
||
|
// Convert from float64 to GDS REAL8 representation.
|
||
|
|
||
|
// Split the ieee float bitfields
|
||
|
let ieee = fnum.to_bits();
|
||
|
let sign = ieee & 0x8000_0000_0000_0000;
|
||
|
let ieee_exp = (ieee >> 52) as i32 & 0x7ff;
|
||
|
let ieee_mant = ieee & 0xf_ffff_ffff_ffff;
|
||
|
|
||
|
let subnorm = (ieee_exp == 0) & (ieee_mant != 0);
|
||
|
if (ieee_exp == 0) & (ieee_mant == 0) {
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
// IEEE normal double is (1 + ieee_mant / 2^52) * 2^(ieee_exp - 1023)
|
||
|
// IEEE subnormal double is (ieee_mant / 2^52) * 2^(-1022)
|
||
|
// GDS real8 is (gds_mant / 2^(7*8)) * 16^(gds_exp - 64)
|
||
|
// = (gds_mant / 2^56) * 2^(4 * gds_exp - 256)
|
||
|
|
||
|
// Convert exponent.
|
||
|
let exp2 = if subnorm { -1022 } else {ieee_exp + 1 - 1023}; // +1 is due to mantissa (1.xxxx in IEEE vs 0.xxxxx in GDSII)
|
||
|
let mut exp16 = exp2 / 4;
|
||
|
let rest = exp2 % 4;
|
||
|
|
||
|
// Compensate for exponent coarseness
|
||
|
let comp = rest != 0;
|
||
|
let mut shift;
|
||
|
if comp {
|
||
|
exp16 += 1;
|
||
|
shift = 4 - rest;
|
||
|
} else {
|
||
|
shift = rest;
|
||
|
}
|
||
|
shift -= 3; // account for gds bit position
|
||
|
|
||
|
// add leading one
|
||
|
let mut gds_mant_unshifted = ieee_mant;
|
||
|
if !subnorm {
|
||
|
gds_mant_unshifted += 0x10_0000_0000_0000;
|
||
|
}
|
||
|
|
||
|
let mut gds_mant = if shift > 0 {
|
||
|
gds_mant_unshifted >> shift
|
||
|
} else {
|
||
|
gds_mant_unshifted << -shift
|
||
|
};
|
||
|
|
||
|
// add gds exponent bias
|
||
|
let mut gds_exp = exp16 + 64;
|
||
|
|
||
|
if gds_exp < -14 {
|
||
|
// number is too small
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
let neg_biased = gds_exp < 0;
|
||
|
if neg_biased {
|
||
|
gds_mant >>= gds_exp * 4;
|
||
|
gds_exp = 0;
|
||
|
}
|
||
|
|
||
|
let too_big = (gds_exp > 0x7f) & !subnorm;
|
||
|
if too_big {
|
||
|
panic!("Number too big for real8 format"); //TODO error handling
|
||
|
}
|
||
|
|
||
|
let gds_exp_bits = gds_exp << 56;
|
||
|
|
||
|
let real8 = sign | gds_exp_bits | gds_mant;
|
||
|
real8
|
||
|
}
|