jbangert-bindata 1.5.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.
Files changed (71) hide show
  1. data/.gitignore +1 -0
  2. data/BSDL +22 -0
  3. data/COPYING +52 -0
  4. data/ChangeLog.rdoc +204 -0
  5. data/Gemfile +2 -0
  6. data/INSTALL +11 -0
  7. data/NEWS.rdoc +164 -0
  8. data/README.md +54 -0
  9. data/Rakefile +13 -0
  10. data/bindata.gemspec +31 -0
  11. data/doc/manual.haml +407 -0
  12. data/doc/manual.md +1649 -0
  13. data/examples/NBT.txt +149 -0
  14. data/examples/gzip.rb +161 -0
  15. data/examples/ip_address.rb +22 -0
  16. data/examples/list.rb +124 -0
  17. data/examples/nbt.rb +178 -0
  18. data/lib/bindata.rb +33 -0
  19. data/lib/bindata/alignment.rb +83 -0
  20. data/lib/bindata/array.rb +335 -0
  21. data/lib/bindata/base.rb +388 -0
  22. data/lib/bindata/base_primitive.rb +214 -0
  23. data/lib/bindata/bits.rb +87 -0
  24. data/lib/bindata/choice.rb +216 -0
  25. data/lib/bindata/count_bytes_remaining.rb +35 -0
  26. data/lib/bindata/deprecated.rb +50 -0
  27. data/lib/bindata/dsl.rb +312 -0
  28. data/lib/bindata/float.rb +80 -0
  29. data/lib/bindata/int.rb +184 -0
  30. data/lib/bindata/io.rb +274 -0
  31. data/lib/bindata/lazy.rb +105 -0
  32. data/lib/bindata/offset.rb +91 -0
  33. data/lib/bindata/params.rb +135 -0
  34. data/lib/bindata/primitive.rb +135 -0
  35. data/lib/bindata/record.rb +110 -0
  36. data/lib/bindata/registry.rb +92 -0
  37. data/lib/bindata/rest.rb +35 -0
  38. data/lib/bindata/sanitize.rb +290 -0
  39. data/lib/bindata/skip.rb +48 -0
  40. data/lib/bindata/string.rb +145 -0
  41. data/lib/bindata/stringz.rb +96 -0
  42. data/lib/bindata/struct.rb +388 -0
  43. data/lib/bindata/trace.rb +94 -0
  44. data/lib/bindata/version.rb +3 -0
  45. data/setup.rb +1585 -0
  46. data/spec/alignment_spec.rb +61 -0
  47. data/spec/array_spec.rb +331 -0
  48. data/spec/base_primitive_spec.rb +238 -0
  49. data/spec/base_spec.rb +376 -0
  50. data/spec/bits_spec.rb +163 -0
  51. data/spec/choice_spec.rb +263 -0
  52. data/spec/count_bytes_remaining_spec.rb +38 -0
  53. data/spec/deprecated_spec.rb +31 -0
  54. data/spec/example.rb +21 -0
  55. data/spec/float_spec.rb +37 -0
  56. data/spec/int_spec.rb +216 -0
  57. data/spec/io_spec.rb +352 -0
  58. data/spec/lazy_spec.rb +217 -0
  59. data/spec/primitive_spec.rb +202 -0
  60. data/spec/record_spec.rb +530 -0
  61. data/spec/registry_spec.rb +108 -0
  62. data/spec/rest_spec.rb +26 -0
  63. data/spec/skip_spec.rb +27 -0
  64. data/spec/spec_common.rb +58 -0
  65. data/spec/string_spec.rb +300 -0
  66. data/spec/stringz_spec.rb +118 -0
  67. data/spec/struct_spec.rb +350 -0
  68. data/spec/system_spec.rb +380 -0
  69. data/tasks/manual.rake +36 -0
  70. data/tasks/rspec.rake +17 -0
  71. metadata +208 -0
