sharksforarms / deku

Declarative binary reading and writing: bit-level, symmetric, serialization/deserialization
Apache License 2.0
1.05k stars 54 forks source link

Error: Parse("Too much data") using custom readers #404

Closed sempervictus closed 5 months ago

sempervictus commented 5 months ago

I have a strange conditional read situation in

pub(super) struct Header {
    #[deku(reader = "Header::read_len(deku::reader, BitSize(8))")]
    pub(super) pkt_length: u16,
    #[deku(reader = "Header::read_sum(deku::reader, BitSize(8))")]
    pub(super) pkt_checksum: u16,
    pub(super) pkt_type: u8,
    pub(super) flags: u8,
    pub(super) checksum: u16
}

which i am handling via

    /// Read length bytes, figure out which ones to use
    fn read_len<R: std::io::Read>(
        reader: &mut Reader<R>,
        bit_size: BitSize,
    ) -> Result<u16, DekuError> {
        let b0 = u8::from_reader_with_ctx(reader, bit_size)?;
        let b1 = u8::from_reader_with_ctx(reader, bit_size)?;
        let pkt_length = ((b0 as u16) << 8) + ((b1 as u16) << 0);
        match pkt_length {
            0|1|2|3|4|5|6|7 => {
                let b2 = u8::from_reader_with_ctx(reader, bit_size)?;
                let b3 = u8::from_reader_with_ctx(reader, bit_size)?;
                let mut pkt_checksum = ((b2 as u16) << 8) + ((b3 as u16) << 0);
                let pkt_length = match pkt_checksum {
                    0 | 4 => {
                        let res = (((b0 as u32) << 8) + ((b1 as u32) << 0)) as u16;
                        res
                    },
                    _ => {
                        pkt_checksum = 0;
                        let res = (((b0 as u32) << 24)
                        + ((b1 as u32) << 16)
                        + ((b2 as u32) << 8)
                        + ((b3 as u32) << 0)) as u16;
                        res
                    },
                };
                Ok(pkt_length)
            },
            _ => Ok(pkt_length)
        }
    }
    fn read_sum<R: std::io::Read>(
        reader: &mut Reader<R>,
        bit_size: BitSize,
    ) -> Result<u16, DekuError> {
        // Check to see how many bytes the prior read consumed
        if reader.bits_read == 16 {
            let pkt_checksum = u16::from_reader_with_ctx(reader, bit_size)?;
            debug_println!("Reader bits read after sum: {}", reader.bits_read);
            Ok(pkt_checksum)
        } else {
            Ok(0u16)
        }
    }

whether its read directly as u16s or with the reader impls above, it's 8B of data consumed overall. Unfortunately, something goes south internally when using these and reading a Header which throws Error: Parse("Too much data"). Am i messing up the Reader cursor somehow by looking at bits_read or breaking something else? :smile:

Potentially of note, i am running c288e8add (the read_all PR).

sempervictus commented 5 months ago

Ah, got it - BitSize is the overall read-length, not the relevant bits of bytes. It's trying read a u16 from 8b vs 2B interpreted at 8b each.