220 lines
5.9 KiB
Rust
220 lines
5.9 KiB
Rust
|
/*
|
||
|
* 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])
|
||
|
}
|
||
|
}
|