bindata 2.2.0 → 2.3.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.

@@ -135,11 +135,12 @@ module BinData
135
135
 
136
136
  def parser_abilities
137
137
  @abilities ||= {
138
- :struct => [:to_struct_params, [:multiple_fields, :optional_fieldnames, :hidden_fields]],
139
- :array => [:to_array_params, [:multiple_fields, :optional_fieldnames]],
140
- :buffer => [:to_array_params, [:multiple_fields, :optional_fieldnames, :hidden_fields]],
141
- :choice => [:to_choice_params, [:multiple_fields, :all_or_none_fieldnames, :fieldnames_are_values]],
142
- :primitive => [:to_struct_params, [:multiple_fields, :optional_fieldnames]]
138
+ :struct => [:to_struct_params, [:multiple_fields, :optional_fieldnames, :hidden_fields]],
139
+ :array => [:to_array_params, [:multiple_fields, :optional_fieldnames]],
140
+ :buffer => [:to_array_params, [:multiple_fields, :optional_fieldnames, :hidden_fields]],
141
+ :choice => [:to_choice_params, [:multiple_fields, :all_or_none_fieldnames, :fieldnames_are_values]],
142
+ :delayed_io => [:to_array_params, [:multiple_fields, :optional_fieldnames, :hidden_fields]],
143
+ :primitive => [:to_struct_params, [:multiple_fields, :optional_fieldnames]]
143
144
  }
144
145
  end
145
146
 
@@ -153,10 +154,7 @@ module BinData
153
154
  end
154
155
 
155
156
  def hints
156
- {
157
- :endian => endian,
158
- :search_prefix => search_prefix,
159
- }
157
+ { :endian => endian, :search_prefix => search_prefix }
160
158
  end
161
159
 
162
160
  def set_endian(endian)
@@ -185,7 +183,7 @@ module BinData
185
183
  end
186
184
 
187
185
  def has_fields?
188
- @fields && @fields.length > 0
186
+ defined? @fields and @fields.length > 0
189
187
  end
190
188
 
191
189
  def parse_and_append_field(*args, &block)
@@ -289,7 +287,7 @@ module BinData
289
287
  }
290
288
  bnl_class.define_singleton_method(:new) do |*args|
291
289
  if self == bnl_class
292
- value, options, parent = arg_processor.separate_args(self, args)
290
+ _, options, _ = arg_processor.separate_args(self, args)
293
291
  delegate = endian_classes[options[:endian]]
294
292
  return delegate.new(*args) if delegate
295
293
  end
@@ -339,13 +337,8 @@ module BinData
339
337
  RegisteredClasses.lookup(class_name, hints)
340
338
  end
341
339
 
342
- def obj_attribute(obj, attr, default = nil)
343
- parser = obj.respond_to?(:dsl_parser) ? obj.dsl_parser : nil
344
- if parser and parser.respond_to?(attr)
345
- parser.send(attr)
346
- else
347
- default
348
- end
340
+ def obj_attribute(obj, attr)
341
+ obj.dsl_parser.send(attr)
349
342
  end
350
343
  end
351
344
  end
@@ -362,7 +355,7 @@ module BinData
362
355
  attr_reader :type, :name, :params
363
356
 
364
357
  def name_from_field_declaration(args)
365
- name, params = args
358
+ name, _ = args
366
359
  if name == "" or name.is_a?(Hash)
367
360
  nil
368
361
  else
@@ -389,10 +382,11 @@ module BinData
389
382
 
390
383
  def params_from_block(&block)
391
384
  bindata_classes = {
392
- :array => BinData::Array,
393
- :buffer => BinData::Buffer,
394
- :choice => BinData::Choice,
395
- :struct => BinData::Struct
385
+ :array => BinData::Array,
386
+ :buffer => BinData::Buffer,
387
+ :choice => BinData::Choice,
388
+ :delayed_io => BinData::DelayedIO,
389
+ :struct => BinData::Struct
396
390
  }
397
391
 
398
392
  if bindata_classes.include?(@type)
@@ -47,6 +47,11 @@ module BinData
47
47
  0
48
48
  end
49
49
 
50
+ # Is this object aligned on non-byte boundaries?
51
+ def bit_aligned?
52
+ false
53
+ end
54
+
50
55
  # Reads the data for this data object from +io+.
51
56
  def do_read(io) #:nodoc:
52
57
  raise NotImplementedError
@@ -104,7 +104,7 @@ module BinData
104
104
  end
105
105
  parts[0].sub!(/ << 0\b/, "") # Remove " << 0" for optimisation
106
106
 
107
- assemble_str = parts.join(" + ")
107
+ parts.join(" + ")
108
108
  end
109
109
 
110
110
  def create_to_binary_s_code(nbits, endian, signed)
@@ -4,6 +4,147 @@ module BinData
4
4
  # A wrapper around an IO object. The wrapper provides a consistent
5
5
  # interface for BinData objects to use when accessing the IO.
6
6
  module IO
7
+
8
+ # Common operations for both Read and Write.
9
+ module Common
10
+ def initialize(io)
11
+ if self.class === io
12
+ raise ArgumentError, "io must not be a #{self.class}"
13
+ end
14
+
15
+ # wrap strings in a StringIO
16
+ if io.respond_to?(:to_str)
17
+ io = BinData::IO.create_string_io(io.to_str)
18
+ end
19
+
20
+ @raw_io = io
21
+ @buffer_end_pos = nil
22
+
23
+ extend seekable? ? SeekableStream : UnSeekableStream
24
+ stream_init
25
+ end
26
+
27
+ #-------------
28
+ private
29
+
30
+ def seekable?
31
+ @raw_io.pos
32
+ rescue NoMethodError, Errno::ESPIPE, Errno::EPIPE
33
+ nil
34
+ end
35
+
36
+ def seek(n)
37
+ seek_raw(buffer_limited_n(n))
38
+ end
39
+
40
+ def buffer_limited_n(n)
41
+ if @buffer_end_pos
42
+ if n.nil? or n > 0
43
+ max = @buffer_end_pos[1] - offset
44
+ n = max if n.nil? or n > max
45
+ else
46
+ min = @buffer_end_pos[0] - offset
47
+ n = min if n < min
48
+ end
49
+ end
50
+
51
+ n
52
+ end
53
+
54
+ def with_buffer_common(n, &block)
55
+ prev = @buffer_end_pos
56
+ if prev
57
+ avail = prev[1] - offset
58
+ n = avail if n > avail
59
+ end
60
+ @buffer_end_pos = [offset, offset + n]
61
+ begin
62
+ block.call(*@buffer_end_pos)
63
+ ensure
64
+ @buffer_end_pos = prev
65
+ end
66
+ end
67
+
68
+ # Use #seek and #pos on seekable streams
69
+ module SeekableStream
70
+ # The number of bytes remaining in the input stream.
71
+ def num_bytes_remaining
72
+ mark = @raw_io.pos
73
+ @raw_io.seek(0, ::IO::SEEK_END)
74
+ bytes_remaining = @raw_io.pos - mark
75
+ @raw_io.seek(mark, ::IO::SEEK_SET)
76
+
77
+ bytes_remaining
78
+ end
79
+
80
+ #-----------
81
+ private
82
+
83
+ def stream_init
84
+ @initial_pos = @raw_io.pos
85
+ end
86
+
87
+ def offset_raw
88
+ @raw_io.pos - @initial_pos
89
+ end
90
+
91
+ def seek_raw(n)
92
+ @raw_io.seek(n, ::IO::SEEK_CUR)
93
+ end
94
+
95
+ def read_raw(n)
96
+ @raw_io.read(n)
97
+ end
98
+
99
+ def write_raw(data)
100
+ @raw_io.write(data)
101
+ end
102
+ end
103
+
104
+ # Manually keep track of offset for unseekable streams.
105
+ module UnSeekableStream
106
+ def offset_raw
107
+ @offset
108
+ end
109
+
110
+ # The number of bytes remaining in the input stream.
111
+ def num_bytes_remaining
112
+ raise IOError, "stream is unseekable"
113
+ end
114
+
115
+ #-----------
116
+ private
117
+
118
+ def stream_init
119
+ @offset = 0
120
+ end
121
+
122
+ def read_raw(n)
123
+ data = @raw_io.read(n)
124
+ @offset += data.size if data
125
+ data
126
+ end
127
+
128
+ def write_raw(data)
129
+ @offset += data.size
130
+ @raw_io.write(data)
131
+ end
132
+
133
+ def seek_raw(n)
134
+ raise IOError, "stream is unseekable" if n < 0
135
+
136
+ # NOTE: how do we seek on a writable stream?
137
+
138
+ # skip over data in 8k blocks
139
+ while n > 0
140
+ bytes_to_read = [n, 8192].min
141
+ read_raw(bytes_to_read)
142
+ n -= bytes_to_read
143
+ end
144
+ end
145
+ end
146
+ end
147
+
7
148
  # Creates a StringIO around +str+.
8
149
  def self.create_string_io(str = "")
9
150
  StringIO.new(str.dup.force_encoding(Encoding::BINARY))
@@ -27,43 +168,32 @@ module BinData
27
168
  # readbits(6), readbits(5) #=> [543210, a9876]
28
169
  #
29
170
  class Read
30
- def initialize(io)
31
- raise ArgumentError, "io must not be a BinData::IO::Read" if BinData::IO::Read === io
32
-
33
- # wrap strings in a StringIO
34
- if io.respond_to?(:to_str)
35
- io = BinData::IO.create_string_io(io.to_str)
36
- end
171
+ include Common
37
172
 
38
- @raw_io = io
173
+ def initialize(io)
174
+ super(io)
39
175
 
40
176
  # bits when reading
41
177
  @rnbits = 0
42
178
  @rval = 0
43
179
  @rendian = nil
44
-
45
- @buffer_end_pos = nil
46
-
47
- extend seekable? ? SeekableStream : UnSeekableStream
48
180
  end
49
181
 
50
182
  # Sets a buffer of +n+ bytes on the io stream. Any reading or seeking
51
183
  # calls inside the +block+ will be contained within this buffer.
52
184
  def with_buffer(n, &block)
53
- prev = @buffer_end_pos
54
- if prev
55
- avail = prev - offset
56
- n = avail if n > avail
57
- end
58
- @buffer_end_pos = offset + n
59
- begin
185
+ with_buffer_common(n) do
60
186
  block.call
61
187
  read
62
- ensure
63
- @buffer_end_pos = prev
64
188
  end
65
189
  end
66
190
 
191
+ # Returns the current offset of the io stream. Offset will be rounded
192
+ # up when reading bitfields.
193
+ def offset
194
+ offset_raw
195
+ end
196
+
67
197
  # Seek +n+ bytes from the current position in the io stream.
68
198
  def seekbytes(n)
69
199
  reset_read_bits
@@ -116,29 +246,10 @@ module BinData
116
246
  #---------------
117
247
  private
118
248
 
119
- def seekable?
120
- @raw_io.pos
121
- rescue NoMethodError, Errno::ESPIPE, Errno::EPIPE
122
- nil
123
- end
124
-
125
- def seek(n)
126
- seek_raw(buffer_limited_n(n))
127
- end
128
-
129
249
  def read(n = nil)
130
250
  read_raw(buffer_limited_n(n))
131
251
  end
132
252
 
133
- def buffer_limited_n(n)
134
- if @buffer_end_pos
135
- max = @buffer_end_pos - offset
136
- n = max if n.nil? or n > max
137
- end
138
-
139
- n
140
- end
141
-
142
253
  def read_big_endian_bits(nbits)
143
254
  while @rnbits < nbits
144
255
  accumulate_big_endian_bits
@@ -184,77 +295,6 @@ module BinData
184
295
  def mask(nbits)
185
296
  (1 << nbits) - 1
186
297
  end
187
-
188
- # Use #seek and #pos on seekable streams
189
- module SeekableStream
190
- # Returns the current offset of the io stream. Offset will be rounded
191
- # up when reading bitfields.
192
- def offset
193
- raw_io.pos - @initial_pos
194
- end
195
-
196
- # The number of bytes remaining in the input stream.
197
- def num_bytes_remaining
198
- mark = raw_io.pos
199
- raw_io.seek(0, ::IO::SEEK_END)
200
- bytes_remaining = raw_io.pos - mark
201
- raw_io.seek(mark, ::IO::SEEK_SET)
202
-
203
- bytes_remaining
204
- end
205
-
206
- #-----------
207
- private
208
-
209
- def read_raw(n)
210
- raw_io.read(n)
211
- end
212
-
213
- def seek_raw(n)
214
- raw_io.seek(n, ::IO::SEEK_CUR)
215
- end
216
-
217
- def raw_io
218
- @initial_pos ||= @raw_io.pos
219
- @raw_io
220
- end
221
- end
222
-
223
- # Manually keep track of offset for unseekable streams.
224
- module UnSeekableStream
225
- # Returns the current offset of the io stream. Offset will be rounded
226
- # up when reading bitfields.
227
- def offset
228
- @read_count ||= 0
229
- end
230
-
231
- # The number of bytes remaining in the input stream.
232
- def num_bytes_remaining
233
- raise IOError, "stream is unseekable"
234
- end
235
-
236
- #-----------
237
- private
238
-
239
- def read_raw(n)
240
- @read_count ||= 0
241
-
242
- data = @raw_io.read(n)
243
- @read_count += data.size if data
244
- data
245
- end
246
-
247
- def seek_raw(n)
248
- raise IOError, "stream is unseekable" if n < 0
249
-
250
- # skip over data in 8k blocks
251
- while n > 0
252
- bytes_to_read = [n, 8192].min
253
- read_raw(bytes_to_read)
254
- n -= bytes_to_read
255
- end
256
- end
257
- end
258
298
  end
