/* * 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; /* * 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> { 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 }