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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fba829df2a0f618021920683747584daef8f572a
|
4
|
+
data.tar.gz: efe2ac6d0ab61895a09f271fb9d7712e289f1897
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eef3a6fd17fcb5fe9afcffa35c566cd4e0752063f20bc4d9d135aa3300184454b8974d3161d90e37390dfa3b6606b5f1bfe1217705075e28bd2e5641b11f878d
|
7
|
+
data.tar.gz: 55bc265de56013c33f1e9abf7d38a796deff58cedf7faa1c20e77ee6dbad5e42a080c3ab46c8f06503e7268888cedd38b51667e1d091fa23cb89afc39b5b124e
|
data/.travis.yml
CHANGED
data/ChangeLog.rdoc
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
= BinData Changelog
|
2
2
|
|
3
|
+
== Version 2.1.0 (2014-04-16)
|
4
|
+
|
5
|
+
* Performance improvements.
|
6
|
+
* Removed deprecated parameters.
|
7
|
+
* Code refactored to use Ruby 1.9 features.
|
8
|
+
* #eval_parameters can now call private methods. Requested by Ole Rasmussen.
|
9
|
+
* Can now determine state of :onlyif fields. Requested by Ole Rasmussen.
|
10
|
+
* Renamed #offset to #abs_offset for clarity. #offset is now deprecated.
|
11
|
+
* Support :byte_align for fields in structs. Requested by Igor Yamolov.
|
12
|
+
* Added bit fields with dynamic length. Requested by Jacob Dam.
|
13
|
+
* Added "endian :big_and_little" option which creates :big and :little
|
14
|
+
versions of the class. Thanks to Jacob Lukas for the prototype.
|
15
|
+
|
3
16
|
== Version 2.0.0 (2014-02-02)
|
4
17
|
|
5
18
|
* Ruby 1.8 now has its own separate branch.
|
data/NEWS.rdoc
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
= 2.1.0
|
2
|
+
|
3
|
+
Several new features in this release.
|
4
|
+
|
5
|
+
* Fields can be aligned on n-bytes boundaries. This make it easier to write
|
6
|
+
parsers for aligned structures.
|
7
|
+
* The endian value :big_and_little can be used to automatically create :big and
|
8
|
+
:little endian versions of the class.
|
9
|
+
* Bit fields can be defined to have their length determined at runtime.
|
10
|
+
* The state of :onlyif fields can be determined by #field?
|
11
|
+
|
12
|
+
== Deprecations
|
13
|
+
|
14
|
+
The #offset method has been renamed to #abs_offset. This make an obvious
|
15
|
+
distinction to #rel_offset.
|
16
|
+
|
1
17
|
= 2.0.0
|
2
18
|
|
3
19
|
BinData 2.0.0 requires ruby 1.9 or greater. Support for ruby 1.8 is found in
|
data/README.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# What is BinData?
|
2
2
|
|
3
|
+
[![Version ](http://img.shields.io/gem/v/bindata.svg) ](https://rubygems.org/gems/bindata)
|
4
|
+
[![Travis CI ](http://img.shields.io/travis/dmendel/bindata/master.svg) ](https://travis-ci.org/dmendel/bindata)
|
5
|
+
[![Quality ](http://img.shields.io/codeclimate/github/dmendel/bindata.svg)](https://codeclimate.com/github/dmendel/bindata)
|
6
|
+
[![Coverage ](http://img.shields.io/coveralls/dmendel/bindata.svg) ](https://coveralls.io/r/dmendel/bindata)
|
7
|
+
|
3
8
|
Do you ever find yourself writing code like this?
|
4
9
|
|
5
10
|
```ruby
|
data/bindata.gemspec
CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
|
20
20
|
s.add_development_dependency('rake')
|
21
21
|
s.add_development_dependency('minitest', "> 5.0.0")
|
22
|
+
s.add_development_dependency('coveralls')
|
22
23
|
s.description = <<-END.gsub(/^ +/, "")
|
23
24
|
BinData is a declarative way to read and write binary file formats.
|
24
25
|
|
data/examples/gzip.rb
CHANGED
data/lib/bindata.rb
CHANGED
data/lib/bindata/array.rb
CHANGED
@@ -48,35 +48,16 @@ module BinData
|
|
48
48
|
# Each data object in an array has the variable +index+ made available
|
49
49
|
# to any lambda evaluated as a parameter of that data object.
|
50
50
|
class Array < BinData::Base
|
51
|
-
|
51
|
+
extend DSLMixin
|
52
52
|
include Enumerable
|
53
53
|
|
54
|
-
dsl_parser
|
54
|
+
dsl_parser :array
|
55
|
+
arg_processor :array
|
55
56
|
|
56
57
|
mandatory_parameter :type
|
57
58
|
optional_parameters :initial_length, :read_until
|
58
59
|
mutually_exclusive_parameters :initial_length, :read_until
|
59
60
|
|
60
|
-
class << self
|
61
|
-
|
62
|
-
def sanitize_parameters!(params) #:nodoc:
|
63
|
-
unless params.has_parameter?(:initial_length) or
|
64
|
-
params.has_parameter?(:read_until)
|
65
|
-
# ensure one of :initial_length and :read_until exists
|
66
|
-
params[:initial_length] = 0
|
67
|
-
end
|
68
|
-
|
69
|
-
params.warn_replacement_parameter(:read_length, :initial_length)
|
70
|
-
|
71
|
-
params.merge!(dsl_params)
|
72
|
-
|
73
|
-
if params.needs_sanitizing?(:type)
|
74
|
-
el_type, el_params = params[:type]
|
75
|
-
params[:type] = params.create_sanitized_object_prototype(el_type, el_params)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
61
|
def initialize_shared_instance
|
81
62
|
@element_prototype = get_parameter(:type)
|
82
63
|
if get_parameter(:read_until) == :eof
|
@@ -292,6 +273,26 @@ module BinData
|
|
292
273
|
end
|
293
274
|
end
|
294
275
|
|
276
|
+
class ArrayArgProcessor < BaseArgProcessor
|
277
|
+
def sanitize_parameters!(obj_class, params) #:nodoc:
|
278
|
+
unless params.has_parameter?(:initial_length) or
|
279
|
+
params.has_parameter?(:read_until)
|
280
|
+
# ensure one of :initial_length and :read_until exists
|
281
|
+
params[:initial_length] = 0
|
282
|
+
end
|
283
|
+
|
284
|
+
params.warn_replacement_parameter(:read_length, :initial_length)
|
285
|
+
params.must_be_integer(:initial_length, :read_length)
|
286
|
+
|
287
|
+
params.merge!(obj_class.dsl_params)
|
288
|
+
|
289
|
+
if params.needs_sanitizing?(:type)
|
290
|
+
el_type, el_params = params[:type]
|
291
|
+
params[:type] = params.create_sanitized_object_prototype(el_type, el_params)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
295
296
|
# Logic for the :read_until parameter
|
296
297
|
module ReadUntilPlugin
|
297
298
|
def do_read(io)
|
data/lib/bindata/base.rb
CHANGED
@@ -8,33 +8,6 @@ require 'bindata/registry'
|
|
8
8
|
require 'bindata/sanitize'
|
9
9
|
|
10
10
|
module BinData
|
11
|
-
# ArgExtractors take the arguments passed to BinData::Base.new and
|
12
|
-
# separate them into [value, parameters, parent].
|
13
|
-
class BaseArgExtractor
|
14
|
-
@@empty_hash = Hash.new.freeze
|
15
|
-
|
16
|
-
def self.extract(the_class, the_args)
|
17
|
-
args = the_args.dup
|
18
|
-
value = parameters = parent = nil
|
19
|
-
|
20
|
-
if args.length > 1 and args.last.is_a? BinData::Base
|
21
|
-
parent = args.pop
|
22
|
-
end
|
23
|
-
|
24
|
-
if args.length > 0 and args.last.is_a? Hash
|
25
|
-
parameters = args.pop
|
26
|
-
end
|
27
|
-
|
28
|
-
if args.length > 0
|
29
|
-
value = args.pop
|
30
|
-
end
|
31
|
-
|
32
|
-
parameters ||= @@empty_hash
|
33
|
-
|
34
|
-
return [value, parameters, parent]
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
11
|
# This is the abstract base class for all data objects.
|
39
12
|
class Base
|
40
13
|
extend AcceptedParametersPlugin
|
@@ -43,18 +16,25 @@ module BinData
|
|
43
16
|
include RegisterNamePlugin
|
44
17
|
|
45
18
|
class << self
|
46
|
-
|
47
19
|
# Instantiates this class and reads from +io+, returning the newly
|
48
|
-
# created data object.
|
49
|
-
def read(io)
|
50
|
-
obj = self.new
|
20
|
+
# created data object. +args+ will be used when instantiating.
|
21
|
+
def read(io, *args)
|
22
|
+
obj = self.new(*args)
|
51
23
|
obj.read(io)
|
52
24
|
obj
|
53
25
|
end
|
54
26
|
|
55
|
-
# The arg
|
56
|
-
def
|
57
|
-
|
27
|
+
# The arg processor for this class.
|
28
|
+
def arg_processor(name = nil)
|
29
|
+
if name
|
30
|
+
@arg_processor = "#{name}_arg_processor".gsub(/(?:^|_)(.)/) { $1.upcase }.to_sym
|
31
|
+
elsif @arg_processor.is_a? Symbol
|
32
|
+
@arg_processor = BinData::const_get(@arg_processor).new
|
33
|
+
elsif @arg_processor.nil?
|
34
|
+
@arg_processor = superclass.arg_processor
|
35
|
+
else
|
36
|
+
@arg_processor
|
37
|
+
end
|
58
38
|
end
|
59
39
|
|
60
40
|
# The name of this class as used by Records, Arrays etc.
|
@@ -69,11 +49,9 @@ module BinData
|
|
69
49
|
|
70
50
|
# Registers all subclasses of this class for use
|
71
51
|
def register_subclasses #:nodoc:
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
register_subclasses
|
76
|
-
end
|
52
|
+
define_singleton_method(:inherited) do |subclass|
|
53
|
+
RegisteredClasses.register(subclass.name, subclass)
|
54
|
+
register_subclasses
|
77
55
|
end
|
78
56
|
end
|
79
57
|
|
@@ -83,6 +61,9 @@ module BinData
|
|
83
61
|
# Register all subclasses of this class.
|
84
62
|
register_subclasses
|
85
63
|
|
64
|
+
# Set the initial arg processor.
|
65
|
+
arg_processor :base
|
66
|
+
|
86
67
|
# Creates a new data object.
|
87
68
|
#
|
88
69
|
# Args are optional, but if present, must be in the following order.
|
@@ -96,10 +77,7 @@ module BinData
|
|
96
77
|
# object resides under.
|
97
78
|
#
|
98
79
|
def initialize(*args)
|
99
|
-
value,
|
100
|
-
|
101
|
-
@params = SanitizedParameters.sanitize(parameters, self.class)
|
102
|
-
@parent = parent
|
80
|
+
value, @params, @parent = extract_args(args)
|
103
81
|
|
104
82
|
initialize_shared_instance
|
105
83
|
initialize_instance
|
@@ -233,16 +211,17 @@ module BinData
|
|
233
211
|
end
|
234
212
|
end
|
235
213
|
|
236
|
-
# Returns the offset of this object
|
237
|
-
|
214
|
+
# Returns the offset (in bytes) of this object with respect to its most
|
215
|
+
# distant ancestor.
|
216
|
+
def abs_offset
|
238
217
|
if @parent
|
239
|
-
@parent.
|
218
|
+
@parent.abs_offset + @parent.offset_of(self)
|
240
219
|
else
|
241
220
|
0
|
242
221
|
end
|
243
222
|
end
|
244
223
|
|
245
|
-
# Returns the offset of this object
|
224
|
+
# Returns the offset (in bytes) of this object with respect to its parent.
|
246
225
|
def rel_offset
|
247
226
|
if @parent
|
248
227
|
@parent.offset_of(self)
|
@@ -266,8 +245,8 @@ module BinData
|
|
266
245
|
#---------------
|
267
246
|
private
|
268
247
|
|
269
|
-
def extract_args(
|
270
|
-
self.class.
|
248
|
+
def extract_args(args)
|
249
|
+
self.class.arg_processor.extract_args(self.class, args)
|
271
250
|
end
|
272
251
|
|
273
252
|
def furthest_ancestor
|
@@ -284,4 +263,51 @@ module BinData
|
|
284
263
|
str.to_s.dup.force_encoding(Encoding::BINARY)
|
285
264
|
end
|
286
265
|
end
|
266
|
+
|
267
|
+
# ArgProcessors process the arguments passed to BinData::Base.new into
|
268
|
+
# the form required to initialise the BinData object.
|
269
|
+
#
|
270
|
+
# Any passed parameters are sanitized so the BinData object doesn't
|
271
|
+
# need to perform error checking on the parameters.
|
272
|
+
class BaseArgProcessor
|
273
|
+
@@empty_hash = Hash.new.freeze
|
274
|
+
|
275
|
+
# Takes the arguments passed to BinData::Base.new and
|
276
|
+
# extracts [value, sanitized_parameters, parent].
|
277
|
+
def extract_args(obj_class, obj_args)
|
278
|
+
value, params, parent = separate_args(obj_class, obj_args)
|
279
|
+
sanitized_params = SanitizedParameters.sanitize(params, obj_class)
|
280
|
+
|
281
|
+
[value, sanitized_params, parent]
|
282
|
+
end
|
283
|
+
|
284
|
+
# Separates the arguments passed to BinData::Base.new into
|
285
|
+
# [value, parameters, parent]. Called by #extract_args.
|
286
|
+
def separate_args(obj_class, obj_args)
|
287
|
+
args = obj_args.dup
|
288
|
+
value = parameters = parent = nil
|
289
|
+
|
290
|
+
if args.length > 1 and args.last.is_a? BinData::Base
|
291
|
+
parent = args.pop
|
292
|
+
end
|
293
|
+
|
294
|
+
if args.length > 0 and args.last.is_a? Hash
|
295
|
+
parameters = args.pop
|
296
|
+
end
|
297
|
+
|
298
|
+
if args.length > 0
|
299
|
+
value = args.pop
|
300
|
+
end
|
301
|
+
|
302
|
+
parameters ||= @@empty_hash
|
303
|
+
|
304
|
+
return [value, parameters, parent]
|
305
|
+
end
|
306
|
+
|
307
|
+
# Performs sanity checks on the given parameters.
|
308
|
+
# This method converts the parameters to the form expected
|
309
|
+
# by the data object.
|
310
|
+
def sanitize_parameters!(obj_class, obj_params)
|
311
|
+
end
|
312
|
+
end
|
287
313
|
end
|
@@ -20,10 +20,10 @@ module BinData
|
|
20
20
|
# obj.assign(5)
|
21
21
|
# obj #=> 42
|
22
22
|
#
|
23
|
-
# obj = BinData::Uint8.new(:
|
23
|
+
# obj = BinData::Uint8.new(:assert_value => 3)
|
24
24
|
# obj.read("\005") #=> BinData::ValidityError: value is '5' but expected '3'
|
25
25
|
#
|
26
|
-
# obj = BinData::Uint8.new(:
|
26
|
+
# obj = BinData::Uint8.new(:assert_value => lambda { value < 5 })
|
27
27
|
# obj.read("\007") #=> BinData::ValidityError: value not as expected
|
28
28
|
#
|
29
29
|
# == Parameters
|
@@ -49,22 +49,13 @@ module BinData
|
|
49
49
|
class BasePrimitive < BinData::Base
|
50
50
|
unregister_self
|
51
51
|
|
52
|
-
optional_parameters :initial_value, :value, :
|
52
|
+
optional_parameters :initial_value, :value, :assert, :asserted_value
|
53
53
|
mutually_exclusive_parameters :initial_value, :value
|
54
54
|
mutually_exclusive_parameters :asserted_value, :value, :assert
|
55
|
-
mutually_exclusive_parameters :check_value, :assert
|
56
|
-
mutually_exclusive_parameters :check_value, :asserted_value
|
57
55
|
|
58
56
|
def initialize_shared_instance
|
59
|
-
if has_parameter?(:check_value) and has_parameter?(:value)
|
60
|
-
warn ":check_value has been deprecated. Consider using :asserted_value instead of :check_value and :value in #{self.class}."
|
61
|
-
elsif has_parameter?(:check_value)
|
62
|
-
warn ":check_value has been deprecated. Use :assert instead in #{self.class}."
|
63
|
-
end
|
64
|
-
|
65
57
|
extend InitialValuePlugin if has_parameter?(:initial_value)
|
66
58
|
extend ValuePlugin if has_parameter?(:value)
|
67
|
-
extend CheckValuePlugin if has_parameter?(:check_value)
|
68
59
|
extend AssertPlugin if has_parameter?(:assert)
|
69
60
|
extend AssertedValuePlugin if has_parameter?(:asserted_value)
|
70
61
|
super
|
@@ -169,26 +160,6 @@ module BinData
|
|
169
160
|
end
|
170
161
|
end
|
171
162
|
|
172
|
-
# Logic for the :check_value parameter
|
173
|
-
module CheckValuePlugin
|
174
|
-
def do_read(io) #:nodoc:
|
175
|
-
super(io)
|
176
|
-
check_value(snapshot)
|
177
|
-
end
|
178
|
-
|
179
|
-
def check_value(current_value)
|
180
|
-
expected = eval_parameter(:check_value, :value => current_value)
|
181
|
-
if not expected
|
182
|
-
raise ValidityError,
|
183
|
-
"value '#{current_value}' not as expected for #{debug_name}"
|
184
|
-
elsif current_value != expected and expected != true
|
185
|
-
raise ValidityError,
|
186
|
-
"value is '#{current_value}' but " +
|
187
|
-
"expected '#{expected}' for #{debug_name}"
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
163
|
# Logic for the :assert parameter
|
193
164
|
module AssertPlugin
|
194
165
|
def assign(val)
|
data/lib/bindata/bits.rb
CHANGED
@@ -6,13 +6,11 @@ module BinData
|
|
6
6
|
|
7
7
|
module BitField #:nodoc: all
|
8
8
|
class << self
|
9
|
-
def define_class(nbits, endian, signed = :unsigned)
|
10
|
-
name = ((signed == :signed ) ? "Sbit" : "Bit") + nbits.to_s
|
11
|
-
name << "le" if endian == :little
|
9
|
+
def define_class(name, nbits, endian, signed = :unsigned)
|
12
10
|
unless BinData.const_defined?(name)
|
13
11
|
BinData.module_eval <<-END
|
14
12
|
class #{name} < BinData::BasePrimitive
|
15
|
-
BitField.define_methods(self, #{nbits},
|
13
|
+
BitField.define_methods(self, #{nbits.inspect}, #{endian.inspect}, #{signed.inspect})
|
16
14
|
end
|
17
15
|
END
|
18
16
|
end
|
@@ -22,27 +20,34 @@ module BinData
|
|
22
20
|
|
23
21
|
def define_methods(bit_class, nbits, endian, signed)
|
24
22
|
bit_class.module_eval <<-END
|
23
|
+
#{create_params_code(nbits)}
|
24
|
+
|
25
25
|
def assign(val)
|
26
|
+
#{create_nbits_code(nbits)}
|
26
27
|
#{create_clamp_code(nbits, signed)}
|
27
28
|
super(val)
|
28
29
|
end
|
29
30
|
|
30
31
|
def do_write(io)
|
32
|
+
#{create_nbits_code(nbits)}
|
31
33
|
val = _value
|
32
|
-
#{create_int2uint_code(nbits
|
34
|
+
#{create_int2uint_code(nbits, signed)}
|
33
35
|
io.writebits(val, #{nbits}, :#{endian})
|
34
36
|
end
|
35
37
|
|
36
38
|
def do_num_bytes
|
37
|
-
#{nbits
|
39
|
+
#{create_nbits_code(nbits)}
|
40
|
+
#{create_do_num_bytes_code(nbits)}
|
38
41
|
end
|
39
42
|
|
40
43
|
#---------------
|
41
44
|
private
|
42
45
|
|
46
|
+
|
43
47
|
def read_and_return_value(io)
|
48
|
+
#{create_nbits_code(nbits)}
|
44
49
|
val = io.readbits(#{nbits}, :#{endian})
|
45
|
-
#{create_uint2int_code(nbits
|
50
|
+
#{create_uint2int_code(nbits, signed)}
|
46
51
|
val
|
47
52
|
end
|
48
53
|
|
@@ -52,7 +57,51 @@ module BinData
|
|
52
57
|
END
|
53
58
|
end
|
54
59
|
|
60
|
+
def create_params_code(nbits)
|
61
|
+
if nbits == :nbits
|
62
|
+
"mandatory_parameter :nbits"
|
63
|
+
else
|
64
|
+
""
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def create_nbits_code(nbits)
|
69
|
+
if nbits == :nbits
|
70
|
+
"nbits = eval_parameter(:nbits)"
|
71
|
+
else
|
72
|
+
""
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def create_do_num_bytes_code(nbits)
|
77
|
+
if nbits == :nbits
|
78
|
+
"nbits / 8.0"
|
79
|
+
else
|
80
|
+
nbits / 8.0
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
55
84
|
def create_clamp_code(nbits, signed)
|
85
|
+
if nbits == :nbits
|
86
|
+
create_dynamic_clamp_code(nbits, signed)
|
87
|
+
else
|
88
|
+
create_fixed_clamp_code(nbits, signed)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def create_dynamic_clamp_code(nbits, signed)
|
93
|
+
if signed == :signed
|
94
|
+
max = "max = (1 << (nbits - 1)) - 1"
|
95
|
+
min = "min = -(max + 1)"
|
96
|
+
else
|
97
|
+
max = "max = (1 << nbits) - 1"
|
98
|
+
min = "min = 0"
|
99
|
+
end
|
100
|
+
|
101
|
+
"#{max}; #{min}; val = (val < min) ? min : (val > max) ? max : val"
|
102
|
+
end
|
103
|
+
|
104
|
+
def create_fixed_clamp_code(nbits, signed)
|
56
105
|
if nbits == 1 and signed == :signed
|
57
106
|
raise "signed bitfield must have more than one bit"
|
58
107
|
end
|
@@ -75,30 +124,50 @@ module BinData
|
|
75
124
|
"val = #{clamp}"
|
76
125
|
end
|
77
126
|
|
78
|
-
def create_int2uint_code(nbits)
|
79
|
-
|
127
|
+
def create_int2uint_code(nbits, signed)
|
128
|
+
if signed != :signed
|
129
|
+
""
|
130
|
+
elsif nbits == :nbits
|
131
|
+
"val &= (1 << nbits) - 1"
|
132
|
+
else
|
133
|
+
"val &= #{(1 << nbits) - 1}"
|
134
|
+
end
|
80
135
|
end
|
81
136
|
|
82
|
-
def create_uint2int_code(nbits)
|
83
|
-
|
137
|
+
def create_uint2int_code(nbits, signed)
|
138
|
+
if signed != :signed
|
139
|
+
""
|
140
|
+
elsif nbits == :nbits
|
141
|
+
"val -= (1 << nbits) if (val >= (1 << (nbits - 1)))"
|
142
|
+
else
|
143
|
+
"val -= #{1 << nbits} if (val >= #{1 << (nbits - 1)})"
|
144
|
+
end
|
84
145
|
end
|
85
146
|
end
|
86
147
|
end
|
87
148
|
|
149
|
+
# Create classes for dynamic bitfields
|
150
|
+
{
|
151
|
+
"Bit" => :big,
|
152
|
+
"BitLe" => :little,
|
153
|
+
"Sbit" => [:big, :signed],
|
154
|
+
"SbitLe" => [:little, :signed],
|
155
|
+
}.each_pair { |name, args| BitField.define_class(name, :nbits, *args) }
|
156
|
+
|
88
157
|
# Create classes on demand
|
89
158
|
module BitFieldFactory
|
90
159
|
def const_missing(name)
|
91
160
|
mappings = {
|
92
|
-
/^Bit(\d+)$/
|
93
|
-
/^Bit(\d+)le$/
|
94
|
-
/^Sbit(\d+)$/
|
161
|
+
/^Bit(\d+)$/ => :big,
|
162
|
+
/^Bit(\d+)le$/ => :little,
|
163
|
+
/^Sbit(\d+)$/ => [:big, :signed],
|
95
164
|
/^Sbit(\d+)le$/ => [:little, :signed]
|
96
165
|
}
|
97
166
|
|
98
167
|
mappings.each_pair do |regex, args|
|
99
168
|
if regex =~ name.to_s
|
100
169
|
nbits = $1.to_i
|
101
|
-
return BitField.define_class(nbits, *args)
|
170
|
+
return BitField.define_class(name, nbits, *args)
|
102
171
|
end
|
103
172
|
end
|
104
173
|
|