bindata 0.9.3 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of bindata might be problematic. Click here for more details.
- data/ChangeLog +18 -0
 - data/NEWS +59 -0
 - data/README +22 -23
 - data/TODO +18 -12
 - data/examples/gzip.rb +4 -4
 - data/lib/bindata.rb +4 -3
 - data/lib/bindata/array.rb +202 -132
 - data/lib/bindata/base.rb +147 -166
 - data/lib/bindata/{single.rb → base_primitive.rb} +82 -56
 - data/lib/bindata/bits.rb +31 -770
 - data/lib/bindata/choice.rb +157 -82
 - data/lib/bindata/float.rb +25 -27
 - data/lib/bindata/int.rb +144 -177
 - data/lib/bindata/io.rb +59 -49
 - data/lib/bindata/lazy.rb +80 -50
 - data/lib/bindata/params.rb +134 -26
 - data/lib/bindata/{single_value.rb → primitive.rb} +71 -64
 - data/lib/bindata/{multi_value.rb → record.rb} +52 -70
 - data/lib/bindata/registry.rb +49 -17
 - data/lib/bindata/rest.rb +6 -10
 - data/lib/bindata/sanitize.rb +55 -70
 - data/lib/bindata/string.rb +60 -42
 - data/lib/bindata/stringz.rb +34 -35
 - data/lib/bindata/struct.rb +197 -152
 - data/lib/bindata/trace.rb +35 -0
 - data/spec/array_spec.rb +128 -112
 - data/spec/{single_spec.rb → base_primitive_spec.rb} +102 -61
 - data/spec/base_spec.rb +190 -185
 - data/spec/bits_spec.rb +126 -98
 - data/spec/choice_spec.rb +89 -98
 - data/spec/example.rb +19 -0
 - data/spec/float_spec.rb +28 -44
 - data/spec/int_spec.rb +217 -127
 - data/spec/io_spec.rb +41 -24
 - data/spec/lazy_spec.rb +95 -49
 - data/spec/primitive_spec.rb +191 -0
 - data/spec/{multi_value_spec.rb → record_spec.rb} +124 -89
 - data/spec/registry_spec.rb +53 -12
 - data/spec/rest_spec.rb +2 -3
 - data/spec/sanitize_spec.rb +47 -73
 - data/spec/spec_common.rb +13 -1
 - data/spec/string_spec.rb +34 -23
 - data/spec/stringz_spec.rb +10 -18
 - data/spec/struct_spec.rb +91 -63
 - data/spec/system_spec.rb +291 -0
 - metadata +12 -8
 - data/spec/single_value_spec.rb +0 -131
 
| 
         @@ -1,18 +1,19 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'bindata/ 
     | 
| 
      
 1 
     | 
    
         
            +
            require 'bindata/base_primitive'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'bindata/registry'
         
     | 
| 
       2 
3 
     | 
    
         
             
            require 'bindata/struct'
         
     | 
| 
       3 
4 
     | 
    
         | 
| 
       4 
5 
     | 
    
         
             
            module BinData
         
     | 
| 
       5 
     | 
    
         
            -
              # A  
     | 
| 
       6 
     | 
    
         
            -
              # The data type must contain a  
     | 
| 
       7 
     | 
    
         
            -
              # that contain multiple values see BinData:: 
     | 
| 
      
 6 
     | 
    
         
            +
              # A Primitive is a declarative way to define a new BinData data type.
         
     | 
| 
      
 7 
     | 
    
         
            +
              # The data type must contain a primitive value only, i.e numbers or strings.
         
     | 
| 
      
 8 
     | 
    
         
            +
              # For new data types that contain multiple values see BinData::Record.
         
     | 
| 
       8 
9 
     | 
    
         
             
              #
         
     | 
| 
       9 
     | 
    
         
            -
              # To define a new data type, set fields as if for  
     | 
| 
      
 10 
     | 
    
         
            +
              # To define a new data type, set fields as if for Record and add a
         
     | 
| 
       10 
11 
     | 
    
         
             
              # #get and #set method to extract / convert the data between the fields
         
     | 
| 
       11 
12 
     | 
    
         
             
              # and the #value of the object.
         
     | 
| 
       12 
13 
     | 
    
         
             
              #
         
     | 
| 
       13 
14 
     | 
    
         
             
              #    require 'bindata'
         
     | 
| 
       14 
15 
     | 
    
         
             
              #
         
     | 
| 
       15 
     | 
    
         
            -
              #    class PascalString < BinData:: 
     | 
| 
      
 16 
     | 
    
         
            +
              #    class PascalString < BinData::Primitive
         
     | 
| 
       16 
17 
     | 
    
         
             
              #      uint8  :len,  :value => lambda { data.length }
         
     | 
| 
       17 
18 
     | 
    
         
             
              #      string :data, :read_length => :len
         
     | 
| 
       18 
19 
     | 
    
         
             
              #    
         
     | 
| 
         @@ -26,12 +27,12 @@ module BinData 
     | 
|
| 
       26 
27 
     | 
    
         
             
              #    end
         
     | 
| 
       27 
28 
     | 
    
         
             
              #
         
     | 
| 
       28 
29 
     | 
    
         
             
              #    ps = PascalString.new(:initial_value => "hello")
         
     | 
| 
       29 
     | 
    
         
            -
              #    ps. 
     | 
| 
      
 30 
     | 
    
         
            +
              #    ps.to_binary_s #=> "\005hello"
         
     | 
| 
       30 