@@ -0,0 +1,87 @@
1
+ require 'bindata/base_primitive'
2
+
3
+ module BinData
4
+ # Defines a number of classes that contain a bit based integer.
5
+ # The integer is defined by endian and number of bits.
6
+
7
+ module BitField #:nodoc: all
8
+ class << self
9
+ def define_class(nbits, endian)
10
+ name = "Bit#{nbits}"
11
+ name << "le" if endian == :little
12
+ unless BinData.const_defined?(name)
13
+ BinData.module_eval <<-END
14
+ class #{name} < BinData::BasePrimitive
15
+ BitField.define_methods(self, #{nbits}, :#{endian})
16
+ end
17
+ END
18
+ end
19
+
20
+ BinData.const_get(name)
21
+ end
22
+
23
+ def define_methods(bit_class, nbits, endian)
24
+ bit_class.module_eval <<-END
25
+ def assign(val)
26
+ #{create_clamp_code(nbits)}
27
+ super(val)
28
+ end
29
+
30
+ def do_write(io)
31
+ io.writebits(_value, #{nbits}, :#{endian})
32
+ end
33
+
34
+ def do_num_bytes
35
+ #{nbits / 8.0}
36
+ end
37
+
38
+ #---------------
39
+ private
40
+
41
+ def read_and_return_value(io)
42
+ io.readbits(#{nbits}, :#{endian})
43
+ end
44
+
45
+ def sensible_default
46
+ 0
47
+ end
48
+ END
49
+ end
50
+
51
+ def create_clamp_code(nbits)
52
+ min = 0
53
+ max = (1 << nbits) - 1
54
+ clamp = "(val < #{min}) ? #{min} : (val > #{max}) ? #{max} : val"
55
+
56
+ if nbits == 1
57
+ # allow single bits to be used as booleans
58
+ clamp = "(val == true) ? 1 : (not val) ? 0 : #{clamp}"
59
+ end
60
+
61
+ "val = #{clamp}"
62
+ end
63
+ end
64
+ end
65
+
66
+ # Create classes on demand
67
+ class << self
68
+ alias_method :const_missing_without_bits, :const_missing
69
+ def const_missing_with_bits(name)
70
+ name = name.to_s
71
+ mappings = {
72
+ /^Bit(\d+)$/ => :big,
73
+ /^Bit(\d+)le$/ => :little
74
+ }
75
+
76
+ mappings.each_pair do |regex, endian|
77
+ if regex =~ name
78
+ nbits = $1.to_i
79
+ return BitField.define_class(nbits, endian)
80
+ end
81
+ end
82
+
83
+ const_missing_without_bits(name)
84
+ end
85
+ alias_method :const_missing, :const_missing_with_bits
86
+ end
87
+ end
@@ -0,0 +1,216 @@
1
+ require 'bindata/base'
2
+ require 'bindata/dsl'
3
+
4
+ module BinData
5
+ # A Choice is a collection of data objects of which only one is active
6
+ # at any particular time. Method calls will be delegated to the active
7
+ # choice.
8
+ #
9
+ # require 'bindata'
10
+ #
11
+ # type1 = [:string, {:value => "Type1"}]
12
+ # type2 = [:string, {:value => "Type2"}]
13
+ #
14
+ # choices = {5 => type1, 17 => type2}
15
+ # a = BinData::Choice.new(:choices => choices, :selection => 5)
16
+ # a # => "Type1"
17
+ #
18
+ # choices = [ type1, type2 ]
19
+ # a = BinData::Choice.new(:choices => choices, :selection => 1)
20
+ # a # => "Type2"
21
+ #
22
+ # choices = [ nil, nil, nil, type1, nil, type2 ]
23
+ # a = BinData::Choice.new(:choices => choices, :selection => 3)
24
+ # a # => "Type1"
25
+ #
26
+ #
27
+ # Chooser = Struct.new(:choice)
28
+ # mychoice = Chooser.new
29
+ # mychoice.choice = 'big'
30
+ #
31
+ # choices = {'big' => :uint16be, 'little' => :uint16le}
32
+ # a = BinData::Choice.new(:choices => choices, :copy_on_change => true,
33
+ # :selection => lambda { mychoice.choice })
34
+ # a.assign(256)
35
+ # a.to_binary_s #=> "\001\000"
36
+ #
37
+ # mychoice.choice = 'little'
38
+ # a.to_binary_s #=> "\000\001"
39
+ #
40
+ # == Parameters
41
+ #
42
+ # Parameters may be provided at initialisation to control the behaviour of
43
+ # an object. These params are:
44
+ #
45
+ # <tt>:choices</tt>:: Either an array or a hash specifying the possible
46
+ # data objects. The format of the
47
+ # array/hash.values is a list of symbols
48
+ # representing the data object type. If a choice
49
+ # is to have params passed to it, then it should
50
+ # be provided as [type_symbol, hash_params]. An
51
+ # implementation constraint is that the hash may
52
+ # not contain symbols as keys, with the exception
53
+ # of :default. :default is to be used when then
54
+ # :selection does not exist in the :choices hash.
55
+ # <tt>:selection</tt>:: An index/key into the :choices array/hash which
56
+ # specifies the currently active choice.
57
+ # <tt>:copy_on_change</tt>:: If set to true, copy the value of the previous
58
+ # selection to the current selection whenever the
59
+ # selection changes. Default is false.
60
+ class Choice < BinData::Base
61
+ include DSLMixin
62
+
63
+ dsl_parser :choice
64
+
65
+ mandatory_parameters :choices, :selection
66
+ optional_parameter :copy_on_change
67
+
68
+ class << self
69
+
70
+ def sanitize_parameters!(params) #:nodoc:
71
+ params.merge!(dsl_params)
72
+
73
+ if params.needs_sanitizing?(:choices)
74
+ choices = choices_as_hash(params[:choices])
75
+ ensure_valid_keys(choices)
76
+ params[:choices] = params.create_sanitized_choices(choices)
77
+ end
78
+ end
79
+
80
+ #-------------
81
+ private
82
+
83
+ def choices_as_hash(choices)
84
+ if choices.respond_to?(:to_ary)
85
+ key_array_by_index(choices.to_ary)
86
+ else
87
+ choices
88
+ end
89
+ end
90
+
91
+ def key_array_by_index(array)
92
+ result = {}
93
+ array.each_with_index do |el, i|
94
+ result[i] = el unless el.nil?
95
+ end
96
+ result
97
+ end
98
+
99
+ def ensure_valid_keys(choices)
100
+ if choices.has_key?(nil)
101
+ raise ArgumentError, ":choices hash may not have nil key"
102
+ end
103
+ if choices.keys.detect { |key| key.is_a?(Symbol) and key != :default }
104
+ raise ArgumentError, ":choices hash may not have symbols for keys"
105
+ end
106
+ end
107
+ end
108
+
109
+ def initialize_shared_instance
110
+ if eval_parameter(:copy_on_change) == true
111
+ class << self
112
+ alias_method :hook_after_current_choice, :copy_previous_value
113
+ end
114
+ end
115
+ end
116
+
117
+ def initialize_instance
118
+ @choices = {}
119
+ @last_selection = nil
120
+ end
121
+
122
+ # A convenience method that returns the current selection.
123
+ def selection
124
+ eval_parameter(:selection)
125
+ end
126
+
127
+ def clear #:nodoc:
128
+ initialize_instance
129
+ end
130
+
131
+ def clear? #:nodoc:
132
+ current_choice.clear?
133
+ end
134
+
135
+ def assign(val)
136
+ current_choice.assign(val)
137
+ end
138
+
139
+ def snapshot
140
+ current_choice.snapshot
141
+ end
142
+
143
+ def respond_to?(symbol, include_private = false) #:nodoc:
144
+ current_choice.respond_to?(symbol, include_private) || super
145
+ end
146
+
147
+ def safe_respond_to?(symbol, include_private = false) #:nodoc:
148
+ orig_respond_to?(symbol, include_private)
149
+ end
150
+
151
+ def method_missing(symbol, *args, &block) #:nodoc:
152
+ current_choice.__send__(symbol, *args, &block)
153
+ end
154
+
155
+ def do_read(io) #:nodoc:
156
+ hook_before_do_read
157
+ current_choice.do_read(io)
158
+ end
159
+
160
+ def do_write(io) #:nodoc:
161
+ current_choice.do_write(io)
162
+ end
163
+
164
+ def do_num_bytes #:nodoc:
165
+ current_choice.do_num_bytes
166
+ end
167
+
168
+ #---------------
169
+ private
170
+
171
+ def hook_before_do_read; end
172
+ def hook_after_current_choice(*args); end
173
+
174
+ def current_choice
175
+ selection = eval_parameter(:selection)
176
+ if selection.nil?
177
+ raise IndexError, ":selection returned nil for #{debug_name}"
178
+ end
179
+
180
+ obj = get_or_instantiate_choice(selection)
181
+ hook_after_current_choice(selection, obj)
182
+
183
+ obj
184
+ end
185
+
186
+ def get_or_instantiate_choice(selection)
187
+ @choices[selection] ||= instantiate_choice(selection)
188
+ end
189
+
190
+ def instantiate_choice(selection)
191
+ prototype = get_parameter(:choices)[selection]
192
+ if prototype.nil?
193
+ raise IndexError, "selection '#{selection}' does not exist in :choices for #{debug_name}"
194
+ end
195
+ prototype.instantiate(nil, self)
196
+ end
197
+
198
+ def copy_previous_value(selection, obj)
199
+ prev = get_previous_choice(selection)
200
+ obj.assign(prev) unless prev.nil?
201
+ remember_current_selection(selection)
202
+ end
203
+
204
+ def get_previous_choice(selection)
205
+ if selection != @last_selection and @last_selection != nil
206
+ @choices[@last_selection]
207
+ else
208
+ nil
209
+ end
210
+ end
211
+
212
+ def remember_current_selection(selection)
213
+ @last_selection = selection
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,35 @@
1
+ require "bindata/base_primitive"
2
+
3
+ module BinData
4
+ # Counts the number of bytes remaining in the input stream from the current
5
+ # position to the end of the stream. This only makes sense for seekable
6
+ # streams.
7
+ #
8
+ # require 'bindata'
9
+ #
10
+ # class A < BinData::Record
11
+ # count_bytes_remaining :bytes_remaining
12
+ # string :all_data, :read_length => :bytes_remaining
13
+ # end
14
+ #
15
+ # obj = A.read("abcdefghij")
16
+ # obj.all_data #=> "abcdefghij"
17
+ #
18
+ class CountBytesRemaining < BinData::BasePrimitive
19
+
20
+ #---------------
21
+ private
22
+
23
+ def value_to_binary_string(val)
24
+ ""
25
+ end
26
+
27
+ def read_and_return_value(io)
28
+ io.num_bytes_remaining
29
+ end
30
+
31
+ def sensible_default
32
+ 0
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,50 @@
1
+ # Implement Kernel#instance_exec for Ruby 1.8.6 and below
2
+ unless Object.respond_to? :instance_exec
3
+ module Kernel
4
+ # Taken from http://eigenclass.org/hiki/instance_exec
5
+ def instance_exec(*args, &block)
6
+ mname = "__instance_exec_#{Thread.current.object_id.abs}_#{object_id.abs}"
7
+ Object.class_eval{ define_method(mname, &block) }
8
+ begin
9
+ ret = send(mname, *args)
10
+ ensure
11
+ Object.class_eval{ undef_method(mname) } rescue nil
12
+ end
13
+ ret
14
+ end
15
+ end
16
+ end
17
+
18
+ module BinData
19
+ class Base
20
+
21
+ # Don't override initialize. If you are defining a new kind of datatype
22
+ # (list, array, choice etc) then put your initialization code in
23
+ # #initialize_instance. This is because BinData objects can be initialized
24
+ # as prototypes and your initialization code may not be called.
25
+ #
26
+ # If you're subclassing BinData::Record, you are definitely doing the wrong
27
+ # thing. Read the documentation on how to use BinData.
28
+ # http://bindata.rubyforge.org/manual.html#records
29
+ alias_method :initialize_without_warning, :initialize
30
+ def initialize_with_warning(*args)
31
+ owner = method(:initialize).owner
32
+ if owner != BinData::Base
33
+ msg = "Don't override #initialize on #{owner}."
34
+ if %w(BinData::Base BinData::BasePrimitive).include? self.class.superclass.name
35
+ msg += "\nrename #initialize to #initialize_instance."
36
+ end
37
+ fail msg
38
+ end
39
+ initialize_without_warning(*args)
40
+ end
41
+ alias_method :initialize, :initialize_with_warning
42
+
43
+ def initialize_instance(*args)
44
+ unless args.empty?
45
+ fail "#{caller[0]} remove the call to super in #initialize_instance"
46
+ end
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,312 @@
1
+ module BinData
2
+ module DSLMixin
3
+ def self.included(base) #:nodoc:
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+
9
+ def dsl_parser(parser_type = nil)
10
+ unless defined? @dsl_parser
11
+ parser_type = superclass.dsl_parser.parser_type if parser_type.nil?
12
+ @dsl_parser = DSLParser.new(self, parser_type)
13
+ end
14
+ @dsl_parser
15
+ end
16
+
17
+ def method_missing(symbol, *args, &block) #:nodoc:
18
+ dsl_parser.__send__(symbol, *args, &block)
19
+ end
20
+
21
+ # Assert object is not an array or string.
22
+ def to_ary; nil; end
23
+ def to_str; nil; end
24
+ end
25
+
26
+ # A DSLParser parses and accumulates field definitions of the form
27
+ #
28
+ # type name, params
29
+ #
30
+ # where:
31
+ # * +type+ is the under_scored name of a registered type
32
+ # * +name+ is the (possible optional) name of the field
33
+ # * +params+ is a hash containing any parameters
34
+ #
35
+ class DSLParser
36
+ def initialize(the_class, parser_type)
37
+ @the_class = the_class
38
+ @parser_type = parser_type
39
+ @endian = parent_attribute(:endian, nil)
40
+ end
41
+
42
+ attr_reader :parser_type
43
+
44
+ def endian(endian = nil)
45
+ if endian.nil?
46
+ @endian
47
+ elsif endian == :big or endian == :little
48
+ @endian = endian
49
+ else
50
+ dsl_raise ArgumentError, "unknown value for endian '#{endian}'"
51
+ end
52
+ end
53
+
54
+ def hide(*args)
55
+ if option?(:hidden_fields)
56
+ hidden = args.collect do |name|
57
+ unless Symbol === name
58
+ warn "Hidden field '#{name}' should be provided as a symbol. Using strings is deprecated"
59
+ end
60
+ name.to_sym
61
+ end
62
+
63
+ unless defined? @hide
64
+ @hide = parent_attribute(:hide, []).dup
65
+ end
66
+
67
+ @hide.concat(hidden.compact)
68
+ @hide
69
+ end
70
+ end
71
+
72
+ def fields
73
+ unless defined? @fields
74
+ fields = parent_attribute(:fields, nil)
75
+ @fields = SanitizedFields.new(endian)
76
+ @fields.copy_fields(fields) if fields
77
+ end
78
+
79
+ @fields
80
+ end
81
+
82
+ def dsl_params
83
+ case @parser_type
84
+ when :struct
85
+ to_struct_params
86
+ when :array
87
+ to_array_params
88
+ when :choice
89
+ to_choice_params
90
+ when :primitive
91
+ to_struct_params
92
+ else
93
+ raise "unknown parser type #{@parser_type}"
94
+ end
95
+ end
96
+
97
+ def method_missing(symbol, *args, &block) #:nodoc:
98
+ type = symbol
99
+ name = name_from_field_declaration(args)
100
+ params = params_from_field_declaration(type, args, &block)
101
+
102
+ append_field(type, name, params)
103
+ end
104
+
105
+ #-------------
106
+ private
107
+
108
+ def option?(opt)
109
+ options.include?(opt)
110
+ end
111
+
112
+ def options
113
+ case @parser_type
114
+ when :struct
115
+ [:multiple_fields, :optional_fieldnames, :hidden_fields]
116
+ when :array
117
+ [:multiple_fields, :optional_fieldnames]
118
+ when :choice
119
+ [:multiple_fields, :all_or_none_fieldnames, :fieldnames_are_values]
120
+ when :primitive
121
+ [:multiple_fields, :optional_fieldnames]
122
+ else
123
+ raise "unknown parser type #{parser_type}"
124
+ end
125
+ end
126
+
127
+ def parent_attribute(attr, default = nil)
128
+ parent = @the_class.superclass.respond_to?(:dsl_parser) ? @the_class.superclass.dsl_parser : nil
129
+ if parent and parent.respond_to?(attr)
130
+ parent.send(attr)
131
+ else
132
+ default
133
+ end
134
+ end
135
+
136
+ def name_from_field_declaration(args)
137
+ name, params = args
138
+ if name == "" or name.is_a?(Hash)
139
+ nil
140
+ else
141
+ name
142
+ end
143
+ end
144
+
145
+ def params_from_field_declaration(type, args, &block)
146
+ params = params_from_args(args)
147
+
148
+ if block_given?
149
+ params.merge(params_from_block(type, &block))
150
+ else
151
+ params
152
+ end
153
+ end
154
+
155
+ def params_from_args(args)
156
+ name, params = args
157
+ params = name if name.is_a?(Hash)
158
+
159
+ params || {}
160
+ end
161
+
162
+ def params_from_block(type, &block)
163
+ bindata_classes = {
164
+ :array => BinData::Array,
165
+ :choice => BinData::Choice,
166
+ :struct => BinData::Struct
167
+ }
168
+
169
+ if bindata_classes.include?(type)
170
+ parser = DSLParser.new(bindata_classes[type], type)
171
+ parser.endian(endian)
172
+ parser.instance_eval(&block)
173
+
174
+ parser.dsl_params
175
+ else
176
+ {}
177
+ end
178
+ end
179
+
180
+ def append_field(type, name, params)
181
+ ensure_valid_field(name)
182
+
183
+ fields.add_field(type, name, params)
184
+ rescue ArgumentError => err
185
+ dsl_raise ArgumentError, err.message
186
+ rescue UnRegisteredTypeError => err
187
+ dsl_raise TypeError, "unknown type '#{err.message}'"
188
+ end
189
+
190
+ def ensure_valid_field(field_name)
191
+ if too_many_fields?
192
+ dsl_raise SyntaxError, "attempting to wrap more than one type"
193
+ end
194
+
195
+ if must_not_have_a_name_failed?(field_name)
196
+ dsl_raise SyntaxError, "field must not have a name"
197
+ end
198
+
199
+ if all_or_none_names_failed?(field_name)
200
+ dsl_raise SyntaxError, "fields must either all have names, or none must have names"
201
+ end
202
+
203
+ if must_have_a_name_failed?(field_name)
204
+ dsl_raise SyntaxError, "field must have a name"
205
+ end
206
+
207
+ ensure_valid_name(field_name)
208
+ end
209
+
210
+ def ensure_valid_name(name)
211
+ if name and not option?(:fieldnames_are_values)
212
+ if malformed_name?(name)
213
+ dsl_raise NameError.new("", name), "field '#{name}' is an illegal fieldname"
214
+ end
215
+
216
+ if duplicate_name?(name)
217
+ dsl_raise SyntaxError, "duplicate field '#{name}'"
218
+ end
219
+
220
+ if name_shadows_method?(name)
221
+ dsl_raise NameError.new("", name), "field '#{name}' shadows an existing method"
222
+ end
223
+
224
+ if name_is_reserved?(name)
225
+ dsl_raise NameError.new("", name), "field '#{name}' is a reserved name"
226
+ end
227
+ end
228
+ end
229
+
230
+ def too_many_fields?
231
+ option?(:only_one_field) and not fields.empty?
232
+ end
233
+
234
+ def must_not_have_a_name_failed?(name)
235
+ option?(:no_fieldnames) and name != nil
236
+ end
237
+
238
+ def must_have_a_name_failed?(name)
239
+ option?(:mandatory_fieldnames) and name.nil?
240
+ end
241
+
242
+ def all_or_none_names_failed?(name)
243
+ if option?(:all_or_none_fieldnames) and not fields.empty?
244
+ all_names_blank = fields.all_field_names_blank?
245
+ no_names_blank = fields.no_field_names_blank?
246
+
247
+ (name != nil and all_names_blank) or (name == nil and no_names_blank)
248
+ else
249
+ false
250
+ end
251
+ end
252
+
253
+ def malformed_name?(name)
254
+ /^[a-z_]\w*$/ !~ name.to_s
255
+ end
256
+
257
+ def duplicate_name?(name)
258
+ fields.has_field_name?(name)
259
+ end
260
+
261
+ def name_shadows_method?(name)
262
+ @the_class.method_defined?(name)
263
+ end
264
+
265
+ def name_is_reserved?(name)
266
+ BinData::Struct::RESERVED.include?(name.to_sym)
267
+ end
268
+
269
+ def dsl_raise(exception, message)
270
+ backtrace = caller
271
+ backtrace.shift while %r{bindata/dsl.rb} =~ backtrace.first
272
+
273
+ raise exception, message + " in #{@the_class}", backtrace
274
+ end
275
+
276
+ def to_array_params
277
+ case fields.length
278
+ when 0
279
+ {}
280
+ when 1
281
+ {:type => fields[0].prototype}
282
+ else
283
+ {:type => [:struct, to_struct_params]}
284
+ end
285
+ end
286
+
287
+ def to_choice_params
288
+ if fields.length == 0
289
+ {}
290
+ elsif fields.all_field_names_blank?
291
+ {:choices => fields.collect { |f| f.prototype }}
292
+ else
293
+ choices = {}
294
+ fields.each { |f| choices[f.name] = f.prototype }
295
+ {:choices => choices}
296
+ end
297
+ end
298
+
299
+ def to_struct_params
300
+ result = {:fields => fields}
301
+ if not endian.nil?
302
+ result[:endian] = endian
303
+ end
304
+ if option?(:hidden_fields) and not hide.empty?
305
+ result[:hide] = hide
306
+ end
307
+
308
+ result
309
+ end
310
+ end
311
+ end
312
+ end