klamath-rs/src/record.rs

220 lines
5.9 KiB
Rust
Raw Normal View History

2021-12-18 21:05:00 -08:00
/*
* Generic record-level read/write functionality.
*/
use nom::IResult;
use std::io::Write;
use byteorder::BigEndian;
use basic::{pack_datetime, pack_bitarray, pack_ascii, pack_int2, pack_int4, pack_real8}; #[warn(unused_imports)]
use basic::{parse_datetime, parse_bitarray, parse_ascii, parse_int2, parse_int4, parse_real8}; #[warn(unused_imports)]
use basic::{OWResult};
use records;
//from .basic import parse_int2, parse_int4, parse_real8, parse_datetime, parse_bitarray
//from .basic import pack_int2, pack_int4, pack_real8, pack_datetime, pack_bitarray
//from .basic import parse_ascii, read
//#[no_mangle]
//pub extern "C" fn write_record_header(
#[repr(C)]
pub struct RecordHeader {
pub tag: u16,
pub data_size: u16,
}
impl RecordHeader {
pub fn parse(input: &[u8]) -> IResult<&[u8], RecordHeader> {
let (_, size) = nom::number::streaming::be_u16(input[0..])?;
let (_, tag) = nom::number::streaming::be_u16(input[2..])?;
Ok((input[4..], RecordHeader{tag:tag, data_size:size - 4}))
}
pub fn pack(self) -> [u8; 4] {
assert!(self.size < 0xffff - 4, "Record too big!");
let vals = [self.size, self.tag];
let mut buf = [0x77; 4];
BigEndian::write_u16_into(&vals, &mut buf);
buf
}
pub fn write<W: Write>(&self, ww: W) -> OWResult {
let bytes = self.pack();
ww.write(bytes)
}
}
pub trait Record {
fn tag() -> u32;
fn expected_size() -> Option<usize>;
//fn parse_data(input: &[u8], size: usize) -> IResult<&[u8], Self>;
}
impl Record {
pub fn check_size(&self, actual_size: usize) -> Result<(), &str> {
match self.expected_size() {
Some(size) => if size == actual_size {
Ok(())
} else {
Err(format!("Expected record size {}, got {}", size, actual_size))
},
None => Ok(()),
}
}
pub fn parse_header(input: &[u8]) -> IResult<&[u8], RecordHeader> {
RecordHeader::parse(input)
}
pub fn write_header<W: Write>(ww: W, data_size: usize) -> OWResult {
RecordHeader{tag: Self.tag(), size: data_size}.write(ww)
}
pub fn skip_past(input: &[u8]) -> IResult<&[u8], bool> {
/*
* Skip to the end of the next occurence of this record.
*
* Return:
* True if the record was encountered and skipped.
* False if the end of the library was reached.
*/
let (input, header) = RecordHeader::parse(input)?;
while header.tag != Self.tag() {
let (input, _) = nom::bytes::streaming::take(header.size)?;
if header.tag == records::RTAG_ENDLIB {
return Ok((input, false))
}
let (input, header) = RecordHeader::parse(input)?;
}
let (input, _) = nom::bytes::streaming::take(header.size)?;
Ok((input, true))
}
/*
pub fn skip_and_read(input: &[u8]) -> IResult<&[u8], bool>{
size, tag = Record.read_header(stream)
while tag != cls.tag{
stream.seek(size, io.SEEK_CUR)
size, tag = Record.read_header(stream)
}
data = cls.read_data(stream, size)
return data
}
def read(cls: Type[R], stream: BinaryIO){
size = expect_record(stream, cls.tag)
data = cls.read_data(stream, size)
return data
}
def write(cls, stream: BinaryIO, data) -> int {
data_bytes = cls.pack_data(data)
b = cls.write_header(stream, len(data_bytes))
b += stream.write(data_bytes)
return b
}
*/
}
pub trait BitArray {
fn parse_data(input: &[u8]) -> IResult<&[u8], [bool; 16]> {
parse_bitarray(input)
}
fn pack_data(buf: &mut [u8], vals: &[bool; 16]) {
pack_bitarray(&mut buf, vals)
}
}
pub trait Int2 {
fn parse_data(input: &[u8]) -> IResult<&[u8], i16> {
parse_int2(input)
}
fn pack_data(buf: &mut [u8], val: i16) {
pack_int2(&mut buf, val)
}
}
pub trait Int4 {
fn parse_data(input: &[u8]) -> IResult<&[u8], i32> {
parse_int4(input)
}
fn pack_data(buf: &mut [u8], val: i32) {
pack_int4(&mut buf, val)
}
}
pub trait Int2Array {
fn parse_data(input: &[u8], size: usize) -> IResult<&[u8], Vec<i16>> {
assert!(size % 2 == 0, "Record must contain an integer quantity of integers");
nom::multi::count(parse_int2, size / 2)(input)
}
fn pack_data(buf: &mut [u8], vals: &[i16]) {
BigEndian::write_i16_into(&vals, &mut buf)
}
}
pub trait Int4Array {
fn parse_data(input: &[u8], size: usize) -> IResult<&[u8], Vec<i32>> {
assert!(size % 4 == 0, "Record must contain an integer quantity of integers");
nom::multi::count(parse_int4, size / 4)(input)
}
fn pack_data(buf: &mut [u8], vals: &[i32]) {
BigEndian::write_i32_into(&vals, &mut buf)
}
}
pub trait Real8 {
fn parse_data(input: &[u8]) -> IResult<&[u8], f64> {
parse_real8(input)
}
fn pack_data(buf: &mut [u8], val: f64) {
pack_real8(&mut buf, val)
}
}
pub trait ASCII {
fn parse_data(input: &[u8]) -> IResult<&[u8], Vec<u8>> {
parse_ascii(input)
}
fn pack_data(buf: &mut [u8], data: &[u8]) {
pack_ascii(&mut buf, data)
}
}
pub trait DateTime {
fn parse_data(input: &[u8]) -> IResult<&[u8], [u16; 6]> {
parse_datetime(input)
}
fn pack_data(buf: &mut [u8], data: [u16; 6]) {
pack_datetime(&mut buf, data)
}
}
impl<DTR: DateTime + Record> DTR {
fn skip_and_read(input: &[u8]) -> IResult<&[u8], [DTR; 2]> {
let mut header = Self.read_header(input)?;
while header.tag != Self.tag() {
nom::bytes::streaming::take(header.data_size)?;
header = Self.read_header(input)?;
}
assert!(header.data_size == 6 * 2);
let data0 = Self.read_data(&input)?;
let data1 = Self.read_data(&input)?;
Ok([data0, data1])
}
}