31 
     | 
    
         
             
              #    ps.read("\003abcde")
         
     | 
| 
       31 
32 
     | 
    
         
             
              #    ps.value #=> "abc"
         
     | 
| 
       32 
33 
     | 
    
         
             
              #
         
     | 
| 
       33 
34 
     | 
    
         
             
              #    # Unsigned 24 bit big endian integer
         
     | 
| 
       34 
     | 
    
         
            -
              #    class Uint24be < BinData:: 
     | 
| 
      
 35 
     | 
    
         
            +
              #    class Uint24be < BinData::Primitive
         
     | 
| 
       35 
36 
     | 
    
         
             
              #      uint8 :byte1
         
     | 
| 
       36 
37 
     | 
    
         
             
              #      uint8 :byte2
         
     | 
| 
       37 
38 
     | 
    
         
             
              #      uint8 :byte3
         
     | 
| 
         @@ -56,100 +57,93 @@ module BinData 
     | 
|
| 
       56 
57 
     | 
    
         
             
              #
         
     | 
| 
       57 
58 
     | 
    
         
             
              # == Parameters
         
     | 
| 
       58 
59 
     | 
    
         
             
              #
         
     | 
| 
       59 
     | 
    
         
            -
              #  
     | 
| 
      
 60 
     | 
    
         
            +
              # Primitive objects accept all the parameters that BinData::BasePrimitive do.
         
     | 
| 
       60 
61 
     | 
    
         
             
              #
         
     | 
| 
       61 
     | 
    
         
            -
              class  
     | 
| 
      
 62 
     | 
    
         
            +
              class Primitive < BasePrimitive
         
     | 
| 
       62 
63 
     | 
    
         | 
| 
       63 
64 
     | 
    
         
             
                class << self
         
     | 
| 
       64 
65 
     | 
    
         | 
| 
       65 
     | 
    
         
            -
                  # Register the names of all subclasses of this class.
         
     | 
| 
       66 
66 
     | 
    
         
             
                  def inherited(subclass) #:nodoc:
         
     | 
| 
      
 67 
     | 
    
         
            +
                    # Register the names of all subclasses of this class.
         
     | 
| 
       67 
68 
     | 
    
         
             
                    register(subclass.name, subclass)
         
     | 
| 
       68 
69 
     | 
    
         
             
                  end
         
     | 
| 
       69 
70 
     | 
    
         | 
| 
       70 
     | 
    
         
            -
                  # Can this data object self reference itself?
         
     | 
| 
       71 
71 
     | 
    
         
             
                  def recursive?
         
     | 
| 
      
 72 
     | 
    
         
            +
                    # A Primitive can possibly self reference itself.
         
     | 
| 
       72 
73 
     | 
    
         
             
                    true
         
     | 
| 
       73 
74 
     | 
    
         
             
                  end
         
     | 
| 
       74 
75 
     | 
    
         | 
| 
       75 
     | 
    
         
            -
                  # Returns or sets the endianess of numerics used in this stucture.
         
     | 
| 
       76 
     | 
    
         
            -
                  # Endianess is applied to the fields of this structure.
         
     | 
| 
       77 
     | 
    
         
            -
                  # Valid values are :little and :big.
         
     | 
| 
       78 
76 
     | 
    
         
             
                  def endian(endian = nil)
         
     | 
| 
       79 
77 
     | 
    
         
             
                    @endian ||= nil
         
     | 
| 
       80 
78 
     | 
    
         
             
                    if [:little, :big].include?(endian)
         
     | 
| 
       81 
79 
     | 
    
         
             
                      @endian = endian
         
     | 
| 
       82 
80 
     | 
    
         
             
                    elsif endian != nil
         
     | 
| 
       83 
     | 
    
         
            -
                      raise ArgumentError, "unknown value for endian '#{endian}'"
         
     | 
| 
      
 81 
     | 
    
         
            +
                      raise ArgumentError, "unknown value for endian '#{endian}'", caller(1)
         
     | 
| 
       84 
82 
     | 
    
         
             
                    end
         
     | 
| 
       85 
83 
     | 
    
         
             
                    @endian
         
     | 
| 
       86 
84 
     | 
    
         
             
                  end
         
     | 
| 
       87 
85 
     | 
    
         | 
| 
       88 
     | 
    
         
            -
                  # Returns all stored fields.  Should only be called by
         
     | 
| 
       89 
     | 
    
         
            -
                  # #sanitize_parameters
         
     | 
| 
       90 
     | 
    
         
            -
                  def fields
         
     | 
| 
       91 
     | 
    
         
            -
                    @fields || []
         
     | 
| 
       92 
     | 
    
         
            -
                  end
         
     | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
       94 
     | 
    
         
            -
                  # Used to define fields for the internal structure.
         
     | 
| 
       95 
86 
     | 
    
         
             
                  def method_missing(symbol, *args)
         
     | 
| 
       96 
87 
     | 
    
         
             
                    name, params = args
         
     | 
| 
       97 
88 
     | 
    
         | 
| 
       98 
89 
     | 
    
         
             
                    type = symbol
         
     | 
| 
       99 
     | 
    
         
            -
                    name =  
     | 
| 
      
 90 
     | 
    
         
            +
                    name = name.to_s
         
     | 
| 
       100 
91 
     | 
    
         
             
                    params ||= {}
         
     | 
| 
       101 
92 
     | 
    
         | 
| 
       102 
     | 
    
         
            -
                     
     | 
| 
       103 
     | 
    
         
            -
                     
     | 
| 
       104 
     | 
    
         
            -
             
     | 
| 
       105 
     | 
    
         
            -
                    # check that type is known
         
     | 
| 
       106 
     | 
    
         
            -
                    unless Sanitizer.type_exists?(type, endian)
         
     | 
| 
       107 
     | 
    
         
            -
                      raise TypeError, "unknown type '#{type}' for #{self}", caller
         
     | 
| 
       108 
     | 
    
         
            -
                    end
         
     | 
| 
       109 
     | 
    
         
            -
             
     | 
| 
       110 
     | 
    
         
            -
                    # check that name is okay
         
     | 
| 
       111 
     | 
    
         
            -
                    if name != nil
         
     | 
| 
       112 
     | 
    
         
            -
                      # check for duplicate names
         
     | 
| 
       113 
     | 
    
         
            -
                      @fields.each do |t, n, p|
         
     | 
| 
       114 
     | 
    
         
            -
                        if n == name
         
     | 
| 
       115 
     | 
    
         
            -
                          raise SyntaxError, "duplicate field '#{name}' in #{self}", caller
         
     | 
| 
       116 
     | 
    
         
            -
                        end
         
     | 
| 
       117 
     | 
    
         
            -
                      end
         
     | 
| 
      
 93 
     | 
    
         
            +
                    ensure_type_exists(type)
         
     | 
| 
      
 94 
     | 
    
         
            +
                    ensure_valid_name(name) unless name.nil?
         
     | 
| 
       118 
95 
     | 
    
         | 
| 
       119 
     | 
    
         
            -
             
     | 
| 
       120 
     | 
    
         
            -
                      if self.instance_methods.include?(name)
         
     | 
| 
       121 
     | 
    
         
            -
                        raise NameError.new("", name),
         
     | 
| 
       122 
     | 
    
         
            -
                              "field '#{name}' shadows an existing method", caller
         
     | 
| 
       123 
     | 
    
         
            -
                      end
         
     | 
| 
       124 
     | 
    
         
            -
                    end
         
     | 
| 
       125 
     | 
    
         
            -
             
     | 
| 
       126 
     | 
    
         
            -
                    # remember this field.  These fields will be recalled upon creating
         
     | 
| 
       127 
     | 
    
         
            -
                    # an instance of this class
         
     | 
| 
       128 
     | 
    
         
            -
                    @fields.push([type, name, params])
         
     | 
| 
      
 96 
     | 
    
         
            +
                    append_field(type, name, params)
         
     | 
| 
       129 
97 
     | 
    
         
             
                  end
         
     | 
| 
       130 
98 
     | 
    
         | 
| 
       131 
     | 
    
         
            -
                  # Ensures that +params+ is of the form expected by #initialize.
         
     | 
| 
       132 
99 
     | 
    
         
             
                  def sanitize_parameters!(sanitizer, params)
         
     | 
| 
       133 
100 
     | 
    
         
             
                    struct_params = {}
         
     | 
| 
       134 
     | 
    
         
            -
                    struct_params[:fields] =  
     | 
| 
       135 
     | 
    
         
            -
                    struct_params[:endian] =  
     | 
| 
      
 101 
     | 
    
         
            +
                    struct_params[:fields] = fields
         
     | 
| 
      
 102 
     | 
    
         
            +
                    struct_params[:endian] = endian unless endian.nil?
         
     | 
| 
       136 
103 
     | 
    
         | 
| 
       137 
104 
     | 
    
         
             
                    params[:struct_params] = struct_params
         
     | 
| 
       138 
105 
     | 
    
         | 
| 
       139 
106 
     | 
    
         
             
                    super(sanitizer, params)
         
     | 
| 
       140 
107 
     | 
    
         
             
                  end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                  #-------------
         
     | 
| 
      
 110 
     | 
    
         
            +
                  private
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                  def ensure_type_exists(type)
         
     | 
| 
      
 113 
     | 
    
         
            +
                    unless RegisteredClasses.is_registered?(type, endian)
         
     | 
| 
      
 114 
     | 
    
         
            +
                      raise TypeError, "unknown type '#{type}' for #{self}", caller(2)
         
     | 
| 
      
 115 
     | 
    
         
            +
                    end
         
     | 
| 
      
 116 
     | 
    
         
            +
                  end
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                  def ensure_valid_name(name)
         
     | 
| 
      
 119 
     | 
    
         
            +
                    fields.each do |t, n, p|
         
     | 
| 
      
 120 
     | 
    
         
            +
                      if n == name
         
     | 
| 
      
 121 
     | 
    
         
            +
                        raise SyntaxError, "duplicate field '#{name}' in #{self}", caller(4)
         
     | 
| 
      
 122 
     | 
    
         
            +
                      end
         
     | 
| 
      
 123 
     | 
    
         
            +
                    end
         
     | 
| 
      
 124 
     | 
    
         
            +
                    if self.instance_methods.include?(name)
         
     | 
| 
      
 125 
     | 
    
         
            +
                      raise NameError.new("", name),
         
     | 
| 
      
 126 
     | 
    
         
            +
                            "field '#{name}' shadows an existing method", caller(2)
         
     | 
| 
      
 127 
     | 
    
         
            +
                    end
         
     | 
| 
      
 128 
     | 
    
         
            +
                  end
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                  def append_field(type, name, params)
         
     | 
| 
      
 131 
     | 
    
         
            +
                    fields.push([type, name, params])
         
     | 
| 
      
 132 
     | 
    
         
            +
                  end
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                  def fields
         
     | 
| 
      
 135 
     | 
    
         
            +
                    @fields ||= []
         
     | 
| 
      
 136 
     | 
    
         
            +
                  end
         
     | 
| 
       141 
137 
     | 
    
         
             
                end
         
     | 
| 
       142 
138 
     | 
    
         | 
| 
       143 
     | 
    
         
            -
                 
     | 
| 
       144 
     | 
    
         
            -
                bindata_mandatory_parameter :struct_params
         
     | 
| 
      
 139 
     | 
    
         
            +
                mandatory_parameter :struct_params
         
     | 
| 
       145 
140 
     | 
    
         | 
| 
       146 
141 
     | 
    
         
             
                def initialize(params = {}, parent = nil)
         
     | 
| 
       147 
142 
     | 
    
         
             
                  super(params, parent)
         
     | 
| 
       148 
143 
     | 
    
         | 
| 
       149 
     | 
    
         
            -
                  @struct = BinData::Struct.new( 
     | 
| 
      
 144 
     | 
    
         
            +
                  @struct = BinData::Struct.new(get_parameter(:struct_params), self)
         
     | 
| 
       150 
145 
     | 
    
         
             
                end
         
     | 
| 
       151 
146 
     | 
    
         | 
| 
       152 
     | 
    
         
            -
                # Forward method calls to the internal struct.
         
     | 
| 
       153 
147 
     | 
    
         
             
                def method_missing(symbol, *args, &block)
         
     | 
| 
       154 
148 
     | 
    
         
             
                  if @struct.respond_to?(symbol)
         
     | 
| 
       155 
149 
     | 
    
         
             
                    @struct.__send__(symbol, *args, &block)
         
     | 
| 
         @@ -158,25 +152,29 @@ module BinData 
     | 
|
| 
       158 
152 
     | 
    
         
             
                  end
         
     | 
| 
       159 
153 
     | 
    
         
             
                end
         
     | 
| 
       160 
154 
     | 
    
         | 
| 
      
 155 
     | 
    
         
            +
                def debug_name_of(child)
         
     | 
| 
      
 156 
     | 
    
         
            +
                  debug_name + "-internal-"
         
     | 
| 
      
 157 
     | 
    
         
            +
                end
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
                def offset_of(child)
         
     | 
| 
      
 160 
     | 
    
         
            +
                  offset
         
     | 
| 
      
 161 
     | 
    
         
            +
                end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
       161 
163 
     | 
    
         
             
                #---------------
         
     | 
| 
       162 
164 
     | 
    
         
             
                private
         
     | 
| 
       163 
165 
     | 
    
         | 
| 
       164 
     | 
    
         
            -
                # Retrieve a sensible default from the internal struct.
         
     | 
| 
       165 
166 
     | 
    
         
             
                def sensible_default
         
     | 
| 
       166 
167 
     | 
    
         
             
                  get
         
     | 
| 
       167 
168 
     | 
    
         
             
                end
         
     | 
| 
       168 
169 
     | 
    
         | 
| 
       169 
     | 
    
         
            -
                 
     | 
| 
       170 
     | 
    
         
            -
                def read_val(io)
         
     | 
| 
      
 170 
     | 
    
         
            +
                def read_and_return_value(io)
         
     | 
| 
       171 
171 
     | 
    
         
             
                  @struct.read(io)
         
     | 
| 
       172 
172 
     | 
    
         
             
                  get
         
     | 
| 
       173 
173 
     | 
    
         
             
                end
         
     | 
| 
       174 
174 
     | 
    
         | 
| 
       175 
     | 
    
         
            -
                 
     | 
| 
       176 
     | 
    
         
            -
                # string representation.
         
     | 
| 
       177 
     | 
    
         
            -
                def val_to_str(val)
         
     | 
| 
      
 175 
     | 
    
         
            +
                def value_to_binary_string(val)
         
     | 
| 
       178 
176 
     | 
    
         
             
                  set(val)
         
     | 
| 
       179 
     | 
    
         
            -
                  @struct. 
     | 
| 
      
 177 
     | 
    
         
            +
                  @struct.to_binary_s
         
     | 
| 
       180 
178 
     | 
    
         
             
                end
         
     | 
| 
       181 
179 
     | 
    
         | 
| 
       182 
180 
     | 
    
         
             
                ###########################################################################
         
     | 
| 
         @@ -196,4 +194,13 @@ module BinData 
     | 
|
| 
       196 
194 
     | 
    
         
             
                # To be implemented by subclasses
         
     | 
| 
       197 
195 
     | 
    
         
             
                ###########################################################################
         
     | 
| 
       198 
196 
     | 
    
         
             
              end
         
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
      
 198 
     | 
    
         
            +
              class SingleValue < Primitive
         
     | 
| 
      
 199 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 200 
     | 
    
         
            +
                  def inherited(subclass) #:nodoc:
         
     | 
| 
      
 201 
     | 
    
         
            +
                    warn "BinData::BasePrimitiveValue is deprecated.  Replacing with BinData::Primitive"
         
     | 
| 
      
 202 
     | 
    
         
            +
                    super
         
     | 
| 
      
 203 
     | 
    
         
            +
                  end
         
     | 
| 
      
 204 
     | 
    
         
            +
                end
         
     | 
| 
      
 205 
     | 
    
         
            +
              end
         
     | 
| 
       199 
206 
     | 
    
         
             
            end
         
     | 
| 
         @@ -1,18 +1,18 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'bindata/ 
     | 
| 
      
 1 
     | 
    
         
            +
            require 'bindata/registry'
         
     | 
| 
       2 
2 
     | 
    
         
             
            require 'bindata/struct'
         
     | 
| 
       3 
3 
     | 
    
         | 
| 
       4 
4 
     | 
    
         
             
            module BinData
         
     | 
| 
       5 
     | 
    
         
            -
              # A  
     | 
| 
      
 5 
     | 
    
         
            +
              # A Record is a declarative wrapper around Struct.
         
     | 
| 
       6 
6 
     | 
    
         
             
              #
         
     | 
| 
       7 
7 
     | 
    
         
             
              #    require 'bindata'
         
     | 
| 
       8 
8 
     | 
    
         
             
              #
         
     | 
| 
       9 
     | 
    
         
            -
              #    class Tuple < BinData:: 
     | 
| 
      
 9 
     | 
    
         
            +
              #    class Tuple < BinData::Record
         
     | 
| 
       10 
10 
     | 
    
         
             
              #      int8  :x
         
     | 
| 
       11 
11 
     | 
    
         
             
              #      int8  :y
         
     | 
| 
       12 
12 
     | 
    
         
             
              #      int8  :z
         
     | 
| 
       13 
13 
     | 
    
         
             
              #    end
         
     | 
| 
       14 
14 
     | 
    
         
             
              #
         
     | 
| 
       15 
     | 
    
         
            -
              #    class SomeDataType < BinData:: 
     | 
| 
      
 15 
     | 
    
         
            +
              #    class SomeDataType < BinData::Record
         
     | 
| 
       16 
16 
     | 
    
         
             
              #      hide 'a'
         
     | 
| 
       17 
17 
     | 
    
         
             
              #
         
     | 
| 
       18 
18 
     | 
    
         
             
              #      int32le :a
         
     | 
| 
         @@ -42,50 +42,36 @@ module BinData 
     | 
|
| 
       42 
42 
     | 
    
         
             
              # <tt>:endian</tt>::   Either :little or :big.  This specifies the default
         
     | 
| 
       43 
43 
     | 
    
         
             
              #                      endian of any numerics in this struct, or in any
         
     | 
| 
       44 
44 
     | 
    
         
             
              #                      nested data objects.
         
     | 
| 
       45 
     | 
    
         
            -
              class  
     | 
| 
      
 45 
     | 
    
         
            +
              class Record < BinData::Struct
         
     | 
| 
       46 
46 
     | 
    
         | 
| 
       47 
47 
     | 
    
         
             
                class << self
         
     | 
| 
       48 
     | 
    
         
            -
                  extend Parameters
         
     | 
| 
       49 
48 
     | 
    
         | 
| 
       50 
     | 
    
         
            -
                  # Register the names of all subclasses of this class.
         
     | 
| 
       51 
49 
     | 
    
         
             
                  def inherited(subclass) #:nodoc:
         
     | 
| 
      
 50 
     | 
    
         
            +
                    # Register the names of all subclasses of this class.
         
     | 
| 
       52 
51 
     | 
    
         
             
                    register(subclass.name, subclass)
         
     | 
| 
       53 
52 
     | 
    
         
             
                  end
         
     | 
| 
       54 
53 
     | 
    
         | 
| 
       55 
     | 
    
         
            -
                  # Can this data object self reference itself?
         
     | 
| 
       56 
54 
     | 
    
         
             
                  def recursive?
         
     | 
| 
      
 55 
     | 
    
         
            +
                    # A Record can self reference itself.
         
     | 
| 
       57 
56 
     | 
    
         
             
                    true
         
     | 
| 
       58 
57 
     | 
    
         
             
                  end
         
     | 
| 
       59 
58 
     | 
    
         | 
| 
       60 
     | 
    
         
            -
                  # Returns or sets the endianess of numerics used in this stucture.
         
     | 
| 
       61 
     | 
    
         
            -
                  # Endianess is applied to the fields of this structure.
         
     | 
| 
       62 
     | 
    
         
            -
                  # Valid values are :little and :big.
         
     | 
| 
       63 
59 
     | 
    
         
             
                  def endian(endian = nil)
         
     | 
| 
       64 
60 
     | 
    
         
             
                    @endian ||= nil
         
     | 
| 
       65 
61 
     | 
    
         
             
                    if [:little, :big].include?(endian)
         
     | 
| 
       66 
62 
     | 
    
         
             
                      @endian = endian
         
     | 
| 
       67 
63 
     | 
    
         
             
                    elsif endian != nil
         
     | 
| 
       68 
     | 
    
         
            -
                      raise ArgumentError, "unknown value for endian '#{endian}'"
         
     | 
| 
      
 64 
     | 
    
         
            +
                      raise ArgumentError, "unknown value for endian '#{endian}'", caller(1)
         
     | 
| 
       69 
65 
     | 
    
         
             
                    end
         
     | 
| 
       70 
66 
     | 
    
         
             
                    @endian
         
     | 
| 
       71 
67 
     | 
    
         
             
                  end
         
     | 
| 
       72 
68 
     | 
    
         | 
| 
       73 
     | 
    
         
            -
                  # Returns the names of any hidden fields in this struct.  Any given args
         
     | 
| 
       74 
     | 
    
         
            -
                  # are appended to the hidden list.
         
     | 
| 
       75 
69 
     | 
    
         
             
                  def hide(*args)
         
     | 
| 
       76 
     | 
    
         
            -
                    # note that fields are stored in an instance variable not a class var
         
     | 
| 
       77 
70 
     | 
    
         
             
                    @hide ||= []
         
     | 
| 
       78 
71 
     | 
    
         
             
                    @hide.concat(args.collect { |name| name.to_s })
         
     | 
| 
       79 
72 
     | 
    
         
             
                    @hide
         
     | 
| 
       80 
73 
     | 
    
         
             
                  end
         
     | 
| 
       81 
74 
     | 
    
         | 
| 
       82 
     | 
    
         
            -
                  # Returns all stored fields.
         
     | 
| 
       83 
     | 
    
         
            -
                  # Should only be called by #sanitize_parameters
         
     | 
| 
       84 
     | 
    
         
            -
                  def fields
         
     | 
| 
       85 
     | 
    
         
            -
                    @fields ||= []
         
     | 
| 
       86 
     | 
    
         
            -
                  end
         
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
       88 
     | 
    
         
            -
                  # Used to define fields for this structure.
         
     | 
| 
       89 
75 
     | 
    
         
             
                  def method_missing(symbol, *args)
         
     | 
| 
       90 
76 
     | 
    
         
             
                    name, params = args
         
     | 
| 
       91 
77 
     | 
    
         | 
| 
         @@ -93,78 +79,74 @@ module BinData 
     | 
|
| 
       93 
79 
     | 
    
         
             
                    name = name.to_s
         
     | 
| 
       94 
80 
     | 
    
         
             
                    params ||= {}
         
     | 
| 
       95 
81 
     | 
    
         | 
| 
       96 
     | 
    
         
            -
                     
     | 
| 
       97 
     | 
    
         
            -
                     
     | 
| 
      
 82 
     | 
    
         
            +
                    ensure_type_exists(type)
         
     | 
| 
      
 83 
     | 
    
         
            +
                    ensure_valid_name(name)
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                    append_field(type, name, params)
         
     | 
| 
      
 86 
     | 
    
         
            +
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                  def sanitize_parameters!(sanitizer, params)
         
     | 
| 
      
 89 
     | 
    
         
            +
                    merge_endian!(params)
         
     | 
| 
      
 90 
     | 
    
         
            +
                    merge_fields!(params)
         
     | 
| 
      
 91 
     | 
    
         
            +
                    merge_hide!(params)
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                    super(sanitizer, params)
         
     | 
| 
      
 94 
     | 
    
         
            +
                  end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                  #-------------
         
     | 
| 
      
 97 
     | 
    
         
            +
                  private
         
     | 
| 
       98 
98 
     | 
    
         | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
                    unless  
     | 
| 
       101 
     | 
    
         
            -
                      raise TypeError, "unknown type '#{type}' for #{self}", caller
         
     | 
| 
      
 99 
     | 
    
         
            +
                  def ensure_type_exists(type)
         
     | 
| 
      
 100 
     | 
    
         
            +
                    unless RegisteredClasses.is_registered?(type, endian)
         
     | 
| 
      
 101 
     | 
    
         
            +
                      raise TypeError, "unknown type '#{type}' for #{self}", caller(2)
         
     | 
| 
       102 
102 
     | 
    
         
             
                    end
         
     | 
| 
      
 103 
     | 
    
         
            +
                  end
         
     | 
| 
       103 
104 
     | 
    
         | 
| 
       104 
     | 
    
         
            -
             
     | 
| 
      
 105 
     | 
    
         
            +
                  def ensure_valid_name(name)
         
     | 
| 
      
 106 
     | 
    
         
            +
                    @fields ||= []
         
     | 
| 
       105 
107 
     | 
    
         
             
                    @fields.each do |t, n, p|
         
     | 
| 
       106 
108 
     | 
    
         
             
                      if n == name
         
     | 
| 
       107 
     | 
    
         
            -
                        raise SyntaxError, "duplicate field '#{name}' in #{self}", caller
         
     | 
| 
      
 109 
     | 
    
         
            +
                        raise SyntaxError, "duplicate field '#{name}' in #{self}", caller(4)
         
     | 
| 
       108 
110 
     | 
    
         
             
                      end
         
     | 
| 
       109 
111 
     | 
    
         
             
                    end
         
     | 
| 
       110 
     | 
    
         
            -
             
     | 
| 
       111 
     | 
    
         
            -
                    # check that name doesn't shadow an existing method
         
     | 
| 
       112 
112 
     | 
    
         
             
                    if self.instance_methods.include?(name)
         
     | 
| 
       113 
113 
     | 
    
         
             
                      raise NameError.new("", name),
         
     | 
| 
       114 
     | 
    
         
            -
                            "field '#{name}' shadows an existing method", caller
         
     | 
| 
      
 114 
     | 
    
         
            +
                            "field '#{name}' shadows an existing method", caller(2)
         
     | 
| 
       115 
115 
     | 
    
         
             
                    end
         
     | 
| 
       116 
     | 
    
         
            -
             
     | 
| 
       117 
     | 
    
         
            -
                    # check that name isn't reserved
         
     | 
| 
       118 
116 
     | 
    
         
             
                    if self::RESERVED.include?(name)
         
     | 
| 
       119 
117 
     | 
    
         
             
                      raise NameError.new("", name),
         
     | 
| 
       120 
     | 
    
         
            -
                            "field '#{name}' is a reserved name", caller
         
     | 
| 
      
 118 
     | 
    
         
            +
                            "field '#{name}' is a reserved name", caller(2)
         
     | 
| 
       121 
119 
     | 
    
         
             
                    end
         
     | 
| 
      
 120 
     | 
    
         
            +
                  end
         
     | 
| 
       122 
121 
     | 
    
         | 
| 
       123 
     | 
    
         
            -
             
     | 
| 
       124 
     | 
    
         
            -
                     
     | 
| 
      
 122 
     | 
    
         
            +
                  def append_field(type, name, params)
         
     | 
| 
      
 123 
     | 
    
         
            +
                    @fields ||= []
         
     | 
| 
       125 
124 
     | 
    
         
             
                    @fields.push([type, name, params])
         
     | 
| 
       126 
125 
     | 
    
         
             
                  end
         
     | 
| 
       127 
126 
     | 
    
         | 
| 
       128 
     | 
    
         
            -
                   
     | 
| 
       129 
     | 
    
         
            -
                  def sanitize_parameters!(sanitizer, params)
         
     | 
| 
      
 127 
     | 
    
         
            +
                  def merge_endian!(params)
         
     | 
| 
       130 
128 
     | 
    
         
             
                    endian = params[:endian] || self.endian
         
     | 
| 
       131 
     | 
    
         
            -
                    fields = params[:fields] || self.fields
         
     | 
| 
       132 
     | 
    
         
            -
                    hide   = params[:hide]   || self.hide
         
     | 
| 
       133 
     | 
    
         
            -
             
     | 
| 
       134 
129 
     | 
    
         
             
                    params[:endian] = endian unless endian.nil?
         
     | 
| 
       135 
     | 
    
         
            -
                    params[:fields] = fields
         
     | 
| 
       136 
     | 
    
         
            -
                    params[:hide]   = hide
         
     | 
| 
       137 
     | 
    
         
            -
             
     | 
| 
       138 
     | 
    
         
            -
                    # add default parameters
         
     | 
| 
       139 
     | 
    
         
            -
                    default_parameters.each do |k,v|
         
     | 
| 
       140 
     | 
    
         
            -
                      params[k] = v unless params.has_key?(k)
         
     | 
| 
       141 
     | 
    
         
            -
                    end
         
     | 
| 
       142 
     | 
    
         
            -
             
     | 
| 
       143 
     | 
    
         
            -
                    # ensure mandatory parameters exist
         
     | 
| 
       144 
     | 
    
         
            -
                    mandatory_parameters.each do |prm|
         
     | 
| 
       145 
     | 
    
         
            -
                      if not params.has_key?(prm)
         
     | 
| 
       146 
     | 
    
         
            -
                        raise ArgumentError, "parameter ':#{prm}' must be specified " +
         
     | 
| 
       147 
     | 
    
         
            -
                                             "in #{self}"
         
     | 
| 
       148 
     | 
    
         
            -
                      end
         
     | 
| 
       149 
     | 
    
         
            -
                    end
         
     | 
| 
       150 
     | 
    
         
            -
             
     | 
| 
       151 
     | 
    
         
            -
                    super(sanitizer, params)
         
     | 
| 
       152 
130 
     | 
    
         
             
                  end
         
     | 
| 
       153 
131 
     | 
    
         | 
| 
       154 
     | 
    
         
            -
                   
     | 
| 
       155 
     | 
    
         
            -
             
     | 
| 
       156 
     | 
    
         
            -
             
     | 
| 
       157 
     | 
    
         
            -
             
     | 
| 
       158 
     | 
    
         
            -
                    args.each { |arg| array << arg.to_sym }
         
     | 
| 
       159 
     | 
    
         
            -
                    array.uniq!
         
     | 
| 
      
 132 
     | 
    
         
            +
                  def merge_fields!(params)
         
     | 
| 
      
 133 
     | 
    
         
            +
                    @fields ||= []
         
     | 
| 
      
 134 
     | 
    
         
            +
                    fields = params[:fields] || @fields || []
         
     | 
| 
      
 135 
     | 
    
         
            +
                    params[:fields] = fields
         
     | 
| 
       160 
136 
     | 
    
         
             
                  end
         
     | 
| 
       161 
137 
     | 
    
         | 
| 
       162 
     | 
    
         
            -
                   
     | 
| 
       163 
     | 
    
         
            -
             
     | 
| 
      
 138 
     | 
    
         
            +
                  def merge_hide!(params)
         
     | 
| 
      
 139 
     | 
    
         
            +
                    hide = params[:hide] || self.hide
         
     | 
| 
      
 140 
     | 
    
         
            +
                    params[:hide] = hide
         
     | 
| 
      
 141 
     | 
    
         
            +
                  end
         
     | 
| 
      
 142 
     | 
    
         
            +
                end
         
     | 
| 
      
 143 
     | 
    
         
            +
              end
         
     | 
| 
       164 
144 
     | 
    
         | 
| 
       165 
     | 
    
         
            -
             
     | 
| 
       166 
     | 
    
         
            -
             
     | 
| 
       167 
     | 
    
         
            -
             
     | 
| 
      
 145 
     | 
    
         
            +
              class MultiValue < Record
         
     | 
| 
      
 146 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 147 
     | 
    
         
            +
                  def inherited(subclass) #:nodoc:
         
     | 
| 
      
 148 
     | 
    
         
            +
                    warn "BinData::MultiValue is deprecated.  Replacing with BinData::Record"
         
     | 
| 
      
 149 
     | 
    
         
            +
                    super
         
     | 
| 
       168 
150 
     | 
    
         
             
                  end
         
     | 
| 
       169 
151 
     | 
    
         
             
                end
         
     | 
| 
       170 
152 
     | 
    
         
             
              end
         
     | 
    
        data/lib/bindata/registry.rb
    CHANGED
    
    | 
         @@ -1,14 +1,34 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'singleton'
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            module BinData
         
     | 
| 
       4 
2 
     | 
    
         
             
              # This registry contains a register of name -> class mappings.
         
     | 
| 
      
 3 
     | 
    
         
            +
              #
         
     | 
| 
      
 4 
     | 
    
         
            +
              # Names are stored in under_score_style, not camelCase.
         
     | 
| 
       5 
5 
     | 
    
         
             
              class Registry
         
     | 
| 
       6 
     | 
    
         
            -
                include Singleton
         
     | 
| 
       7 
6 
     | 
    
         | 
| 
       8 
7 
     | 
    
         
             
                def initialize
         
     | 
| 
       9 
8 
     | 
    
         
             
                  @registry = {}
         
     | 
| 
       10 
9 
     | 
    
         
             
                end
         
     | 
| 
       11 
10 
     | 
    
         | 
| 
      
 11 
     | 
    
         
            +
                def register(name, class_to_register)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  formatted_name = underscore_name(name)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  warn_if_name_is_already_registered(formatted_name, class_to_register)
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  @registry[formatted_name] = class_to_register
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                def lookup(name, endian = nil)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  key = underscore_name(name.to_s)
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  result = @registry[key]
         
     | 
| 
      
 22 
     | 
    
         
            +
                  if result.nil?
         
     | 
| 
      
 23 
     | 
    
         
            +
                    result = @registry[merge_key_and_endian(key, endian)]
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  result
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def is_registered?(name, endian = nil)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  lookup(name, endian) != nil
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
       12 
32 
     | 
    
         
             
                # Convert camelCase +name+ to underscore style.
         
     | 
| 
       13 
33 
     | 
    
         
             
                def underscore_name(name)
         
     | 
| 
       14 
34 
     | 
    
         
             
                  name.to_s.sub(/.*::/, "").
         
     | 
| 
         @@ -18,25 +38,37 @@ module BinData 
     | 
|
| 
       18 
38 
     | 
    
         
             
                            downcase
         
     | 
| 
       19 
39 
     | 
    
         
             
                end
         
     | 
| 
       20 
40 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
                 
     | 
| 
       22 
     | 
    
         
            -
                 
     | 
| 
       23 
     | 
    
         
            -
                # Returns the converted name
         
     | 
| 
       24 
     | 
    
         
            -
                def register(name, klass)
         
     | 
| 
       25 
     | 
    
         
            -
                  # convert camelCase name to underscore style
         
     | 
| 
       26 
     | 
    
         
            -
                  key = underscore_name(name)
         
     | 
| 
      
 41 
     | 
    
         
            +
                #---------------
         
     | 
| 
      
 42 
     | 
    
         
            +
                private
         
     | 
| 
       27 
43 
     | 
    
         | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
                   
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
      
 44 
     | 
    
         
            +
                def merge_key_and_endian(key, endian)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  result = key
         
     | 
| 
      
 46 
     | 
    
         
            +
                  if endian != nil
         
     | 
| 
      
 47 
     | 
    
         
            +
                    if /^u?int\d+$/ =~ key
         
     | 
| 
      
 48 
     | 
    
         
            +
                      result = key + ((endian == :little) ? "le" : "be")
         
     | 
| 
      
 49 
     | 
    
         
            +
                    elsif /^(float|double)$/ =~ key
         
     | 
| 
      
 50 
     | 
    
         
            +
                      result = key + ((endian == :little) ? "_le" : "_be")
         
     | 
| 
      
 51 
     | 
    
         
            +
                    end
         
     | 
| 
       31 
52 
     | 
    
         
             
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
                  result
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
       32 
55 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
                   
     | 
| 
      
 56 
     | 
    
         
            +
                def warn_if_name_is_already_registered(name, class_to_register)
         
     | 
| 
      
 57 
     | 
    
         
            +
                  if $VERBOSE and @registry.has_key?(name)
         
     | 
| 
      
 58 
     | 
    
         
            +
                    prev_class = @registry[name]
         
     | 
| 
      
 59 
     | 
    
         
            +
                    warn "warning: replacing registered class #{prev_class} " +
         
     | 
| 
      
 60 
     | 
    
         
            +
                         "with #{class_to_register}"
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
       35 
62 
     | 
    
         
             
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
              end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
              # A singleton registry of all registered classes.
         
     | 
| 
      
 66 
     | 
    
         
            +
              RegisteredClasses = Registry.new
         
     | 
| 
       36 
67 
     | 
    
         | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
                def  
     | 
| 
       39 
     | 
    
         
            -
                   
     | 
| 
      
 68 
     | 
    
         
            +
              class Registry
         
     | 
| 
      
 69 
     | 
    
         
            +
                def Registry.instance
         
     | 
| 
      
 70 
     | 
    
         
            +
                  warn "'Registry.instance' is deprecated.  Replacing with 'RegisteredClasses'"
         
     | 
| 
      
 71 
     | 
    
         
            +
                  RegisteredClasses
         
     | 
| 
       40 
72 
     | 
    
         
             
                end
         
     | 
| 
       41 
73 
     | 
    
         
             
              end
         
     | 
| 
       42 
74 
     | 
    
         
             
            end
         
     |