259
299
 
260
300
  # Create a new IO Write wrapper around +io+. +io+ must provide #write.
@@ -265,25 +305,13 @@ module BinData
265
305
  #
266
306
  # See IO::Read for more information.
267
307
  class Write
308
+ include Common
268
309
  def initialize(io)
269
- if BinData::IO::Write === io
270
- raise ArgumentError, "io must not be a BinData::IO::Write"
271
- end
272
-
273
- # wrap strings in a StringIO
274
- if io.respond_to?(:to_str)
275
- io = BinData::IO.create_string_io(io.to_str)
276
- end
277
-
278
- @raw_io = io
310
+ super(io)
279
311
 
280
312
  @wnbits = 0
281
313
  @wval = 0
282
314
  @wendian = nil
283
-
284
- @write_count = 0
285
-
286
- @bytes_remaining = nil
287
315
  end
288
316
 
289
317
  # Sets a buffer of +n+ bytes on the io stream. Any writes inside the
@@ -291,31 +319,28 @@ module BinData
291
319
  # are written inside the block, the remainder will be padded with '\0'
292
320
  # bytes.
293
321
  def with_buffer(n, &block)
294
- prev = @bytes_remaining
295
- if prev
296
- n = prev if n > prev
297
- prev -= n
298
- end
299
-
300
- @bytes_remaining = n
301
- begin
322
+ with_buffer_common(n) do |buf_start, buf_end|
302
323
  block.call
303
- write_raw("\0" * @bytes_remaining)
304
- ensure
305
- @bytes_remaining = prev
324
+ write("\0" * (buf_end - offset))
306
325
  end
307
326
  end
308
327
 
309
328
  # Returns the current offset of the io stream. Offset will be rounded
310
329
  # up when writing bitfields.
311
330
  def offset
312
- @write_count + (@wnbits > 0 ? 1 : 0)
331
+ offset_raw + (@wnbits > 0 ? 1 : 0)
332
+ end
333
+
334
+ # Seek +n+ bytes from the current position in the io stream.
335
+ def seekbytes(n)
336
+ flushbits
337
+ seek(n)
313
338
  end
314
339
 
315
340
  # Writes the given string of bytes to the io stream.
316
341
  def writebytes(str)
317
342
  flushbits
318
- write_raw(str)
343
+ write(str)
319
344
  end
320
345
 
321
346
  # Writes +nbits+ bits from +val+ to the stream. +endian+ specifies whether
@@ -349,6 +374,15 @@ module BinData
349
374
  #---------------
350
375
  private
351
376
 
377
+ def write(data)
378
+ n = buffer_limited_n(data.size)
379
+ if n < data.size
380
+ data = data[0, n]
381
+ end
382
+
383
+ write_raw(data)
384
+ end
385
+
352
386
  def write_big_endian_bits(val, nbits)
353
387
  while nbits > 0
354
388
  bits_req = 8 - @wnbits
@@ -358,7 +392,7 @@ module BinData
358
392
  val &= mask(nbits)
359
393
 
360
394
  @wval = (@wval << bits_req) | msb_bits
361
- write_raw(@wval.chr)
395
+ write(@wval.chr)
362
396
 
363
397
  @wval = 0
364
398
  @wnbits = 0
@@ -379,7 +413,7 @@ module BinData
379
413
  val >>= bits_req
380
414
 
381
415
  @wval = @wval | (lsb_bits << @wnbits)
382
- write_raw(@wval.chr)
416
+ write(@wval.chr)
383
417
 
384
418
  @wval = 0
385
419
  @wnbits = 0
@@ -391,18 +425,6 @@ module BinData
391
425
  end
392
426
  end
393
427
 
394
- def write_raw(data)
395
- if @bytes_remaining
396
- if data.size > @bytes_remaining
397
- data = data[0, @bytes_remaining]
398
- end
399
- @bytes_remaining -= data.size
400
- end
401
-
402
- @write_count += data.size
403
- @raw_io.write(data)
404
- end
405
-
406
428
  def mask(nbits)
407
429
  (1 << nbits) - 1
408
430
  end