bindata 1.8.0 → 1.8.1

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.

@@ -1,5 +1,9 @@
1
1
  = BinData Changelog
2
2
 
3
+ == Version 1.8.1 (2014-01-15)
4
+
5
+ * Added signed bitfields. Requested by redood.
6
+
3
7
  == Version 1.8.0 (2014-01-06)
4
8
 
5
9
  * Allow custom types to have endian, not just numerics.
@@ -6,13 +6,13 @@ module BinData
6
6
 
7
7
  module BitField #:nodoc: all
8
8
  class << self
9
- def define_class(nbits, endian)
10
- name = "Bit#{nbits}"
9
+ def define_class(nbits, endian, signed = :unsigned)
10
+ name = ((signed == :signed ) ? "Sbit" : "Bit") + nbits.to_s
11
11
  name << "le" if endian == :little
12
12
  unless BinData.const_defined?(name)
13
13
  BinData.module_eval <<-END
14
14
  class #{name} < BinData::BasePrimitive
15
- BitField.define_methods(self, #{nbits}, :#{endian})
15
+ BitField.define_methods(self, #{nbits}, :#{endian}, :#{signed})
16
16
  end
17
17
  END
18
18
  end
@@ -20,15 +20,17 @@ module BinData
20
20
  BinData.const_get(name)
21
21
  end
22
22
 
23
- def define_methods(bit_class, nbits, endian)
23
+ def define_methods(bit_class, nbits, endian, signed)
24
24
  bit_class.module_eval <<-END
25
25
  def assign(val)
26
- #{create_clamp_code(nbits)}
26
+ #{create_clamp_code(nbits, signed)}
27
27
  super(val)
28
28
  end
29
29
 
30
30
  def do_write(io)
31
- io.writebits(_value, #{nbits}, :#{endian})
31
+ val = _value
32
+ #{create_int2uint_code(nbits) if signed == :signed}
33
+ io.writebits(val, #{nbits}, :#{endian})
32
34
  end
33
35
 
34
36
  def do_num_bytes
@@ -39,7 +41,9 @@ module BinData
39
41
  private
40
42
 
41
43
  def read_and_return_value(io)
42
- io.readbits(#{nbits}, :#{endian})
44
+ val = io.readbits(#{nbits}, :#{endian})
45
+ #{create_uint2int_code(nbits) if signed == :signed}
46
+ val
43
47
  end
44
48
 
45
49
  def sensible_default
@@ -48,9 +52,19 @@ module BinData
48
52
  END
49
53
  end
50
54
 
51
- def create_clamp_code(nbits)
52
- min = 0
53
- max = (1 << nbits) - 1
55
+ def create_clamp_code(nbits, signed)
56
+ if nbits == 1 and signed == :signed
57
+ raise "signed bitfield must have more than one bit"
58
+ end
59
+
60
+ if signed == :signed
61
+ max = (1 << (nbits - 1)) - 1
62
+ min = -(max + 1)
63
+ else
64
+ min = 0
65
+ max = (1 << nbits) - 1
66
+ end
67
+
54
68
  clamp = "(val < #{min}) ? #{min} : (val > #{max}) ? #{max} : val"
55
69
 
56
70
  if nbits == 1
@@ -60,6 +74,14 @@ module BinData
60
74
 
61
75
  "val = #{clamp}"
62
76
  end
77
+
78
+ def create_int2uint_code(nbits)
79
+ "val = val & #{(1 << nbits) - 1}"
80
+ end
81
+
82
+ def create_uint2int_code(nbits)
83
+ "val = val - #{1 << nbits} if (val >= #{1 << (nbits - 1)})"
84
+ end
63
85
  end
64
86
  end
65
87
 
@@ -68,13 +90,15 @@ module BinData
68
90
  def const_missing(name)
69
91
  mappings = {
70
92
  /^Bit(\d+)$/ => :big,
71
- /^Bit(\d+)le$/ => :little
93
+ /^Bit(\d+)le$/ => :little,
94
+ /^Sbit(\d+)$/ => [:big, :signed],
95
+ /^Sbit(\d+)le$/ => [:little, :signed]
72
96
  }
73
97
 
74
- mappings.each_pair do |regex, endian|
98
+ mappings.each_pair do |regex, args|
75
99
  if regex =~ name.to_s
76
100
  nbits = $1.to_i
77
- return BitField.define_class(nbits, endian)
101
+ return BitField.define_class(nbits, *args)
78
102
  end
79
103
  end
80
104
 
@@ -73,7 +73,7 @@ module BinData
73
73
  end
74
74
 
75
75
  def register_dynamic_class(name)
76
- if /^u?int\d+(le|be)$/ =~ name or /^bit\d+(le)?$/ =~ name
76
+ if /^u?int\d+(le|be)$/ =~ name or /^s?bit\d+(le)?$/ =~ name
77
77
  class_name = name.gsub(/(?:^|_)(.)/) { $1.upcase }
78
78
  begin
79
79
  BinData::const_get(class_name)
@@ -1,3 +1,3 @@
1
1
  module BinData
2
- VERSION = "1.8.0"
2
+ VERSION = "1.8.1"
3
3
  end
@@ -69,11 +69,19 @@ module AllBitfields
69
69
  end
70
70
 
71
71
  def min_value
72
- 0
72
+ if @signed
73
+ -max_value - 1
74
+ else
75
+ 0
76
+ end
73
77
  end
74
78
 
75
79
  def max_value
76
- (1 << @nbits) - 1
80
+ if @signed
81
+ (1 << (@nbits - 1)) - 1
82
+ else
83
+ (1 << @nbits) - 1
84
+ end
77
85
  end
78
86
 
79
87
  def some_values_within_range
@@ -89,21 +97,31 @@ module AllBitfields
89
97
  end
90
98
  end
91
99
 
92
- def generate_bit_classes_to_test(endian)
100
+ def generate_bit_classes_to_test(endian, signed)
93
101
  bits = {}
94
- (1 .. 50).each do |nbits|
95
- name = (endian == :big) ? "Bit#{nbits}" : "Bit#{nbits}le"
102
+ if signed
103
+ base = "Sbit"
104
+ start = 2
105
+ else
106
+ base = "Bit"
107
+ start = 1
108
+ end
109
+
110
+ (start .. 50).each do |nbits|
111
+ name = "#{base}#{nbits}"
112
+ name << "le" if endian == :little
96
113
  bit_class = BinData.const_get(name)
97
114
  bits[bit_class] = nbits
98
115
  end
99
116
  bits
100
117
  end
101
118
 
102
- describe "Big endian bitfields" do
119
+ describe "Unsigned big endian bitfields" do
103
120
  include AllBitfields
104
121
 
105
122
  before do
106
- @bits = generate_bit_classes_to_test(:big)
123
+ @signed = false
124
+ @bits = generate_bit_classes_to_test(:big, @signed)
107
125
  end
108
126
 
109
127
  it "read big endian values" do
@@ -116,11 +134,48 @@ describe "Big endian bitfields" do
116
134
  end
117
135
  end
118
136
 
119
- describe "Little endian bitfields" do
137
+ describe "Signed big endian bitfields" do
138
+ include AllBitfields
139
+
140
+ before do
141
+ @signed = true
142
+ @bits = generate_bit_classes_to_test(:big, @signed)
143
+ end
144
+
145
+ it "read big endian values" do
146
+ @bits.each_pair do |bit_class, nbits|
147
+ nbytes = (nbits + 7) / 8
148
+ str = [0b0100_0000].pack("C") + "\000" * (nbytes - 1)
149
+
150
+ bit_class.read(str).must_equal 1 << (nbits - 2)
151
+ end
152
+ end
153
+ end
154
+
155
+ describe "Unsigned little endian bitfields" do
120
156
  include AllBitfields
121
157
 
122
158
  before do
123
- @bits = generate_bit_classes_to_test(:little)
159
+ @signed = false
160
+ @bits = generate_bit_classes_to_test(:little, @signed)
161
+ end
162
+
163
+ it "read little endian values" do
164
+ @bits.each_pair do |bit_class, nbits|
165
+ nbytes = (nbits + 7) / 8
166
+ str = [0b0000_0001].pack("C") + "\000" * (nbytes - 1)
167
+
168
+ bit_class.read(str).must_equal 1
169
+ end
170
+ end
171
+ end
172
+
173
+ describe "Signed little endian bitfields" do
174
+ include AllBitfields
175
+
176
+ before do
177
+ @signed = true
178
+ @bits = generate_bit_classes_to_test(:little, @signed)
124
179
  end
125
180
 
126
181
  it "read little endian values" do
@@ -160,4 +215,3 @@ describe "Bits of size 1" do
160
215
  end
161
216
  end
162
217
  end
163
-
@@ -92,6 +92,7 @@ describe BinData::Registry, "with numerics" do
92
92
 
93
93
  it "lookup bits" do
94
94
  r.lookup("bit5").to_s.must_equal "BinData::Bit5"
95
+ r.lookup("sbit5").to_s.must_equal "BinData::Sbit5"
95
96
  r.lookup("bit6le").to_s.must_equal "BinData::Bit6le"
96
97
  end
97
98
 
@@ -101,6 +102,13 @@ describe BinData::Registry, "with numerics" do
101
102
  r.lookup("bit2", :little).to_s.must_equal "BinData::Bit2"
102
103
  r.lookup("bit3le", :little).to_s.must_equal "BinData::Bit3le"
103
104
  end
105
+
106
+ it "lookup signed bits by ignoring endian" do
107
+ r.lookup("sbit2", :big).to_s.must_equal "BinData::Sbit2"
108
+ r.lookup("sbit3le", :big).to_s.must_equal "BinData::Sbit3le"
109
+ r.lookup("sbit2", :little).to_s.must_equal "BinData::Sbit2"
110
+ r.lookup("sbit3le", :little).to_s.must_equal "BinData::Sbit3le"
111
+ end
104
112
  end
105
113
 
106
114
  describe BinData::Registry, "with endian specific types" do
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bindata
3
3
  version: !ruby/object:Gem::Version
4
- hash: 55
4
+ hash: 53
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 8
9
- - 0
10
- version: 1.8.0
9
+ - 1
10
+ version: 1.8.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Dion Mendel
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2014-01-06 00:00:00 +08:00
18
+ date: 2014-01-15 00:00:00 +08:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency