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

Offset-based reading #52

Closed
madprogrammer opened this issue Dec 9, 2014 · 3 comments
Closed

Offset-based reading #52

madprogrammer opened this issue Dec 9, 2014 · 3 comments

Comments

@madprogrammer
Copy link

Suppose I have a table of offsets to some child objects, given that the offsets in the table are relative to the parent:

    class BlobIndex < BinData::Record
        uint32be :type
        uint32be :offs
    end

    class Blob < BinData::Record; end;

    class SuperBlob < BinData::Record
        uint32be :len
        array :blob_offsets, :type => :blob_index, :initial_length => :len
        # Blob objects follow, according to the offsets, the offset of the first blob will be equal to the length of the blob_offsets array in bytes
    end

I couldn't find how can I make such structure into an array of Blob records. I have also tried:

array :blob_offsets, :type => :blob_index, :initial_length => :len
array :blobs, :initial_length => :len do
   blob :adjust_offset => lambda { offset[index].offs }
end

Which didn't work properly, probably because the offset is adjusted related to the start of the IO, not the start of SuperBlob object. Is it possible to rebase the offset calculation to a given field in the SuperBlob object. I'm trying to port the following code from Python (notice it has a feature called Anchor: https://github.com/comex/cs/blob/master/macho_cs.py)

@madprogrammer
Copy link
Author

Managed to solve it:

    class BlobIndex < BinData::Record
        uint32be :type
        uint32be :offs
    end

    class Blob < BinData::Record; end;

    class SuperBlob < BinData::Record
        uint32be :len
        array :blob_offsets, :type => :blob_index, :initial_length => :len
        array :blobs, :initial_length => :len do
            blob :adjust_offset => lambda { self.parent.abs_offset - 8 + blob_offsets[index].offs }
        end
    end

The :adjust_offset parameter does lack documentation, though.

@dmendel
Copy link
Owner

dmendel commented Dec 20, 2014

The :adjust_offset parameter is undocumented as it is not officially supported. I am still thinking about a better way to perform the same functionality. I'll leave this issue open until I've added something official.

@dmendel
Copy link
Owner

dmendel commented Mar 24, 2016

BinData operates in a single pass as single pass formats are easier to comprehend. Easy comprehension is a primary design goal.

The offset example above is not necessarily single pass, as the offsets may point to earlier in the stream. Solving this example requires multi pass processing, introduced in BinData 2.3.0.

Here is how to do this with BinData:

class Blob < BinData::Record; end;

class SuperBlob < BinData::Record
  auto_call_delayed_io
  endian :big

  uint32 :len
  array  :blob_offsets, :initial_length => :len do
    uint32 :type
    uint32 :offs
  end

  array :blobs, :initial_length => :len do
    delayed_io :type => :blob,
               :read_abs_offset => lambda { offset_adjustment + blob_offsets[index].offs }
  end
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants