6

I have a C-like struct like this:

SomeStruct << BinData::Record
endian :little

uint32 :offsetOfName
uint32 :offsetOfLastname
#...
uint32 :lenVars
struct :Person, :length => :lenVars
    string :name
    string :lname
    #...
end

I have a bunch of offsets and lengths before :Person. All the offsets and lengths describe the data within the :Person struct.

How can I start reading data at a specified offset, for the given length, or until the next offset?

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
omninonsense
  • 6,644
  • 9
  • 45
  • 66

3 Answers3

4

Seek to offset 1234 and then read 32 bytes into String s:

open 'some-binary-file', 'r' do |f|
  f.seek 1234
  s = f.read 32
  # tho in your case, something like:
  o = aBinData_object.read f
  p s
end

Update: It looks like BinData understands records that encode the lengths of their own fields, but I doubt if there is any way to make it seek for you, unless you are willing to essentially encode dummy fields the size of the seeked-over space, and then ignore forever the data that it's skipping.

I suspect that a good solution will involve an explicit seek and then someBinDataObject.read(f) to get the record.

DigitalRoss
  • 143,651
  • 25
  • 248
  • 329
  • I was hoping for a solution with BinData, but thanks anyway. I'll go forth and play with the code a little, will let you know of the results. – omninonsense Jun 12 '11 at 20:23
  • @DigitalRoss Why are you reading it into a string at all? open 'some-binary-file', 'r' do |f| f.seek 1234 o = aBinData_object.read f end Wouldn't that be enough? – thegreendroid Feb 26 '12 at 20:38
2

BinData has two options related to offsets - :check_offset and :adjust_offset. These are not documented in the manual, but are documented in bindata/offset.rb

Here's how they'd work into your example.

class SomeStruct < BinData::Record
  endian :little

  uint32 :offsetOfName
  uint32 :offsetOfLastname
  #...
  uint32 :lenVars

  struct :person do
    string :name,  :adjust_offset => :offsetOfName,
                   :read_length => lambda { offsetOfLastName - offsetOfName }
    string :lname, :adjust_offset => :offsetOfLastName,
                   :read_length => ...
    #...
  end
end
  • Do you know if adjust_offset is absolute or relative? The API documentation is really lacking in this regard. – thegreendroid Feb 27 '12 at 22:21
  • I looked at the source and figured out that it is indeed relative. However, I need to adjust the offset based on the current file (io) offset. For example - :adjust_offset => (SOME_CONSTANT - currentOffset) How do I access the file's current offset in the closure (lambda)? – thegreendroid Feb 28 '12 at 00:37
1

Docs for BinData: http://bindata.rubyforge.org/#nested_records

Not familiar with BinData so maybe I'm off base here but the examples seem to define a class for the outermost structure:

class SomeStruct < BinData::Record
...

Then it talks about nesting anonymous structs within that class:

  struct :person do
  ...

Also, looks like you're giving your inner struct :person a length. My guess is that length doesn't apply here.

seph
  • 6,066
  • 3
  • 21
  • 19
  • Oh, the length has to stay, but it's not that relevant, really. I could take it out, even. I've read the documentation a few times, looking for what I need, but couldn't find it, so that's why I resorted to bothering smarter people on here. :P – omninonsense Jun 12 '11 at 20:45
  • My understanding is that the length of a struct(in c) is the sum of the lengths of the primitive types within it. I created a BinData::Struct and tried to take the length: Got this error: undefined method `length' for {"a"=>0}:BinData::Struct – seph Jun 12 '11 at 21:20