bindata 2.0.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bindata might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/ChangeLog.rdoc +13 -0
- data/NEWS.rdoc +16 -0
- data/README.md +5 -0
- data/bindata.gemspec +1 -0
- data/examples/gzip.rb +1 -1
- data/lib/bindata.rb +1 -1
- data/lib/bindata/array.rb +23 -22
- data/lib/bindata/base.rb +75 -49
- data/lib/bindata/base_primitive.rb +3 -32
- data/lib/bindata/bits.rb +84 -15
- data/lib/bindata/buffer.rb +19 -18
- data/lib/bindata/choice.rb +51 -67
- data/lib/bindata/dsl.rb +268 -161
- data/lib/bindata/framework.rb +0 -11
- data/lib/bindata/int.rb +67 -42
- data/lib/bindata/io.rb +13 -4
- data/lib/bindata/lazy.rb +1 -1
- data/lib/bindata/primitive.rb +9 -8
- data/lib/bindata/record.rb +9 -60
- data/lib/bindata/sanitize.rb +35 -5
- data/lib/bindata/string.rb +33 -34
- data/lib/bindata/struct.rb +166 -109
- data/lib/bindata/version.rb +1 -1
- data/lib/bindata/{deprecated.rb → warnings.rb} +9 -3
- data/test/array_test.rb +3 -3
- data/test/base_primitive_test.rb +0 -34
- data/test/bits_test.rb +38 -34
- data/test/common.rb +4 -0
- data/test/io_test.rb +15 -0
- data/test/lazy_test.rb +11 -3
- data/test/record_test.rb +83 -6
- data/test/struct_test.rb +40 -9
- data/test/system_test.rb +1 -1
- data/test/{deprecated_test.rb → warnings_test.rb} +0 -0
- metadata +18 -4
data/lib/bindata/buffer.rb
CHANGED
@@ -51,32 +51,18 @@ module BinData
|
|
51
51
|
# <tt>:type</tt>:: The single type inside the buffer. Use a struct if
|
52
52
|
# multiple fields are required.
|
53
53
|
class Buffer < BinData::Base
|
54
|
-
|
54
|
+
extend DSLMixin
|
55
55
|
|
56
|
-
dsl_parser
|
56
|
+
dsl_parser :buffer
|
57
|
+
arg_processor :buffer
|
57
58
|
|
58
59
|
mandatory_parameters :length, :type
|
59
60
|
|
60
|
-
class << self
|
61
|
-
def arg_extractor
|
62
|
-
MultiFieldArgExtractor
|
63
|
-
end
|
64
|
-
|
65
|
-
def sanitize_parameters!(params) #:nodoc:
|
66
|
-
params.merge!(dsl_params)
|
67
|
-
|
68
|
-
if params.needs_sanitizing?(:type)
|
69
|
-
el_type, el_params = params[:type]
|
70
|
-
params[:type] = params.create_sanitized_object_prototype(el_type, el_params)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
61
|
def initialize_instance
|
76
62
|
@type = get_parameter(:type).instantiate(nil, self)
|
77
63
|
end
|
78
64
|
|
79
|
-
def clear?
|
65
|
+
def clear?
|
80
66
|
@type.clear?
|
81
67
|
end
|
82
68
|
|
@@ -116,4 +102,19 @@ module BinData
|
|
116
102
|
eval_parameter(:length)
|
117
103
|
end
|
118
104
|
end
|
105
|
+
|
106
|
+
class BufferArgProcessor < BaseArgProcessor
|
107
|
+
include MultiFieldArgSeparator
|
108
|
+
|
109
|
+
def sanitize_parameters!(obj_class, params)
|
110
|
+
params.merge!(obj_class.dsl_params)
|
111
|
+
|
112
|
+
params.must_be_integer(:length)
|
113
|
+
|
114
|
+
if params.needs_sanitizing?(:type)
|
115
|
+
el_type, el_params = params[:type]
|
116
|
+
params[:type] = params.create_sanitized_object_prototype(el_type, el_params)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
119
120
|
end
|
data/lib/bindata/choice.rb
CHANGED
@@ -58,54 +58,14 @@ module BinData
|
|
58
58
|
# selection to the current selection whenever the
|
59
59
|
# selection changes. Default is false.
|
60
60
|
class Choice < BinData::Base
|
61
|
-
|
61
|
+
extend DSLMixin
|
62
62
|
|
63
|
-
dsl_parser
|
63
|
+
dsl_parser :choice
|
64
|
+
arg_processor :choice
|
64
65
|
|
65
66
|
mandatory_parameters :choices, :selection
|
66
67
|
optional_parameter :copy_on_change
|
67
68
|
|
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
69
|
def initialize_shared_instance
|
110
70
|
extend CopyOnChangePlugin if eval_parameter(:copy_on_change) == true
|
111
71
|
super
|
@@ -125,40 +85,24 @@ module BinData
|
|
125
85
|
selection
|
126
86
|
end
|
127
87
|
|
128
|
-
def
|
129
|
-
|
130
|
-
end
|
131
|
-
|
132
|
-
def assign(val)
|
133
|
-
current_choice.assign(val)
|
134
|
-
end
|
135
|
-
|
136
|
-
def snapshot
|
137
|
-
current_choice.snapshot
|
88
|
+
def safe_respond_to?(symbol, include_private = false) #:nodoc:
|
89
|
+
base_respond_to?(symbol, include_private)
|
138
90
|
end
|
139
91
|
|
140
92
|
def respond_to?(symbol, include_private = false) #:nodoc:
|
141
93
|
current_choice.respond_to?(symbol, include_private) || super
|
142
94
|
end
|
143
95
|
|
144
|
-
def safe_respond_to?(symbol, include_private = false) #:nodoc:
|
145
|
-
base_respond_to?(symbol, include_private)
|
146
|
-
end
|
147
|
-
|
148
96
|
def method_missing(symbol, *args, &block) #:nodoc:
|
149
97
|
current_choice.__send__(symbol, *args, &block)
|
150
98
|
end
|
151
99
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
end
|
159
|
-
|
160
|
-
def do_num_bytes #:nodoc:
|
161
|
-
current_choice.do_num_bytes
|
100
|
+
%w(clear? assign snapshot do_read do_write do_num_bytes).each do |m|
|
101
|
+
self.module_eval <<-END
|
102
|
+
def #{m}(*args)
|
103
|
+
current_choice.#{m}(*args)
|
104
|
+
end
|
105
|
+
END
|
162
106
|
end
|
163
107
|
|
164
108
|
#---------------
|
@@ -178,6 +122,46 @@ module BinData
|
|
178
122
|
end
|
179
123
|
end
|
180
124
|
|
125
|
+
class ChoiceArgProcessor < BaseArgProcessor
|
126
|
+
def sanitize_parameters!(obj_class, params) #:nodoc:
|
127
|
+
params.merge!(obj_class.dsl_params)
|
128
|
+
|
129
|
+
if params.needs_sanitizing?(:choices)
|
130
|
+
choices = choices_as_hash(params[:choices])
|
131
|
+
ensure_valid_keys(choices)
|
132
|
+
params[:choices] = params.create_sanitized_choices(choices)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
#-------------
|
137
|
+
private
|
138
|
+
|
139
|
+
def choices_as_hash(choices)
|
140
|
+
if choices.respond_to?(:to_ary)
|
141
|
+
key_array_by_index(choices.to_ary)
|
142
|
+
else
|
143
|
+
choices
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def key_array_by_index(array)
|
148
|
+
result = {}
|
149
|
+
array.each_with_index do |el, i|
|
150
|
+
result[i] = el unless el.nil?
|
151
|
+
end
|
152
|
+
result
|
153
|
+
end
|
154
|
+
|
155
|
+
def ensure_valid_keys(choices)
|
156
|
+
if choices.has_key?(nil)
|
157
|
+
raise ArgumentError, ":choices hash may not have nil key"
|
158
|
+
end
|
159
|
+
if choices.keys.detect { |key| key.is_a?(Symbol) and key != :default }
|
160
|
+
raise ArgumentError, ":choices hash may not have symbols for keys"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
181
165
|
# Logic for the :copy_on_change parameter
|
182
166
|
module CopyOnChangePlugin
|
183
167
|
def current_choice
|
data/lib/bindata/dsl.rb
CHANGED
@@ -5,60 +5,52 @@ module BinData
|
|
5
5
|
#
|
6
6
|
# BaseArgExtractor always assumes :bar is parameter. This extractor correctly
|
7
7
|
# identifies it as value or parameter.
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
value, parameters, parent = BaseArgExtractor.extract(the_class, the_args)
|
12
|
-
|
13
|
-
if parameters_is_value?(the_class, value, parameters)
|
14
|
-
value = parameters
|
15
|
-
parameters = {}
|
16
|
-
end
|
8
|
+
module MultiFieldArgSeparator
|
9
|
+
def separate_args(obj_class, obj_args)
|
10
|
+
value, parameters, parent = super(obj_class, obj_args)
|
17
11
|
|
18
|
-
|
12
|
+
if parameters_is_value?(obj_class, value, parameters)
|
13
|
+
value = parameters
|
14
|
+
parameters = {}
|
19
15
|
end
|
20
16
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
17
|
+
[value, parameters, parent]
|
18
|
+
end
|
19
|
+
|
20
|
+
def parameters_is_value?(obj_class, value, parameters)
|
21
|
+
if value.nil? and parameters.length > 0
|
22
|
+
field_names_in_parameters?(obj_class, parameters)
|
23
|
+
else
|
24
|
+
false
|
27
25
|
end
|
26
|
+
end
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
def field_names_in_parameters?(obj_class, parameters)
|
29
|
+
field_names = obj_class.fields.field_names
|
30
|
+
param_keys = parameters.keys
|
32
31
|
|
33
|
-
|
34
|
-
end
|
32
|
+
(field_names & param_keys).length > 0
|
35
33
|
end
|
36
34
|
end
|
37
35
|
|
36
|
+
# BinData classes that are part of the DSL must be extended by this.
|
38
37
|
module DSLMixin
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
module ClassMethods
|
44
|
-
|
45
|
-
def dsl_parser(parser_type = nil)
|
46
|
-
unless defined? @dsl_parser
|
47
|
-
parser_type = superclass.dsl_parser.parser_type if parser_type.nil?
|
48
|
-
@dsl_parser = DSLParser.new(self, parser_type)
|
49
|
-
end
|
50
|
-
@dsl_parser
|
51
|
-
end
|
52
|
-
|
53
|
-
def method_missing(symbol, *args, &block) #:nodoc:
|
54
|
-
dsl_parser.__send__(symbol, *args, &block)
|
38
|
+
def dsl_parser(parser_type = nil)
|
39
|
+
unless defined? @dsl_parser
|
40
|
+
parser_type = superclass.dsl_parser.parser_type if parser_type.nil?
|
41
|
+
@dsl_parser = DSLParser.new(self, parser_type)
|
55
42
|
end
|
43
|
+
@dsl_parser
|
44
|
+
end
|
56
45
|
|
57
|
-
|
58
|
-
|
59
|
-
def to_str; nil; end
|
46
|
+
def method_missing(symbol, *args, &block) #:nodoc:
|
47
|
+
dsl_parser.__send__(symbol, *args, &block)
|
60
48
|
end
|
61
49
|
|
50
|
+
# Assert object is not an array or string.
|
51
|
+
def to_ary; nil; end
|
52
|
+
def to_str; nil; end
|
53
|
+
|
62
54
|
# A DSLParser parses and accumulates field definitions of the form
|
63
55
|
#
|
64
56
|
# type name, params
|
@@ -70,21 +62,25 @@ module BinData
|
|
70
62
|
#
|
71
63
|
class DSLParser
|
72
64
|
def initialize(the_class, parser_type)
|
73
|
-
|
74
|
-
|
75
|
-
@
|
65
|
+
raise "unknown parser type #{parser_type}" unless parser_abilities[parser_type]
|
66
|
+
|
67
|
+
@the_class = the_class
|
68
|
+
@parser_type = parser_type
|
69
|
+
@validator = DSLFieldValidator.new(the_class, self)
|
70
|
+
@endian_handler = DSLBigAndLittleEndianHandler.new(the_class)
|
71
|
+
@endian = nil
|
76
72
|
end
|
77
73
|
|
78
74
|
attr_reader :parser_type
|
79
75
|
|
80
76
|
def endian(endian = nil)
|
81
|
-
if endian
|
82
|
-
|
83
|
-
elsif endian
|
84
|
-
|
85
|
-
|
86
|
-
dsl_raise ArgumentError, "unknown value for endian '#{endian}'"
|
77
|
+
if endian
|
78
|
+
set_endian(endian)
|
79
|
+
elsif @endian.nil?
|
80
|
+
pendian = parent_attribute(:endian, nil)
|
81
|
+
set_endian(pendian) if pendian
|
87
82
|
end
|
83
|
+
@endian
|
88
84
|
end
|
89
85
|
|
90
86
|
def hide(*args)
|
@@ -102,7 +98,7 @@ module BinData
|
|
102
98
|
|
103
99
|
def fields
|
104
100
|
unless defined? @fields
|
105
|
-
fields = parent_attribute(:fields
|
101
|
+
fields = @endian_handler.ancestor_fields || parent_attribute(:fields)
|
106
102
|
@fields = SanitizedFields.new(endian)
|
107
103
|
@fields.copy_fields(fields) if fields
|
108
104
|
end
|
@@ -111,62 +107,217 @@ module BinData
|
|
111
107
|
end
|
112
108
|
|
113
109
|
def dsl_params
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
to_array_params
|
121
|
-
when :choice
|
122
|
-
to_choice_params
|
123
|
-
when :primitive
|
124
|
-
to_struct_params
|
110
|
+
send(parser_abilities[@parser_type].at(0))
|
111
|
+
end
|
112
|
+
|
113
|
+
def method_missing(*args, &block)
|
114
|
+
if endian == :big_and_little
|
115
|
+
@endian_handler.forward_field_definition(*args, &block)
|
125
116
|
else
|
126
|
-
|
117
|
+
parse_and_append_field(*args, &block)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
#-------------
|
122
|
+
private
|
123
|
+
|
124
|
+
def parser_abilities
|
125
|
+
@abilities ||= {
|
126
|
+
:struct => [:to_struct_params, [:multiple_fields, :optional_fieldnames, :hidden_fields]],
|
127
|
+
:array => [:to_array_params, [:multiple_fields, :optional_fieldnames]],
|
128
|
+
:buffer => [:to_array_params, [:multiple_fields, :optional_fieldnames]],
|
129
|
+
:choice => [:to_choice_params, [:multiple_fields, :all_or_none_fieldnames, :fieldnames_are_values]],
|
130
|
+
:primitive => [:to_struct_params, [:multiple_fields, :optional_fieldnames]]
|
131
|
+
}
|
132
|
+
end
|
133
|
+
|
134
|
+
def option?(opt)
|
135
|
+
parser_abilities[@parser_type].at(1).include?(opt)
|
136
|
+
end
|
137
|
+
|
138
|
+
def set_endian(endian)
|
139
|
+
if has_fields?
|
140
|
+
dsl_raise SyntaxError, "endian must not be called after defining fields"
|
127
141
|
end
|
142
|
+
if not valid_endian?(endian)
|
143
|
+
dsl_raise ArgumentError, "unknown value for endian '#{endian}'"
|
144
|
+
end
|
145
|
+
|
146
|
+
if endian == :big_and_little
|
147
|
+
@endian_handler.prepare_subclasses
|
148
|
+
end
|
149
|
+
|
150
|
+
@endian = endian
|
128
151
|
end
|
129
152
|
|
130
|
-
def
|
131
|
-
|
132
|
-
|
133
|
-
params = params_from_field_declaration(type, args, &block)
|
153
|
+
def has_fields?
|
154
|
+
@fields && @fields.length > 0
|
155
|
+
end
|
134
156
|
|
135
|
-
|
157
|
+
def valid_endian?(endian)
|
158
|
+
[:big, :little, :big_and_little].include?(endian)
|
159
|
+
end
|
160
|
+
|
161
|
+
def parent_attribute(attr, default = nil)
|
162
|
+
parent = @the_class.superclass
|
163
|
+
parser = parent.respond_to?(:dsl_parser) ? parent.dsl_parser : nil
|
164
|
+
if parser and parser.respond_to?(attr)
|
165
|
+
parser.send(attr)
|
166
|
+
else
|
167
|
+
default
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def parse_and_append_field(*args, &block)
|
172
|
+
parser = DSLFieldParser.new(endian, *args, &block)
|
173
|
+
begin
|
174
|
+
@validator.validate_field(parser.name)
|
175
|
+
append_field(parser.type, parser.name, parser.params)
|
176
|
+
rescue Exception => err
|
177
|
+
dsl_raise err.class, err.message
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def append_field(type, name, params)
|
182
|
+
fields.add_field(type, name, params)
|
183
|
+
rescue BinData::UnRegisteredTypeError => err
|
184
|
+
raise TypeError, "unknown type '#{err.message}'"
|
185
|
+
end
|
186
|
+
|
187
|
+
def dsl_raise(exception, message)
|
188
|
+
backtrace = caller
|
189
|
+
backtrace.shift while %r{bindata/dsl.rb} =~ backtrace.first
|
190
|
+
|
191
|
+
raise exception, message + " in #{@the_class}", backtrace
|
192
|
+
end
|
193
|
+
|
194
|
+
def to_array_params
|
195
|
+
case fields.length
|
196
|
+
when 0
|
197
|
+
{}
|
198
|
+
when 1
|
199
|
+
{:type => fields[0].prototype}
|
200
|
+
else
|
201
|
+
{:type => [:struct, to_struct_params]}
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def to_choice_params
|
206
|
+
if fields.length == 0
|
207
|
+
{}
|
208
|
+
elsif fields.all_field_names_blank?
|
209
|
+
{:choices => fields.collect { |f| f.prototype }}
|
210
|
+
else
|
211
|
+
choices = {}
|
212
|
+
fields.each { |f| choices[f.name] = f.prototype }
|
213
|
+
{:choices => choices}
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def to_struct_params
|
218
|
+
result = {:fields => fields}
|
219
|
+
if not endian.nil?
|
220
|
+
result[:endian] = endian
|
221
|
+
end
|
222
|
+
if option?(:hidden_fields) and not hide.empty?
|
223
|
+
result[:hide] = hide
|
224
|
+
end
|
225
|
+
|
226
|
+
result
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# Handles the :big_and_little endian option.
|
231
|
+
# This option creates two subclasses, each handling
|
232
|
+
# :big or :little endian.
|
233
|
+
class DSLBigAndLittleEndianHandler
|
234
|
+
def initialize(the_class)
|
235
|
+
@the_class = the_class
|
236
|
+
end
|
237
|
+
|
238
|
+
def prepare_subclasses
|
239
|
+
create_subclasses_with_endian
|
240
|
+
make_class_abstract
|
241
|
+
override_new_in_class
|
242
|
+
end
|
243
|
+
|
244
|
+
def forward_field_definition(*args, &block)
|
245
|
+
class_with_endian(@the_class, :big).send(*args, &block)
|
246
|
+
class_with_endian(@the_class, :little).send(*args, &block)
|
247
|
+
end
|
248
|
+
|
249
|
+
def ancestor_fields
|
250
|
+
if subclass_of_big_and_little_endian?
|
251
|
+
pparent = @the_class.superclass.superclass
|
252
|
+
ancestor_with_endian = class_with_endian(pparent, @the_class.endian)
|
253
|
+
obj_attribute(ancestor_with_endian, :fields)
|
254
|
+
else
|
255
|
+
nil
|
256
|
+
end
|
136
257
|
end
|
137
258
|
|
138
259
|
#-------------
|
139
260
|
private
|
140
261
|
|
141
|
-
def
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
262
|
+
def create_subclasses_with_endian
|
263
|
+
instance_eval "class ::#{@the_class}Be < ::#{@the_class}; endian :big; end"
|
264
|
+
instance_eval "class ::#{@the_class}Le < ::#{@the_class}; endian :little; end"
|
265
|
+
end
|
266
|
+
|
267
|
+
def make_class_abstract
|
268
|
+
@the_class.send(:unregister_self)
|
269
|
+
end
|
270
|
+
|
271
|
+
def override_new_in_class
|
272
|
+
saved_class = @the_class
|
273
|
+
endian_classes = {
|
274
|
+
:big => class_with_endian(saved_class, :big),
|
275
|
+
:little => class_with_endian(saved_class, :little),
|
276
|
+
}
|
277
|
+
@the_class.define_singleton_method(:new) do |*args|
|
278
|
+
if self == saved_class
|
279
|
+
value, options, parent = arg_processor.separate_args(self, args)
|
280
|
+
delegate = endian_classes[options[:endian]]
|
281
|
+
return delegate.new(*args) if delegate
|
282
|
+
end
|
283
|
+
|
284
|
+
super(*args)
|
159
285
|
end
|
160
286
|
end
|
161
287
|
|
162
|
-
def
|
163
|
-
parent
|
164
|
-
|
165
|
-
|
288
|
+
def subclass_of_big_and_little_endian?
|
289
|
+
parent = @the_class.superclass
|
290
|
+
pparent = parent.superclass
|
291
|
+
|
292
|
+
obj_attribute(parent, :endian) == :big_and_little and
|
293
|
+
obj_attribute(pparent, :endian) == :big_and_little and
|
294
|
+
[:big, :little].include?(@the_class.endian)
|
295
|
+
end
|
296
|
+
|
297
|
+
def class_with_endian(class_name, endian)
|
298
|
+
RegisteredClasses.lookup(class_name, endian)
|
299
|
+
end
|
300
|
+
|
301
|
+
def obj_attribute(obj, attr, default = nil)
|
302
|
+
parser = obj.respond_to?(:dsl_parser) ? obj.dsl_parser : nil
|
303
|
+
if parser and parser.respond_to?(attr)
|
304
|
+
parser.send(attr)
|
166
305
|
else
|
167
306
|
default
|
168
307
|
end
|
169
308
|
end
|
309
|
+
end
|
310
|
+
|
311
|
+
# Extracts the details from a field declaration.
|
312
|
+
class DSLFieldParser
|
313
|
+
def initialize(endian, symbol, *args, &block)
|
314
|
+
@endian = endian
|
315
|
+
@type = symbol
|
316
|
+
@name = name_from_field_declaration(args)
|
317
|
+
@params = params_from_field_declaration(args, &block)
|
318
|
+
end
|
319
|
+
|
320
|
+
attr_reader :type, :name, :params
|
170
321
|
|
171
322
|
def name_from_field_declaration(args)
|
172
323
|
name, params = args
|
@@ -177,11 +328,11 @@ module BinData
|
|
177
328
|
end
|
178
329
|
end
|
179
330
|
|
180
|
-
def params_from_field_declaration(
|
331
|
+
def params_from_field_declaration(args, &block)
|
181
332
|
params = params_from_args(args)
|
182
333
|
|
183
334
|
if block_given?
|
184
|
-
params.merge(params_from_block(
|
335
|
+
params.merge(params_from_block(&block))
|
185
336
|
else
|
186
337
|
params
|
187
338
|
end
|
@@ -194,7 +345,7 @@ module BinData
|
|
194
345
|
params || {}
|
195
346
|
end
|
196
347
|
|
197
|
-
def params_from_block(
|
348
|
+
def params_from_block(&block)
|
198
349
|
bindata_classes = {
|
199
350
|
:array => BinData::Array,
|
200
351
|
:buffer => BinData::Buffer,
|
@@ -202,9 +353,9 @@ module BinData
|
|
202
353
|
:struct => BinData::Struct
|
203
354
|
}
|
204
355
|
|
205
|
-
if bindata_classes.include?(type)
|
206
|
-
parser = DSLParser.new(bindata_classes[type], type)
|
207
|
-
parser.endian(endian)
|
356
|
+
if bindata_classes.include?(@type)
|
357
|
+
parser = DSLParser.new(bindata_classes[@type], @type)
|
358
|
+
parser.endian(@endian)
|
208
359
|
parser.instance_eval(&block)
|
209
360
|
|
210
361
|
parser.dsl_params
|
@@ -212,61 +363,51 @@ module BinData
|
|
212
363
|
{}
|
213
364
|
end
|
214
365
|
end
|
366
|
+
end
|
215
367
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
dsl_raise ArgumentError, err.message
|
222
|
-
rescue UnRegisteredTypeError => err
|
223
|
-
dsl_raise TypeError, "unknown type '#{err.message}'"
|
368
|
+
# Validates a field defined in a DSLMixin.
|
369
|
+
class DSLFieldValidator
|
370
|
+
def initialize(the_class, parser)
|
371
|
+
@the_class = the_class
|
372
|
+
@dsl_parser = parser
|
224
373
|
end
|
225
374
|
|
226
|
-
def
|
227
|
-
if
|
228
|
-
|
229
|
-
end
|
230
|
-
|
231
|
-
if must_not_have_a_name_failed?(field_name)
|
232
|
-
dsl_raise SyntaxError, "field must not have a name"
|
375
|
+
def validate_field(name)
|
376
|
+
if must_not_have_a_name_failed?(name)
|
377
|
+
raise SyntaxError, "field must not have a name"
|
233
378
|
end
|
234
379
|
|
235
|
-
if all_or_none_names_failed?(
|
236
|
-
|
380
|
+
if all_or_none_names_failed?(name)
|
381
|
+
raise SyntaxError, "fields must either all have names, or none must have names"
|
237
382
|
end
|
238
383
|
|
239
|
-
if must_have_a_name_failed?(
|
240
|
-
|
384
|
+
if must_have_a_name_failed?(name)
|
385
|
+
raise SyntaxError, "field must have a name"
|
241
386
|
end
|
242
387
|
|
243
|
-
ensure_valid_name(
|
388
|
+
ensure_valid_name(name)
|
244
389
|
end
|
245
390
|
|
246
391
|
def ensure_valid_name(name)
|
247
392
|
if name and not option?(:fieldnames_are_values)
|
248
393
|
if malformed_name?(name)
|
249
|
-
|
394
|
+
raise NameError.new("", name), "field '#{name}' is an illegal fieldname"
|
250
395
|
end
|
251
396
|
|
252
397
|
if duplicate_name?(name)
|
253
|
-
|
398
|
+
raise SyntaxError, "duplicate field '#{name}'"
|
254
399
|
end
|
255
400
|
|
256
401
|
if name_shadows_method?(name)
|
257
|
-
|
402
|
+
raise NameError.new("", name), "field '#{name}' shadows an existing method"
|
258
403
|
end
|
259
404
|
|
260
405
|
if name_is_reserved?(name)
|
261
|
-
|
406
|
+
raise NameError.new("", name), "field '#{name}' is a reserved name"
|
262
407
|
end
|
263
408
|
end
|
264
409
|
end
|
265
410
|
|
266
|
-
def too_many_fields?
|
267
|
-
option?(:only_one_field) and not fields.empty?
|
268
|
-
end
|
269
|
-
|
270
411
|
def must_not_have_a_name_failed?(name)
|
271
412
|
option?(:no_fieldnames) and name != nil
|
272
413
|
end
|
@@ -302,46 +443,12 @@ module BinData
|
|
302
443
|
BinData::Struct::RESERVED.include?(name.to_sym)
|
303
444
|
end
|
304
445
|
|
305
|
-
def
|
306
|
-
|
307
|
-
backtrace.shift while %r{bindata/dsl.rb} =~ backtrace.first
|
308
|
-
|
309
|
-
raise exception, message + " in #{@the_class}", backtrace
|
310
|
-
end
|
311
|
-
|
312
|
-
def to_array_params
|
313
|
-
case fields.length
|
314
|
-
when 0
|
315
|
-
{}
|
316
|
-
when 1
|
317
|
-
{:type => fields[0].prototype}
|
318
|
-
else
|
319
|
-
{:type => [:struct, to_struct_params]}
|
320
|
-
end
|
321
|
-
end
|
322
|
-
|
323
|
-
def to_choice_params
|
324
|
-
if fields.length == 0
|
325
|
-
{}
|
326
|
-
elsif fields.all_field_names_blank?
|
327
|
-
{:choices => fields.collect { |f| f.prototype }}
|
328
|
-
else
|
329
|
-
choices = {}
|
330
|
-
fields.each { |f| choices[f.name] = f.prototype }
|
331
|
-
{:choices => choices}
|
332
|
-
end
|
446
|
+
def fields
|
447
|
+
@dsl_parser.fields
|
333
448
|
end
|
334
449
|
|
335
|
-
def
|
336
|
-
|
337
|
-
if not endian.nil?
|
338
|
-
result[:endian] = endian
|
339
|
-
end
|
340
|
-
if option?(:hidden_fields) and not hide.empty?
|
341
|
-
result[:hide] = hide
|
342
|
-
end
|
343
|
-
|
344
|
-
result
|
450
|
+
def option?(opt)
|
451
|
+
@dsl_parser.send(:option?, opt)
|
345
452
|
end
|
346
453
|
end
|
347
454
|
end
|