bindata 1.8.3 → 2.0.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 +7 -0
- data/.travis.yml +1 -1
- data/ChangeLog.rdoc +5 -14
- data/INSTALL +10 -9
- data/NEWS.rdoc +19 -0
- data/README.md +2 -6
- data/Rakefile +0 -2
- data/bindata.gemspec +0 -3
- data/examples/gzip.rb +70 -106
- data/examples/tcp_ip.rb +8 -10
- data/lib/bindata.rb +4 -0
- data/lib/bindata/base.rb +5 -10
- data/lib/bindata/bits.rb +15 -84
- data/lib/bindata/buffer.rb +1 -1
- data/lib/bindata/choice.rb +24 -8
- data/lib/bindata/deprecated.rb +3 -26
- data/lib/bindata/int.rb +10 -2
- data/lib/bindata/io.rb +5 -17
- data/lib/bindata/lazy.rb +1 -1
- data/lib/bindata/params.rb +1 -1
- data/lib/bindata/record.rb +19 -1
- data/lib/bindata/sanitize.rb +0 -20
- data/lib/bindata/string.rb +4 -5
- data/lib/bindata/struct.rb +23 -124
- data/lib/bindata/version.rb +1 -1
- data/test/alignment_test.rb +1 -1
- data/test/array_test.rb +3 -3
- data/test/bits_test.rb +34 -38
- data/test/common.rb +1 -5
- data/test/io_test.rb +0 -15
- data/test/lazy_test.rb +3 -11
- data/test/record_test.rb +21 -27
- data/test/string_test.rb +23 -25
- data/test/struct_test.rb +21 -52
- data/test/system_test.rb +9 -9
- metadata +48 -119
- data/doc/manual.haml +0 -407
- data/doc/manual.md +0 -1682
- data/setup.rb +0 -1585
- data/tasks/manual.rake +0 -36
data/lib/bindata/bits.rb
CHANGED
@@ -6,11 +6,13 @@ module BinData
|
|
6
6
|
|
7
7
|
module BitField #:nodoc: all
|
8
8
|
class << self
|
9
|
-
def define_class(
|
9
|
+
def define_class(nbits, endian, signed = :unsigned)
|
10
|
+
name = ((signed == :signed ) ? "Sbit" : "Bit") + nbits.to_s
|
11
|
+
name << "le" if endian == :little
|
10
12
|
unless BinData.const_defined?(name)
|
11
13
|
BinData.module_eval <<-END
|
12
14
|
class #{name} < BinData::BasePrimitive
|
13
|
-
BitField.define_methods(self, #{nbits
|
15
|
+
BitField.define_methods(self, #{nbits}, :#{endian}, :#{signed})
|
14
16
|
end
|
15
17
|
END
|
16
18
|
end
|
@@ -20,34 +22,27 @@ module BinData
|
|
20
22
|
|
21
23
|
def define_methods(bit_class, nbits, endian, signed)
|
22
24
|
bit_class.module_eval <<-END
|
23
|
-
#{create_params_code(nbits)}
|
24
|
-
|
25
25
|
def assign(val)
|
26
|
-
#{create_nbits_code(nbits)}
|
27
26
|
#{create_clamp_code(nbits, signed)}
|
28
27
|
super(val)
|
29
28
|
end
|
30
29
|
|
31
30
|
def do_write(io)
|
32
|
-
#{create_nbits_code(nbits)}
|
33
31
|
val = _value
|
34
|
-
#{create_int2uint_code(nbits
|
32
|
+
#{create_int2uint_code(nbits) if signed == :signed}
|
35
33
|
io.writebits(val, #{nbits}, :#{endian})
|
36
34
|
end
|
37
35
|
|
38
36
|
def do_num_bytes
|
39
|
-
#{
|
40
|
-
#{create_do_num_bytes_code(nbits)}
|
37
|
+
#{nbits / 8.0}
|
41
38
|
end
|
42
39
|
|
43
40
|
#---------------
|
44
41
|
private
|
45
42
|
|
46
|
-
|
47
43
|
def read_and_return_value(io)
|
48
|
-
#{create_nbits_code(nbits)}
|
49
44
|
val = io.readbits(#{nbits}, :#{endian})
|
50
|
-
#{create_uint2int_code(nbits
|
45
|
+
#{create_uint2int_code(nbits) if signed == :signed}
|
51
46
|
val
|
52
47
|
end
|
53
48
|
|
@@ -57,51 +52,7 @@ module BinData
|
|
57
52
|
END
|
58
53
|
end
|
59
54
|
|
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
|
-
|
84
55
|
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)
|
105
56
|
if nbits == 1 and signed == :signed
|
106
57
|
raise "signed bitfield must have more than one bit"
|
107
58
|
end
|
@@ -124,50 +75,30 @@ module BinData
|
|
124
75
|
"val = #{clamp}"
|
125
76
|
end
|
126
77
|
|
127
|
-
def create_int2uint_code(nbits
|
128
|
-
|
129
|
-
""
|
130
|
-
elsif nbits == :nbits
|
131
|
-
"val &= (1 << nbits) - 1"
|
132
|
-
else
|
133
|
-
"val &= #{(1 << nbits) - 1}"
|
134
|
-
end
|
78
|
+
def create_int2uint_code(nbits)
|
79
|
+
"val = val & #{(1 << nbits) - 1}"
|
135
80
|
end
|
136
81
|
|
137
|
-
def create_uint2int_code(nbits
|
138
|
-
if
|
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
|
82
|
+
def create_uint2int_code(nbits)
|
83
|
+
"val = val - #{1 << nbits} if (val >= #{1 << (nbits - 1)})"
|
145
84
|
end
|
146
85
|
end
|
147
86
|
end
|
148
87
|
|
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
|
-
|
157
88
|
# Create classes on demand
|
158
89
|
module BitFieldFactory
|
159
90
|
def const_missing(name)
|
160
91
|
mappings = {
|
161
|
-
/^Bit(\d+)$/
|
162
|
-
/^Bit(\d+)le$/
|
163
|
-
/^Sbit(\d+)$/
|
92
|
+
/^Bit(\d+)$/ => :big,
|
93
|
+
/^Bit(\d+)le$/ => :little,
|
94
|
+
/^Sbit(\d+)$/ => [:big, :signed],
|
164
95
|
/^Sbit(\d+)le$/ => [:little, :signed]
|
165
96
|
}
|
166
97
|
|
167
98
|
mappings.each_pair do |regex, args|
|
168
99
|
if regex =~ name.to_s
|
169
100
|
nbits = $1.to_i
|
170
|
-
return BitField.define_class(
|
101
|
+
return BitField.define_class(nbits, *args)
|
171
102
|
end
|
172
103
|
end
|
173
104
|
|
data/lib/bindata/buffer.rb
CHANGED
data/lib/bindata/choice.rb
CHANGED
@@ -125,24 +125,40 @@ module BinData
|
|
125
125
|
selection
|
126
126
|
end
|
127
127
|
|
128
|
-
def
|
129
|
-
|
128
|
+
def clear? #:nodoc:
|
129
|
+
current_choice.clear?
|
130
|
+
end
|
131
|
+
|
132
|
+
def assign(val)
|
133
|
+
current_choice.assign(val)
|
134
|
+
end
|
135
|
+
|
136
|
+
def snapshot
|
137
|
+
current_choice.snapshot
|
130
138
|
end
|
131
139
|
|
132
140
|
def respond_to?(symbol, include_private = false) #:nodoc:
|
133
141
|
current_choice.respond_to?(symbol, include_private) || super
|
134
142
|
end
|
135
143
|
|
144
|
+
def safe_respond_to?(symbol, include_private = false) #:nodoc:
|
145
|
+
base_respond_to?(symbol, include_private)
|
146
|
+
end
|
147
|
+
|
136
148
|
def method_missing(symbol, *args, &block) #:nodoc:
|
137
149
|
current_choice.__send__(symbol, *args, &block)
|
138
150
|
end
|
139
151
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
152
|
+
def do_read(io) #:nodoc:
|
153
|
+
current_choice.do_read(io)
|
154
|
+
end
|
155
|
+
|
156
|
+
def do_write(io) #:nodoc:
|
157
|
+
current_choice.do_write(io)
|
158
|
+
end
|
159
|
+
|
160
|
+
def do_num_bytes #:nodoc:
|
161
|
+
current_choice.do_num_bytes
|
146
162
|
end
|
147
163
|
|
148
164
|
#---------------
|
data/lib/bindata/deprecated.rb
CHANGED
@@ -1,31 +1,14 @@
|
|
1
|
-
# Implement Kernel#instance_exec for Ruby 1.8.6 and below
|
2
|
-
unless Object.respond_to? :instance_exec
|
3
|
-
module Kernel
|
4
|
-
# Taken from http://eigenclass.org/hiki/instance_exec
|
5
|
-
def instance_exec(*args, &block)
|
6
|
-
mname = "__instance_exec_#{Thread.current.object_id.abs}_#{object_id.abs}"
|
7
|
-
Object.class_eval{ define_method(mname, &block) }
|
8
|
-
begin
|
9
|
-
ret = send(mname, *args)
|
10
|
-
ensure
|
11
|
-
Object.class_eval{ undef_method(mname) } rescue nil
|
12
|
-
end
|
13
|
-
ret
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
1
|
module BinData
|
19
2
|
class Base
|
20
3
|
|
21
4
|
# Don't override initialize. If you are defining a new kind of datatype
|
22
5
|
# (list, array, choice etc) then put your initialization code in
|
23
|
-
# #initialize_instance. BinData objects
|
24
|
-
# and your initialization code may not be called.
|
6
|
+
# #initialize_instance. This is because BinData objects can be initialized
|
7
|
+
# as prototypes and your initialization code may not be called.
|
25
8
|
#
|
26
9
|
# If you're subclassing BinData::Record, you are definitely doing the wrong
|
27
10
|
# thing. Read the documentation on how to use BinData.
|
28
|
-
# http://
|
11
|
+
# http://bindata.rubyforge.org/manual.html#records
|
29
12
|
alias_method :initialize_without_warning, :initialize
|
30
13
|
def initialize_with_warning(*args)
|
31
14
|
owner = method(:initialize).owner
|
@@ -46,11 +29,5 @@ module BinData
|
|
46
29
|
end
|
47
30
|
end
|
48
31
|
|
49
|
-
# #offset has been renamed to #abs_offset.
|
50
|
-
# Eventually #rel_offset will be renamed to #offset.
|
51
|
-
def offset
|
52
|
-
warn "#offset is deprecated in #{debug_name}. Use #abs_offset instead"
|
53
|
-
abs_offset
|
54
|
-
end
|
55
32
|
end
|
56
33
|
end
|
data/lib/bindata/int.rb
CHANGED
@@ -6,7 +6,8 @@ module BinData
|
|
6
6
|
|
7
7
|
module Int #:nodoc: all
|
8
8
|
class << self
|
9
|
-
def define_class(
|
9
|
+
def define_class(nbits, endian, signed)
|
10
|
+
name = class_name(nbits, endian, signed)
|
10
11
|
unless BinData.const_defined?(name)
|
11
12
|
BinData.module_eval <<-END
|
12
13
|
class #{name} < BinData::BasePrimitive
|
@@ -18,6 +19,13 @@ module BinData
|
|
18
19
|
BinData.const_get(name)
|
19
20
|
end
|
20
21
|
|
22
|
+
def class_name(nbits, endian, signed)
|
23
|
+
endian_str = (endian == :big) ? "be" : "le"
|
24
|
+
base = (signed == :signed) ? "Int" : "Uint"
|
25
|
+
|
26
|
+
"#{base}#{nbits}#{endian_str}"
|
27
|
+
end
|
28
|
+
|
21
29
|
def define_methods(int_class, nbits, endian, signed)
|
22
30
|
raise "nbits must be divisible by 8" unless (nbits % 8).zero?
|
23
31
|
|
@@ -162,7 +170,7 @@ module BinData
|
|
162
170
|
if regex =~ name.to_s
|
163
171
|
nbits = $1.to_i
|
164
172
|
if (nbits % 8).zero?
|
165
|
-
return Int.define_class(
|
173
|
+
return Int.define_class(nbits, *args)
|
166
174
|
end
|
167
175
|
end
|
168
176
|
end
|
data/lib/bindata/io.rb
CHANGED
@@ -6,10 +6,7 @@ module BinData
|
|
6
6
|
module IO
|
7
7
|
# Creates a StringIO around +str+.
|
8
8
|
def self.create_string_io(str = "")
|
9
|
-
|
10
|
-
str = str.dup.force_encoding(Encoding::BINARY)
|
11
|
-
end
|
12
|
-
StringIO.new(str)
|
9
|
+
StringIO.new(str.dup.force_encoding(Encoding::BINARY))
|
13
10
|
end
|
14
11
|
|
15
12
|
# Create a new IO Read wrapper around +io+. +io+ must provide #read,
|
@@ -190,8 +187,8 @@ module BinData
|
|
190
187
|
|
191
188
|
# Use #seek and #pos on seekable streams
|
192
189
|
module SeekableStream
|
193
|
-
# Returns the current offset of the io stream.
|
194
|
-
#
|
190
|
+
# Returns the current offset of the io stream. The exact value of
|
191
|
+
# the offset when reading bitfields is not defined.
|
195
192
|
def offset
|
196
193
|
raw_io.pos - @initial_pos
|
197
194
|
end
|
@@ -225,8 +222,8 @@ module BinData
|
|
225
222
|
|
226
223
|
# Manually keep track of offset for unseekable streams.
|
227
224
|
module UnSeekableStream
|
228
|
-
# Returns the current offset of the io stream.
|
229
|
-
#
|
225
|
+
# Returns the current offset of the io stream. The exact value of
|
226
|
+
# the offset when reading bitfields is not defined.
|
230
227
|
def offset
|
231
228
|
@read_count ||= 0
|
232
229
|
end
|
@@ -284,8 +281,6 @@ module BinData
|
|
284
281
|
@wval = 0
|
285
282
|
@wendian = nil
|
286
283
|
|
287
|
-
@write_count = 0
|
288
|
-
|
289
284
|
@bytes_remaining = nil
|
290
285
|
end
|
291
286
|
|
@@ -309,12 +304,6 @@ module BinData
|
|
309
304
|
end
|
310
305
|
end
|
311
306
|
|
312
|
-
# Returns the current offset of the io stream. Offset will be rounded
|
313
|
-
# up when writing bitfields.
|
314
|
-
def offset
|
315
|
-
@write_count + (@wnbits > 0 ? 1 : 0)
|
316
|
-
end
|
317
|
-
|
318
307
|
# Writes the given string of bytes to the io stream.
|
319
308
|
def writebytes(str)
|
320
309
|
flushbits
|
@@ -402,7 +391,6 @@ module BinData
|
|
402
391
|
@bytes_remaining -= data.size
|
403
392
|
end
|
404
393
|
|
405
|
-
@write_count += data.size
|
406
394
|
@raw_io.write(data)
|
407
395
|
end
|
408
396
|
|
data/lib/bindata/lazy.rb
CHANGED
data/lib/bindata/params.rb
CHANGED
@@ -118,7 +118,7 @@ module BinData
|
|
118
118
|
def self.invalid_parameter_names
|
119
119
|
unless defined? @invalid_names
|
120
120
|
all_names = LazyEvaluator.instance_methods(true) + Kernel.methods
|
121
|
-
allowed_names = [
|
121
|
+
allowed_names = [:name, :type]
|
122
122
|
invalid_names = (all_names - allowed_names).uniq
|
123
123
|
@invalid_names = Hash[*invalid_names.collect { |key| [key.to_sym, true] }.flatten]
|
124
124
|
end
|
data/lib/bindata/record.rb
CHANGED
@@ -1,10 +1,28 @@
|
|
1
1
|
require 'bindata/dsl'
|
2
|
+
require 'bindata/sanitize'
|
2
3
|
require 'bindata/struct'
|
3
4
|
|
4
5
|
module BinData
|
5
6
|
# A Record is a declarative wrapper around Struct.
|
6
7
|
#
|
7
|
-
#
|
8
|
+
# require 'bindata'
|
9
|
+
#
|
10
|
+
# class SomeDataType < BinData::Record
|
11
|
+
# hide :a
|
12
|
+
#
|
13
|
+
# int32le :a
|
14
|
+
# int16le :b
|
15
|
+
# struct :s do
|
16
|
+
# int8 :x
|
17
|
+
# int8 :y
|
18
|
+
# int8 :z
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# obj = SomeDataType.new
|
23
|
+
# obj.field_names =># [:b, :s]
|
24
|
+
# obj.s.field_names =># [:x, :y, :z]
|
25
|
+
#
|
8
26
|
class Record < BinData::Struct
|
9
27
|
include DSLMixin
|
10
28
|
|
data/lib/bindata/sanitize.rb
CHANGED
@@ -24,14 +24,6 @@ module BinData
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
def has_parameter?(param)
|
28
|
-
if @factory
|
29
|
-
@factory.has_parameter?(param)
|
30
|
-
else
|
31
|
-
@obj_params.has_parameter?(param)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
27
|
def instantiate(value = nil, parent = nil)
|
36
28
|
@factory ||= @obj_class.new(@obj_params)
|
37
29
|
|
@@ -56,10 +48,6 @@ module BinData
|
|
56
48
|
@name
|
57
49
|
end
|
58
50
|
|
59
|
-
def has_parameter?(param)
|
60
|
-
@prototype.has_parameter?(param)
|
61
|
-
end
|
62
|
-
|
63
51
|
def instantiate(value = nil, parent = nil)
|
64
52
|
@prototype.instantiate(value, parent)
|
65
53
|
end
|
@@ -95,10 +83,6 @@ module BinData
|
|
95
83
|
@fields.each(&block)
|
96
84
|
end
|
97
85
|
|
98
|
-
def each_with_index(&block)
|
99
|
-
@fields.each_with_index(&block)
|
100
|
-
end
|
101
|
-
|
102
86
|
def collect(&block)
|
103
87
|
@fields.collect(&block)
|
104
88
|
end
|
@@ -119,10 +103,6 @@ module BinData
|
|
119
103
|
@fields.all? { |f| f.name != nil }
|
120
104
|
end
|
121
105
|
|
122
|
-
def any_field_has_parameter?(parameter)
|
123
|
-
@fields.any? { |f| f.has_parameter?(parameter) }
|
124
|
-
end
|
125
|
-
|
126
106
|
def copy_fields(other)
|
127
107
|
@fields.concat(other.fields)
|
128
108
|
end
|