Skipping Bytes when reading with BinData

2019-09-16 06:46发布

问题:

So I have a Record like such:

class Property < BinData::Record
    endian :little

    int32  :name_len
    string :name, read_length: :name_len

    # want to quit here.

    int32 :type_len
    string :type, read_length: :type_len
end

Is there a way for me to stop reading from the Record after it reads :name_len and :name, only if :name is equal to a certain value? Or is it the case that once you begin to read a file with a Record it must run all the way through?

I know I can use :onlyif to skip all the remaining, but is there a way to put the :onlyif on everything after? Can you put an :onlyif on a choice?

Code I tried:

class Property < BinData::Record
    endian :little

    int32  :name_len
    string :name, read_length: :name_len

    int32 :type_len, :onlyif => :not_none?
    string :type, read_length: :type_len, :onlyif => :not_none?

    int64 :data_len, :onlyif => :not_none?    
    choice :data, :onlyif => :not_none?, selection: :type do
        int32 "IntProperty\x00"

        float "FloatProperty\x00"

        struct "StrProperty\x00" do
            int32 :len
            string :data, read_length: :len
        end 

        struct "NameProperty\x00" do
            int32 :len
            string :data, read_length: :len
        end

        struct "ArrayProperty\x00" do
            int32 :num_items
            array :properties, type: :property, initial_length: :num_items
        end
    end

    def not_none?
        name != 'None\x00'
    end
end

I also tried putting everything below the :name_len and :name in it's own Record and doing this:

class Property < BinData::Record
    endian :little

    string_record :name

    property_data :p_data, :onlyif => :not_none?

    def not_none?
        name.data != 'None\x00'
    end 
end

But this didn't work because if I put the PropertyData Record above this (which it has to be because Property needs to know what PropertyData is) then it errors because PropertyData needs to know what Property is (because it fills the array with that type). There is no way for them to both know each other exist since they both use one another.

回答1:

[T]his didn't work because if I put the PropertyData Record above this (which it has to be because Property needs to know what PropertyData is) then it errors because PropertyData needs to know what Property is (because it fills the array with that type).

You can solve this by declaring the PropertyData class before Property, but filling it out after:

class PropertyData < BinData::Record; end # Forward declaration

class Property < BinData::Record
  endian :little

  # ...
end

class PropertyData < BinData::Record
  endian :little

  # ...
end

You can see the same thing happening in the list.rb example.



标签: ruby bindata