Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pointer: jump to position, parse/write struct, and come back #100

Open
marnunez opened this issue Sep 21, 2020 · 5 comments
Open

Pointer: jump to position, parse/write struct, and come back #100

marnunez opened this issue Sep 21, 2020 · 5 comments
Labels
enhancement New feature or request

Comments

@marnunez
Copy link

In construct, there's a wrapper called Pointer, which is really useful for binary files that have jumptables. It uses a field as an offset, jumps to the position, parses/writes the content of the structure, and jumps back to position. Would something like this be feasible in Deku?

@sharksforarms
Copy link
Owner

I don't see why not! Possibly a seek and peek attribute. Do you have an example protocol or format for reference?

@marnunez
Copy link
Author

There's a nice example of case of use in the construct gallery for the PE/COFF format.

@kitlith
Copy link

kitlith commented Oct 7, 2020

So, I went to implement something like this as part of my own project, and ran into the fact that currently, an implementation of DekuRead has no way to perform an absolute offset operation -- you'd have to pass in the original BitSlice as context. so, that indicates to me that some breaking changes to deku are likely necessary to make any sort of file pointer ergonomic, or else some very careful additions to the derive macro to thread the starting position through to whatever needs it.

@sharksforarms
Copy link
Owner

@kitlith Breaking changes are fine with me. This crate is still pre 1.0.0 :)

@sharksforarms sharksforarms added enhancement New feature or request and removed good first issue labels Nov 4, 2020
@CJKay
Copy link

CJKay commented Sep 3, 2021

For anybody looking for an interim solution, I hacked up this absolute nightmare:

fn read_offset<'a, C, T, O>(
    rest: &'a BitSlice<Msb0, u8>,
    input: &'a BitSlice<Msb0, u8>,
    ctx: C,
    offset: O,
) -> Result<(&'a BitSlice<Msb0, u8>, T), DekuError>
where
    C: Copy,
    T: DekuRead<'a, C>,
    O: Into<usize>,
{
    let offset = offset.into();
    let subslice = input.get(offset..).ok_or_else(|| {
        let need = NeedSize::new(rest.len() - offset);

        DekuError::Incomplete(need)
    })?;

    T::read(subslice, ctx)
}

fn read_offset_count<'a, C, T, U, O, N>(
    rest: &'a BitSlice<Msb0, u8>,
    input: &'a BitSlice<Msb0, u8>,
    ctx: C,
    offset: O,
    count: N,
) -> Result<(&'a BitSlice<Msb0, u8>, T), DekuError>
where
    C: Copy,
    T: DekuRead<'a, (Limit<U, fn(&U) -> bool>, C)>,
    U: Copy + DekuRead<'a, C>,
    O: Into<usize>,
    N: Into<usize>,
{
    read_offset(rest, input, (Limit::new_count(count.into()), ctx), offset)
}

Usage example:

#[derive(PartialEq, Debug, DekuRead)]
#[deku(endian = "little", ctx = "endian: deku::ctx::Endian")]
pub struct MorrowindArchive {
    ...

    /// File name hashes.
    #[deku(reader = "read_offset_count(deku::rest, deku::input_bits, endian, ((*file_name_hashes_offset as usize) + 8) * 8, *file_count as usize)")]
    file_name_hashes: Vec<u64>,
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants