bindata 0.9.0 → 0.9.1

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/spec/array_spec.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require File.expand_path(File.dirname(__FILE__)) + '/spec_common'
4
4
  require 'bindata/array'
5
+ require 'bindata/bits'
5
6
  require 'bindata/int'
6
7
  require 'bindata/struct'
7
8
 
@@ -266,3 +267,39 @@ describe BinData::Array, "with :read_until containing +array+ and +index+" do
266
267
  @data.length.should == 7
267
268
  end
268
269
  end
270
+
271
+ describe BinData::Array, "of bits" do
272
+ before(:each) do
273
+ @data = BinData::Array.new(:type => :bit1, :initial_length => 15)
274
+ end
275
+
276
+ it "should read" do
277
+ str = [0b0001_0100, 0b1000_1000].pack("CC")
278
+ @data.read(str)
279
+ @data[0].should == 0
280
+ @data[1].should == 0
281
+ @data[2].should == 0
282
+ @data[3].should == 1
283
+ @data[4].should == 0
284
+ @data[5].should == 1
285
+ @data[6].should == 0
286
+ @data[7].should == 0
287
+ @data[8].should == 1
288
+ @data[9].should == 0
289
+ @data[10].should == 0
290
+ @data[11].should == 0
291
+ @data[12].should == 1
292
+ @data[13].should == 0
293
+ @data[14].should == 0
294
+ end
295
+
296
+ it "should write" do
297
+ @data[3] = 1
298
+ @data.to_s.should == [0b0001_0000, 0b0000_0000].pack("CC")
299
+ end
300
+
301
+ it "should return num_bytes" do
302
+ @data.num_bytes.should == 2
303
+ end
304
+ end
305
+
data/spec/base_spec.rb CHANGED
@@ -5,13 +5,13 @@ require 'bindata/base'
5
5
 
6
6
  class BaseStub < BinData::Base
7
7
  def clear; end
8
- def _do_read(io) end
9
- def done_read; end
10
- def _write(io) end
11
- def _num_bytes; end
12
- def snapshot; end
13
8
  def single_value?; end
14
9
  def field_names; end
10
+ def snapshot; end
11
+ def done_read; end
12
+ def _do_read(io) end
13
+ def _do_write(io) end
14
+ def _do_num_bytes; end
15
15
  end
16
16
 
17
17
  describe BinData::Base, "with mandatory parameters" do
@@ -142,7 +142,7 @@ describe BinData::Base, "with :check_offset" do
142
142
  class TenByteOffsetBase < BaseStub
143
143
  def do_read(io)
144
144
  # advance the io position before checking offset
145
- io.seek(10, IO::SEEK_CUR)
145
+ io.seekbytes(10)
146
146
  super(io)
147
147
  end
148
148
  end
@@ -184,7 +184,7 @@ describe BinData::Base, "with :adjust_offset" do
184
184
  class TenByteAdjustingOffsetBase < BaseStub
185
185
  def do_read(io)
186
186
  # advance the io position before checking offset
187
- io.seek(10, IO::SEEK_CUR)
187
+ io.seekbytes(10)
188
188
  super(io)
189
189
  end
190
190
  end
@@ -226,8 +226,8 @@ describe BinData::Base, "with :readwrite => false" do
226
226
  class NoIOBase < BaseStub
227
227
  attr_accessor :mock
228
228
  def _do_read(io) mock._do_read(io); end
229
- def _write(io) mock._write(io); end
230
- def _num_bytes; mock._num_bytes; end
229
+ def _do_write(io) mock._do_write(io); end
230
+ def _do_num_bytes; mock._do_num_bytes; end
231
231
  end
232
232
  END
233
233
  end
@@ -250,16 +250,33 @@ describe BinData::Base, "with :readwrite => false" do
250
250
  end
251
251
 
252
252
  it "should have zero num_bytes" do
253
- @obj.mock.should_not_receive(:_num_bytes)
253
+ @obj.mock.should_not_receive(:_do_num_bytes)
254
254
  @obj.num_bytes.should be_zero
255
255
  end
256
256
  end
257
257
 
258
+ describe BinData::Base, "with :onlyif" do
259
+ before(:all) do
260
+ eval <<-END
261
+ class OnlyIfBase < BinData::Base
262
+ public :has_param?, :param
263
+ end
264
+ END
265
+ end
266
+
267
+ it "should alias to :readwrite" do
268
+ obj = OnlyIfBase.new(:onlyif => "a")
269
+ obj.should_not have_param(:onlyif)
270
+ obj.should have_param(:readwrite)
271
+ obj.param(:readwrite).should == "a"
272
+ end
273
+ end
274
+
258
275
  describe BinData::Base, "when subclassing" do
259
276
  before(:all) do
260
277
  eval <<-END
261
278
  class SubClassOfBase < BinData::Base
262
- public :_do_read, :_write, :_num_bytes
279
+ public :_do_read, :_do_write, :_do_num_bytes
263
280
  end
264
281
  END
265
282
  end
@@ -273,13 +290,13 @@ describe BinData::Base, "when subclassing" do
273
290
  SubClassOfBase.all_possible_field_names(nil)
274
291
  }.should raise_error(NotImplementedError)
275
292
  lambda { @obj.clear }.should raise_error(NotImplementedError)
276
- lambda { @obj._do_read(nil) }.should raise_error(NotImplementedError)
277
- lambda { @obj.done_read }.should raise_error(NotImplementedError)
278
- lambda { @obj._write(nil) }.should raise_error(NotImplementedError)
279
- lambda { @obj._num_bytes }.should raise_error(NotImplementedError)
280
- lambda { @obj.snapshot }.should raise_error(NotImplementedError)
281
293
  lambda { @obj.single_value? }.should raise_error(NotImplementedError)
282
294
  lambda { @obj.field_names }.should raise_error(NotImplementedError)
295
+ lambda { @obj.snapshot }.should raise_error(NotImplementedError)
296
+ lambda { @obj.done_read }.should raise_error(NotImplementedError)
297
+ lambda { @obj._do_read(nil) }.should raise_error(NotImplementedError)
298
+ lambda { @obj._do_write(nil) }.should raise_error(NotImplementedError)
299
+ lambda { @obj._do_num_bytes }.should raise_error(NotImplementedError)
283
300
  end
284
301
  end
285
302
 
@@ -323,7 +340,7 @@ describe BinData::Base do
323
340
  eval <<-END
324
341
  class InstanceOfBase < BaseStub
325
342
  def snapshot; 123; end
326
- def _write(io); io.write('456'); end
343
+ def _do_write(io); io.writebytes('456'); end
327
344
  end
328
345
  END
329
346
  end
data/spec/bits_spec.rb ADDED
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(File.dirname(__FILE__)) + '/spec_common'
4
+ require 'bindata/bits'
5
+
6
+ describe "Bits of size 1" do
7
+ it "should accept true as value" do
8
+ obj = BinData::Bit1.new
9
+ obj.value = true
10
+ obj.value.should == 1
11
+
12
+ obj = BinData::Bit1le.new
13
+ obj.value = true
14
+ obj.value.should == 1
15
+ end
16
+
17
+ it "should accept false as value" do
18
+ obj = BinData::Bit1.new
19
+ obj.value = false
20
+ obj.value.should == 0
21
+
22
+ obj = BinData::Bit1le.new
23
+ obj.value = false
24
+ obj.value.should == 0
25
+ end
26
+
27
+ it "should accept nil as value" do
28
+ obj = BinData::Bit1.new
29
+ obj.value = nil
30
+ obj.value.should == 0
31
+
32
+ obj = BinData::Bit1le.new
33
+ obj.value = nil
34
+ obj.value.should == 0
35
+ end
36
+ end
37
+
38
+ describe "All bitfields" do
39
+ it "should have a sensible value of zero" do
40
+ begin
41
+ nbits = 1
42
+ loop do
43
+ ["", "le"].each do |suffix|
44
+ klass = BinData.const_get("Bit#{nbits}#{suffix}")
45
+ klass.new.value.should be_zero
46
+ end
47
+
48
+ nbits += 1
49
+ end
50
+ rescue NameError
51
+ end
52
+ end
53
+
54
+ it "should clamp " do
55
+ begin
56
+ nbits = 1
57
+ loop do
58
+ ["", "le"].each do |suffix|
59
+ klass = BinData.const_get("Bit#{nbits}#{suffix}")
60
+ obj = klass.new
61
+
62
+ obj.value = -1
63
+ obj.value.should == 0
64
+
65
+ obj.value = 1 << nbits
66
+ obj.value.should == ((1 << nbits) - 1)
67
+ end
68
+
69
+ nbits += 1
70
+ end
71
+ rescue NameError
72
+ end
73
+ end
74
+
75
+ it "should read big endian value" do
76
+ begin
77
+ nbits = 1
78
+ loop do
79
+ klass = BinData.const_get("Bit#{nbits}")
80
+ obj = klass.new
81
+
82
+ str = [0b1000_0000].pack("C") + "\000" * (nbits / 8)
83
+ obj.read(str)
84
+ obj.value.should == 1 << (nbits - 1)
85
+
86
+ nbits += 1
87
+ end
88
+ rescue NameError
89
+ end
90
+ end
91
+
92
+ it "should read little endian value" do
93
+ begin
94
+ nbits = 1
95
+ loop do
96
+ klass = BinData.const_get("Bit#{nbits}le")
97
+ obj = klass.new
98
+
99
+ str = [0b0000_0001].pack("C") + "\000" * (nbits / 8)
100
+ obj.read(str)
101
+ obj.value.should == 1
102
+
103
+ nbits += 1
104
+ end
105
+ rescue NameError
106
+ end
107
+ end
108
+
109
+ it "should read written values" do
110
+ begin
111
+ nbits = 1
112
+ loop do
113
+ ["", "le"].each do |suffix|
114
+ klass = BinData.const_get("Bit#{nbits}#{suffix}")
115
+
116
+ min = 0
117
+ max = (1 << nbits) - 1
118
+ range = [min .. max]
119
+
120
+ values = []
121
+ values << (min + 1) if range.include?(min + 1)
122
+ values << (min + 3) if range.include?(min + 3)
123
+ values << (max - 1) if range.include?(max - 1)
124
+
125
+ value.each do |val|
126
+ obj = klass.new
127
+ obj.value = val
128
+ str = obj.to_s
129
+ obj.read(str)
130
+ obj.value.should == val
131
+ end
132
+ end
133
+
134
+ nbits += 1
135
+ end
136
+ rescue NameError
137
+ end
138
+ end
139
+ end
data/spec/io_spec.rb ADDED
@@ -0,0 +1,288 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(File.dirname(__FILE__)) + '/spec_common'
4
+ require 'bindata/io'
5
+
6
+ describe BinData::IO do
7
+ it "should wrap strings in StringIO" do
8
+ io = BinData::IO.new("abcd")
9
+ io.raw_io.class.should == StringIO
10
+ end
11
+
12
+ it "should not wrap IO objects" do
13
+ stream = StringIO.new
14
+ io = BinData::IO.new(stream)
15
+ io.raw_io.should == stream
16
+ end
17
+
18
+ it "should raise error when io is BinData::IO" do
19
+ lambda {
20
+ io = BinData::IO.new(BinData::IO.new(""))
21
+ }.should raise_error(ArgumentError)
22
+ end
23
+
24
+ it "should return correct offset" do
25
+ stream = StringIO.new("abcdefghij")
26
+ stream.seek(3, IO::SEEK_CUR)
27
+
28
+ io = BinData::IO.new(stream)
29
+ io.offset.should == 0
30
+ io.readbytes(4)
31
+ io.offset.should == 4
32
+ end
33
+
34
+ it "should seek" do
35
+ stream = StringIO.new("abcdefghij")
36
+ io = BinData::IO.new(stream)
37
+
38
+ io.seekbytes(2)
39
+ io.readbytes(4).should == "cdef"
40
+ end
41
+
42
+ it "should raise error when reading at eof" do
43
+ stream = StringIO.new("abcdefghij")
44
+ io = BinData::IO.new(stream)
45
+ io.seekbytes(10)
46
+ lambda {
47
+ io.readbytes(3)
48
+ }.should raise_error(EOFError)
49
+ end
50
+
51
+ it "should raise error on short reads" do
52
+ stream = StringIO.new("abcdefghij")
53
+ io = BinData::IO.new(stream)
54
+ lambda {
55
+ io.readbytes(20)
56
+ }.should raise_error(IOError)
57
+ end
58
+
59
+ it "should write" do
60
+ stream = StringIO.new
61
+ io = BinData::IO.new(stream)
62
+ io.writebytes("abcd")
63
+
64
+ stream.rewind
65
+ stream.read.should == "abcd"
66
+ end
67
+ end
68
+
69
+ describe BinData::IO, "reading bits in big endian" do
70
+ before(:each) do
71
+ @b1 = 0b1111_1010
72
+ @b2 = 0b1100_1110
73
+ @b3 = 0b0110_1010
74
+ str = [@b1, @b2, @b3].pack("CCC")
75
+ @io = BinData::IO.new(str)
76
+ end
77
+
78
+ it "should read a bitfield less than 1 byte" do
79
+ @io.readbits(3).should == 0b111
80
+ end
81
+
82
+ it "should read a bitfield more than 1 byte" do
83
+ @io.readbits(10).should == 0b1111_1010_11
84
+ end
85
+
86
+ it "should read a bitfield more than 2 bytes" do
87
+ @io.readbits(17).should == 0b1111_1010_1100_1110_0
88
+ end
89
+
90
+ it "should read two bitfields totalling less than 1 byte" do
91
+ @io.readbits(5).should == 0b1111_1
92
+ @io.readbits(2).should == 0b01
93
+ end
94
+
95
+ it "should read two bitfields totalling more than 1 byte" do
96
+ @io.readbits(6).should == 0b1111_10
97
+ @io.readbits(8).should == 0b10_1100_11
98
+ end
99
+
100
+ it "should read two bitfields totalling more than 2 bytes" do
101
+ @io.readbits(7).should == 0b1111_101
102
+ @io.readbits(12).should == 0b0_1100_1110_011
103
+ end
104
+
105
+ it "should ignore unused bits when reading bytes" do
106
+ @io.readbits(3).should == 0b111
107
+ @io.readbytes(1).should == [@b2].pack("C")
108
+ @io.readbits(2).should == 0b01
109
+ end
110
+ end
111
+
112
+ describe BinData::IO, "reading bits in little endian" do
113
+ before(:each) do
114
+ @b1 = 0b1111_1010
115
+ @b2 = 0b1100_1110
116
+ @b3 = 0b0110_1010
117
+ str = [@b1, @b2, @b3].pack("CCC")
118
+ @io = BinData::IO.new(str)
119
+ end
120
+
121
+ it "should read a bitfield less than 1 byte" do
122
+ @io.readbits(3, :little).should == 0b010
123
+ end
124
+
125
+ it "should read a bitfield more than 1 byte" do
126
+ @io.readbits(10, :little).should == 0b10_1111_1010
127
+ end
128
+
129
+ it "should read a bitfield more than 2 bytes" do
130
+ @io.readbits(17, :little).should == 0b0_1100_1110_1111_1010
131
+ end
132
+
133
+ it "should read two bitfields totalling less than 1 byte" do
134
+ @io.readbits(5, :little).should == 0b1_1010
135
+ @io.readbits(2, :little).should == 0b11
136
+ end
137
+
138
+ it "should read two bitfields totalling more than 1 byte" do
139
+ @io.readbits(6, :little).should == 0b11_1010
140
+ @io.readbits(8, :little).should == 0b00_1110_11
141
+ end
142
+
143
+ it "should read two bitfields totalling more than 2 bytes" do
144
+ @io.readbits(7, :little).should == 0b111_1010
145
+ @io.readbits(12, :little).should == 0b010_1100_1110_1
146
+ end
147
+
148
+ it "should ignore unused bits when reading bytes" do
149
+ @io.readbits(3, :little).should == 0b010
150
+ @io.readbytes(1).should == [@b2].pack("C")
151
+ @io.readbits(2, :little).should == 0b10
152
+ end
153
+ end
154
+
155
+ class BitWriterHelper
156
+ def initialize
157
+ @stringio = StringIO.new
158
+ @io = BinData::IO.new(@stringio)
159
+ end
160
+
161
+ def writebits(val, nbits, endian = :big)
162
+ @io.writebits(val, nbits, endian)
163
+ end
164
+
165
+ def writebytes(val)
166
+ @io.writebytes(val)
167
+ end
168
+
169
+ def value
170
+ @io.flushbits
171
+ @stringio.rewind
172
+ @stringio.read
173
+ end
174
+ end
175
+
176
+ describe BinData::IO, "writing bits in big endian" do
177
+ before(:each) do
178
+ @io = BitWriterHelper.new
179
+ end
180
+
181
+ it "should write a bitfield less than 1 byte" do
182
+ @io.writebits(0b010, 3)
183
+ @io.value.should == [0b0100_0000].pack("C")
184
+ end
185
+
186
+ it "should write a bitfield more than 1 byte" do
187
+ @io.writebits(0b10_1001_1101, 10)
188
+ @io.value.should == [0b1010_0111, 0b0100_0000].pack("CC")
189
+ end
190
+
191
+ it "should write a bitfield more than 2 bytes" do
192
+ @io.writebits(0b101_1000_0010_1001_1101, 19)
193
+ @io.value.should == [0b1011_0000, 0b0101_0011, 0b1010_0000].pack("CCC")
194
+ end
195
+
196
+ it "should write two bitfields totalling less than 1 byte" do
197
+ @io.writebits(0b1_1001, 5)
198
+ @io.writebits(0b00, 2)
199
+ @io.value.should == [0b1100_1000].pack("C")
200
+ end
201
+
202
+ it "should write two bitfields totalling more than 1 byte" do
203
+ @io.writebits(0b01_0101, 6)
204
+ @io.writebits(0b001_1001, 7)
205
+ @io.value.should == [0b0101_0100, 0b1100_1000].pack("CC")
206
+ end
207
+
208
+ it "should write two bitfields totalling more than 2 bytes" do
209
+ @io.writebits(0b01_0111, 6)
210
+ @io.writebits(0b1_0010_1001_1001, 13)
211
+ @io.value.should == [0b0101_1110, 0b0101_0011, 0b0010_0000].pack("CCC")
212
+ end
213
+
214
+ it "should pad unused bits when writing bytes" do
215
+ @io.writebits(0b101, 3)
216
+ @io.writebytes([0b1011_1111].pack("C"))
217
+ @io.writebits(0b01, 2)
218
+
219
+ @io.value.should == [0b1010_0000, 0b1011_1111, 0b0100_0000].pack("CCC")
220
+ end
221
+ end
222
+
223
+ describe BinData::IO, "writing bits in little endian" do
224
+ before(:each) do
225
+ @io = BitWriterHelper.new
226
+ end
227
+
228
+ it "should write a bitfield less than 1 byte" do
229
+ @io.writebits(0b010, 3, :little)
230
+ @io.value.should == [0b0000_0010].pack("C")
231
+ end
232
+
233
+ it "should write a bitfield more than 1 byte" do
234
+ @io.writebits(0b10_1001_1101, 10, :little)
235
+ @io.value.should == [0b1001_1101, 0b0000_0010].pack("CC")
236
+ end
237
+
238
+ it "should write a bitfield more than 2 bytes" do
239
+ @io.writebits(0b101_1000_0010_1001_1101, 19, :little)
240
+ @io.value.should == [0b1001_1101, 0b1000_0010, 0b0000_0101].pack("CCC")
241
+ end
242
+
243
+ it "should write two bitfields totalling less than 1 byte" do
244
+ @io.writebits(0b1_1001, 5, :little)
245
+ @io.writebits(0b00, 2, :little)
246
+ @io.value.should == [0b0001_1001].pack("C")
247
+ end
248
+
249
+ it "should write two bitfields totalling more than 1 byte" do
250
+ @io.writebits(0b01_0101, 6, :little)
251
+ @io.writebits(0b001_1001, 7, :little)
252
+ @io.value.should == [0b0101_0101, 0b0000_0110].pack("CC")
253
+ end
254
+
255
+ it "should write two bitfields totalling more than 2 bytes" do
256
+ @io.writebits(0b01_0111, 6, :little)
257
+ @io.writebits(0b1_0010_1001_1001, 13, :little)
258
+ @io.value.should == [0b0101_0111, 0b1010_0110, 0b0000_0100].pack("CCC")
259
+ end
260
+
261
+ it "should pad unused bits when writing bytes" do
262
+ @io.writebits(0b101, 3, :little)
263
+ @io.writebytes([0b1011_1111].pack("C"))
264
+ @io.writebits(0b01, 2, :little)
265
+
266
+ @io.value.should == [0b0000_0101, 0b1011_1111, 0b0000_0001].pack("CCC")
267
+ end
268
+ end
269
+
270
+ describe BinData::IO, "with changing endian" do
271
+ it "should not mix different endianess when reading" do
272
+ b1 = 0b0110_1010
273
+ b2 = 0b1110_0010
274
+ str = [b1, b2].pack("CC")
275
+ io = BinData::IO.new(str)
276
+
277
+ io.readbits(3, :big).should == 0b011
278
+ io.readbits(4, :little).should == 0b0010
279
+ end
280
+
281
+ it "should not mix different endianess when writing" do
282
+ io = BitWriterHelper.new
283
+ io.writebits(0b110, 3, :big)
284
+ io.writebits(0b010, 3, :little)
285
+ io.value.should == [0b1100_0000, 0b0000_0010].pack("CC")
286
+ end
287
+ end
288
+