bindata 0.5.1 → 0.6.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.
- data/ChangeLog +6 -0
- data/README +36 -0
- data/TODO +3 -6
- data/lib/bindata.rb +2 -1
- data/lib/bindata/array.rb +1 -1
- data/lib/bindata/base.rb +25 -1
- data/lib/bindata/choice.rb +1 -1
- data/lib/bindata/float.rb +84 -0
- data/lib/bindata/int.rb +107 -107
- data/lib/bindata/lazy.rb +5 -0
- data/lib/bindata/struct.rb +16 -2
- data/spec/float_spec.rb +105 -0
- data/spec/int_spec.rb +10 -2
- data/spec/struct_spec.rb +45 -2
- metadata +4 -2
data/ChangeLog
CHANGED
data/README
CHANGED
@@ -164,6 +164,11 @@ BinData::Uint16be:: Unsigned 16 bit integer (big endian).
|
|
164
164
|
BinData::Uint32le:: Unsigned 32 bit integer (little endian).
|
165
165
|
BinData::Uint32be:: Unsigned 32 bit integer (big endian).
|
166
166
|
|
167
|
+
BinData::FloatLe:: Single precision floating point number (little endian).
|
168
|
+
BinData::FloatBe:: Single precision floating point number (big endian).
|
169
|
+
BinData::DoubleLe:: Double precision floating point number (little endian).
|
170
|
+
BinData::DoubleBe:: Double precision floating point number (big endian).
|
171
|
+
|
167
172
|
BinData::String:: A sequence of bytes.
|
168
173
|
BinData::Stringz:: A zero terminated sequence of bytes.
|
169
174
|
|
@@ -201,6 +206,37 @@ If the value is a symbol, it is taken as syntactic sugar for a lambda
|
|
201
206
|
containing the value of the symbol.
|
202
207
|
e.g <tt>:param => :foo</tt> is <tt>:param => lambda { foo }</tt>
|
203
208
|
|
209
|
+
== Saving Typing
|
210
|
+
|
211
|
+
The endianess of numeric types must be explicitly defined so that the code
|
212
|
+
produced is independent of architecture. Explicitly specifying the
|
213
|
+
endianess of each numeric type can become tedious, so the following
|
214
|
+
shortcut is provided.
|
215
|
+
|
216
|
+
class A < BinData::Struct
|
217
|
+
endian :little
|
218
|
+
|
219
|
+
uint16 :a
|
220
|
+
uint32 :b
|
221
|
+
double :c
|
222
|
+
uint32be :d
|
223
|
+
array :e, :type => :int16
|
224
|
+
end
|
225
|
+
|
226
|
+
is equivalent to:
|
227
|
+
|
228
|
+
class A < BinData::Struct
|
229
|
+
uint16le :a
|
230
|
+
uint32le :b
|
231
|
+
double_le :c
|
232
|
+
uint32be :d
|
233
|
+
array :e, :type => :int16le
|
234
|
+
end
|
235
|
+
|
236
|
+
Using the endian keyword improves the readability of the declaration as well
|
237
|
+
as reducing the amount of typing necessary. Note that the endian keyword will
|
238
|
+
cascade to nested types, as illustrated with the array in the above example.
|
239
|
+
|
204
240
|
== Creating custom types
|
205
241
|
|
206
242
|
Custom types should be created by subclassing BinData::Struct.
|
data/TODO
CHANGED
@@ -3,11 +3,8 @@
|
|
3
3
|
|
4
4
|
* Add scoping so the value of a param doesn't need to call parent
|
5
5
|
|
6
|
-
* Optimise int.rb for speed.
|
7
|
-
|
8
|
-
* Maybe add an endian method to struct so you can say int16 instead of int16le.
|
9
|
-
- Should this by lazily evaluated, or evaluated only once when
|
10
|
-
instantiating fields?
|
11
|
-
|
12
6
|
* Think how offset_of should work.
|
13
7
|
|
8
|
+
* Need optional parameter for fields
|
9
|
+
|
10
|
+
* Should I add seek capability?
|
data/lib/bindata.rb
CHANGED
@@ -3,11 +3,12 @@
|
|
3
3
|
|
4
4
|
require 'bindata/array'
|
5
5
|
require 'bindata/choice'
|
6
|
+
require 'bindata/float'
|
6
7
|
require 'bindata/int'
|
7
8
|
require 'bindata/string'
|
8
9
|
require 'bindata/stringz'
|
9
10
|
require 'bindata/struct'
|
10
11
|
|
11
12
|
module BinData
|
12
|
-
VERSION = "0.
|
13
|
+
VERSION = "0.6.0"
|
13
14
|
end
|
data/lib/bindata/array.rb
CHANGED
data/lib/bindata/base.rb
CHANGED
@@ -83,7 +83,21 @@ module BinData
|
|
83
83
|
|
84
84
|
# Returns the class matching a previously registered +name+.
|
85
85
|
def lookup(name)
|
86
|
-
Registry.instance.lookup(name)
|
86
|
+
klass = Registry.instance.lookup(name)
|
87
|
+
if klass.nil?
|
88
|
+
# lookup failed so attempt endian lookup
|
89
|
+
if self.respond_to?(:endian) and self.endian != nil
|
90
|
+
name = name.to_s
|
91
|
+
if /^u?int\d\d?$/ =~ name
|
92
|
+
new_name = name + ((self.endian == :little) ? "le" : "be")
|
93
|
+
klass = Registry.instance.lookup(new_name)
|
94
|
+
elsif ["float", "double"].include?(name)
|
95
|
+
new_name = name + ((self.endian == :little) ? "_le" : "_be")
|
96
|
+
klass = Registry.instance.lookup(new_name)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
klass
|
87
101
|
end
|
88
102
|
end
|
89
103
|
|
@@ -131,6 +145,16 @@ module BinData
|
|
131
145
|
@env.data_object = self
|
132
146
|
end
|
133
147
|
|
148
|
+
# Returns the class matching a previously registered +name+.
|
149
|
+
def klass_lookup(name)
|
150
|
+
klass = self.class.lookup(name)
|
151
|
+
if klass.nil? and @env.parent_data_object != nil
|
152
|
+
# lookup failed so retry in the context of the parent data object
|
153
|
+
klass = @env.parent_data_object.klass_lookup(name)
|
154
|
+
end
|
155
|
+
klass
|
156
|
+
end
|
157
|
+
|
134
158
|
# Reads data into this bin object by calling #do_read then #done_read.
|
135
159
|
def read(io)
|
136
160
|
# remember the current position in the IO object
|
data/lib/bindata/choice.rb
CHANGED
@@ -38,7 +38,7 @@ module BinData
|
|
38
38
|
@choices = []
|
39
39
|
param(:choices).each do |choice_type, choice_params|
|
40
40
|
choice_params ||= {}
|
41
|
-
klass =
|
41
|
+
klass = klass_lookup(choice_type)
|
42
42
|
if klass.nil?
|
43
43
|
raise TypeError, "unknown type '#{choice_type.id2name}' for #{self}"
|
44
44
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'bindata/single'
|
2
|
+
|
3
|
+
module BinData
|
4
|
+
# Provides a number of classes that contain a floating point number.
|
5
|
+
# The float is defined by endian, and precision.
|
6
|
+
|
7
|
+
module Float #:nodoc: all
|
8
|
+
def self.create_float_methods(klass, single_precision, endian)
|
9
|
+
read = create_read_code(single_precision, endian)
|
10
|
+
to_s = create_to_s_code(single_precision, endian)
|
11
|
+
|
12
|
+
define_methods(klass, single_precision, read, to_s)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.create_read_code(single_precision, endian)
|
16
|
+
if single_precision
|
17
|
+
unpack = (endian == :little) ? 'e' : 'g'
|
18
|
+
nbytes = 4
|
19
|
+
else # double_precision
|
20
|
+
unpack = (endian == :little) ? 'E' : 'G'
|
21
|
+
nbytes = 8
|
22
|
+
end
|
23
|
+
|
24
|
+
"readbytes(io,#{nbytes}).unpack('#{unpack}').at(0)"
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.create_to_s_code(single_precision, endian)
|
28
|
+
if single_precision
|
29
|
+
pack = (endian == :little) ? 'e' : 'g'
|
30
|
+
else # double_precision
|
31
|
+
pack = (endian == :little) ? 'E' : 'G'
|
32
|
+
end
|
33
|
+
|
34
|
+
"[val].pack('#{pack}')"
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.define_methods(klass, single_precision, read, to_s)
|
38
|
+
nbytes = single_precision ? 4 : 8
|
39
|
+
|
40
|
+
# define methods in the given class
|
41
|
+
klass.module_eval <<-END
|
42
|
+
def _num_bytes(ignored)
|
43
|
+
#{nbytes}
|
44
|
+
end
|
45
|
+
|
46
|
+
#---------------
|
47
|
+
private
|
48
|
+
|
49
|
+
def sensible_default
|
50
|
+
0.0
|
51
|
+
end
|
52
|
+
|
53
|
+
def val_to_str(val)
|
54
|
+
#{to_s}
|
55
|
+
end
|
56
|
+
|
57
|
+
def read_val(io)
|
58
|
+
#{read}
|
59
|
+
end
|
60
|
+
END
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
# Single precision floating point number in little endian format
|
66
|
+
class FloatLe < Single
|
67
|
+
Float.create_float_methods(self, true, :little)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Single precision floating point number in big endian format
|
71
|
+
class FloatBe < Single
|
72
|
+
Float.create_float_methods(self, true, :big)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Double precision floating point number in little endian format
|
76
|
+
class DoubleLe < Single
|
77
|
+
Float.create_float_methods(self, false, :little)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Double precision floating point number in big endian format
|
81
|
+
class DoubleBe < Single
|
82
|
+
Float.create_float_methods(self, false, :big)
|
83
|
+
end
|
84
|
+
end
|
data/lib/bindata/int.rb
CHANGED
@@ -4,168 +4,168 @@ module BinData
|
|
4
4
|
# Provides a number of classes that contain an integer. The integer
|
5
5
|
# is defined by endian, signedness and number of bytes.
|
6
6
|
|
7
|
-
module
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
module Integer #:nodoc: all
|
8
|
+
def self.create_int_methods(klass, nbits, endian)
|
9
|
+
max = (1 << (nbits - 1)) - 1
|
10
|
+
min = -(max + 1)
|
11
|
+
clamp = "val = (val < #{min}) ? #{min} : (val > #{max}) ? #{max} : val"
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
int2uint = "val = val & #{(1 << nbits) - 1}"
|
14
|
+
uint2int = "val = ((val & #{1 << (nbits - 1)}).zero?) ? " +
|
15
|
+
"val & #{max} : -(((~val) & #{max}) + 1)"
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
end
|
17
|
+
read = create_read_code(nbits, endian)
|
18
|
+
to_s = create_to_s_code(nbits, endian)
|
19
19
|
|
20
|
-
|
21
|
-
_val_to_str(clamp(val))
|
20
|
+
define_methods(klass, nbits / 8, clamp, read, to_s, int2uint, uint2int)
|
22
21
|
end
|
23
22
|
|
24
|
-
|
25
|
-
def clamp(val)
|
26
|
-
v = val
|
27
|
-
nbytes = val_num_bytes(0)
|
23
|
+
def self.create_uint_methods(klass, nbits, endian)
|
28
24
|
min = 0
|
29
|
-
max = (1 <<
|
30
|
-
val = min
|
31
|
-
val = max if val > max
|
32
|
-
val
|
33
|
-
end
|
34
|
-
end
|
25
|
+
max = (1 << nbits) - 1
|
26
|
+
clamp = "val = (val < #{min}) ? #{min} : (val > #{max}) ? #{max} : val"
|
35
27
|
|
36
|
-
|
37
|
-
|
38
|
-
nbytes = val_num_bytes(0)
|
39
|
-
mask = (1 << (nbytes * 8 - 1)) - 1
|
40
|
-
msb = (val >> (nbytes * 8 - 1)) & 0x1
|
41
|
-
(msb == 1) ? -(((~val) & mask) + 1) : val & mask
|
42
|
-
end
|
28
|
+
read = create_read_code(nbits, endian)
|
29
|
+
to_s = create_to_s_code(nbits, endian)
|
43
30
|
|
44
|
-
|
45
|
-
nbytes = val_num_bytes(0)
|
46
|
-
mask = (1 << (nbytes * 8)) - 1
|
47
|
-
val & mask
|
31
|
+
define_methods(klass, nbits / 8, clamp, read, to_s)
|
48
32
|
end
|
49
33
|
|
50
|
-
def
|
51
|
-
|
34
|
+
def self.create_read_code(nbits, endian)
|
35
|
+
c16 = (endian == :little) ? 'v' : 'n'
|
36
|
+
c32 = (endian == :little) ? 'V' : 'N'
|
37
|
+
b1 = (endian == :little) ? 0 : 1
|
38
|
+
b2 = (endian == :little) ? 1 : 0
|
39
|
+
|
40
|
+
case nbits
|
41
|
+
when 8; "readbytes(io,1)[0]"
|
42
|
+
when 16; "readbytes(io,2).unpack('#{c16}').at(0)"
|
43
|
+
when 32; "readbytes(io,4).unpack('#{c32}').at(0)"
|
44
|
+
when 64; "(a = readbytes(io,8).unpack('#{c32 * 2}'); " +
|
45
|
+
"(a.at(#{b2}) << 32) + a.at(#{b1}))"
|
46
|
+
else
|
47
|
+
raise "unknown nbits '#{nbits}'"
|
48
|
+
end
|
52
49
|
end
|
53
50
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
51
|
+
def self.create_to_s_code(nbits, endian)
|
52
|
+
c16 = (endian == :little) ? 'v' : 'n'
|
53
|
+
c32 = (endian == :little) ? 'V' : 'N'
|
54
|
+
v1 = (endian == :little) ? 'val' : '(val >> 32)'
|
55
|
+
v2 = (endian == :little) ? '(val >> 32)' : 'val'
|
56
|
+
|
57
|
+
case nbits
|
58
|
+
when 8; "val.chr"
|
59
|
+
when 16; "[val].pack('#{c16}')"
|
60
|
+
when 32; "[val].pack('#{c32}')"
|
61
|
+
when 64; "[#{v1} & 0xffffffff, #{v2} & 0xffffffff].pack('#{c32 * 2}')"
|
62
|
+
else
|
63
|
+
raise "unknown nbits '#{nbits}'"
|
64
|
+
end
|
59
65
|
end
|
60
66
|
|
61
|
-
def
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
67
|
+
def self.define_methods(klass, nbytes, clamp, read, to_s,
|
68
|
+
int2uint = nil, uint2int = nil)
|
69
|
+
# define methods in the given class
|
70
|
+
klass.module_eval <<-END
|
71
|
+
def value=(val)
|
72
|
+
#{clamp}
|
73
|
+
super(val)
|
74
|
+
end
|
75
|
+
|
76
|
+
def _num_bytes(ignored)
|
77
|
+
#{nbytes}
|
78
|
+
end
|
79
|
+
|
80
|
+
#---------------
|
81
|
+
private
|
82
|
+
|
83
|
+
def sensible_default
|
84
|
+
0
|
85
|
+
end
|
86
|
+
|
87
|
+
def val_to_str(val)
|
88
|
+
#{clamp}
|
89
|
+
#{int2uint unless int2uint.nil?}
|
90
|
+
#{to_s}
|
91
|
+
end
|
92
|
+
|
93
|
+
def read_val(io)
|
94
|
+
val = #{read}
|
95
|
+
#{uint2int unless uint2int.nil?}
|
96
|
+
end
|
97
|
+
END
|
78
98
|
end
|
79
99
|
end
|
80
100
|
|
81
101
|
|
82
102
|
# Unsigned 1 byte integer.
|
83
103
|
class Uint8 < Single
|
84
|
-
|
85
|
-
private
|
86
|
-
def val_num_bytes(val) 1 end
|
87
|
-
def read_val(io) readbytes(io,1)[0] end
|
88
|
-
def _val_to_str(val) val.chr end
|
104
|
+
Integer.create_uint_methods(self, 8, :little)
|
89
105
|
end
|
90
106
|
|
91
107
|
# Unsigned 2 byte little endian integer.
|
92
108
|
class Uint16le < Single
|
93
|
-
|
94
|
-
private
|
95
|
-
def val_num_bytes(val) 2 end
|
96
|
-
def read_val(io) readbytes(io,2).unpack("v")[0] end
|
97
|
-
def _val_to_str(val) [val].pack("v") end
|
109
|
+
Integer.create_uint_methods(self, 16, :little)
|
98
110
|
end
|
99
111
|
|
100
112
|
# Unsigned 2 byte big endian integer.
|
101
113
|
class Uint16be < Single
|
102
|
-
|
103
|
-
private
|
104
|
-
def val_num_bytes(val) 2 end
|
105
|
-
def read_val(io) readbytes(io,2).unpack("n")[0] end
|
106
|
-
def _val_to_str(val) [val].pack("n") end
|
114
|
+
Integer.create_uint_methods(self, 16, :big)
|
107
115
|
end
|
108
116
|
|
109
117
|
# Unsigned 4 byte little endian integer.
|
110
118
|
class Uint32le < Single
|
111
|
-
|
112
|
-
private
|
113
|
-
def val_num_bytes(val) 4 end
|
114
|
-
def read_val(io) readbytes(io,4).unpack("V")[0] end
|
115
|
-
def _val_to_str(val) [val].pack("V") end
|
119
|
+
Integer.create_uint_methods(self, 32, :little)
|
116
120
|
end
|
117
121
|
|
118
122
|
# Unsigned 4 byte big endian integer.
|
119
123
|
class Uint32be < Single
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
124
|
+
Integer.create_uint_methods(self, 32, :big)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Unsigned 8 byte little endian integer.
|
128
|
+
class Uint64le < Single
|
129
|
+
Integer.create_uint_methods(self, 64, :little)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Unsigned 8 byte big endian integer.
|
133
|
+
class Uint64be < Single
|
134
|
+
Integer.create_uint_methods(self, 64, :big)
|
125
135
|
end
|
126
136
|
|
127
137
|
# Signed 1 byte integer.
|
128
138
|
class Int8 < Single
|
129
|
-
|
130
|
-
private
|
131
|
-
def val_num_bytes(val) 1 end
|
132
|
-
def _read_val(io) readbytes(io,1)[0] end
|
133
|
-
def _val_to_str(val) val.chr end
|
139
|
+
Integer.create_int_methods(self, 8, :little)
|
134
140
|
end
|
135
141
|
|
136
142
|
# Signed 2 byte little endian integer.
|
137
143
|
class Int16le < Single
|
138
|
-
|
139
|
-
private
|
140
|
-
def val_num_bytes(val) 2 end
|
141
|
-
def _read_val(io) readbytes(io,2).unpack("v")[0] end
|
142
|
-
def _val_to_str(val) [val].pack("v") end
|
144
|
+
Integer.create_int_methods(self, 16, :little)
|
143
145
|
end
|
144
146
|
|
145
147
|
# Signed 2 byte big endian integer.
|
146
148
|
class Int16be < Single
|
147
|
-
|
148
|
-
private
|
149
|
-
def val_num_bytes(val) 2 end
|
150
|
-
def _read_val(io) readbytes(io,2).unpack("n")[0] end
|
151
|
-
def _val_to_str(val) [val].pack("n") end
|
149
|
+
Integer.create_int_methods(self, 16, :big)
|
152
150
|
end
|
153
151
|
|
154
152
|
# Signed 4 byte little endian integer.
|
155
153
|
class Int32le < Single
|
156
|
-
|
157
|
-
private
|
158
|
-
def val_num_bytes(val) 4 end
|
159
|
-
def _read_val(io) readbytes(io,4).unpack("V")[0] end
|
160
|
-
def _val_to_str(val) [val].pack("V") end
|
154
|
+
Integer.create_int_methods(self, 32, :little)
|
161
155
|
end
|
162
156
|
|
163
157
|
# Signed 4 byte big endian integer.
|
164
158
|
class Int32be < Single
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
159
|
+
Integer.create_int_methods(self, 32, :big)
|
160
|
+
end
|
161
|
+
|
162
|
+
# Signed 8 byte little endian integer.
|
163
|
+
class Int64le < Single
|
164
|
+
Integer.create_int_methods(self, 64, :little)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Signed 8 byte big endian integer.
|
168
|
+
class Int64be < Single
|
169
|
+
Integer.create_int_methods(self, 64, :big)
|
170
170
|
end
|
171
171
|
end
|
data/lib/bindata/lazy.rb
CHANGED
@@ -37,6 +37,11 @@ module BinData
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
+
# Returns the data_object for the parent environment.
|
41
|
+
def parent_data_object
|
42
|
+
@parent.nil? ? nil : @parent.data_object
|
43
|
+
end
|
44
|
+
|
40
45
|
# Returns the value of the data object wrapped by this environment.
|
41
46
|
def value
|
42
47
|
@data_object.respond_to?(:value) ? @data_object.value : nil
|
data/lib/bindata/struct.rb
CHANGED
@@ -55,6 +55,20 @@ module BinData
|
|
55
55
|
register(subclass.name, subclass)
|
56
56
|
end
|
57
57
|
|
58
|
+
# Returns or sets the endianess of numerics used in this stucture.
|
59
|
+
# Endianess is propagated to nested data objects unless overridden
|
60
|
+
# in a nested Struct.
|
61
|
+
# Valid values are :little and :big.
|
62
|
+
def endian(endian = nil)
|
63
|
+
@endian ||= nil
|
64
|
+
if [:little, :big].include?(endian)
|
65
|
+
@endian = endian
|
66
|
+
elsif endian != nil
|
67
|
+
raise ArgumentError, "unknown value for endian '#{endian}'"
|
68
|
+
end
|
69
|
+
@endian
|
70
|
+
end
|
71
|
+
|
58
72
|
# Returns the names of any hidden fields in this struct. Any given args
|
59
73
|
# are appended to the hidden list.
|
60
74
|
def hide(*args)
|
@@ -106,7 +120,7 @@ module BinData
|
|
106
120
|
|
107
121
|
# These are the parameters used by this class.
|
108
122
|
mandatory_parameter :fields
|
109
|
-
optional_parameter :hide
|
123
|
+
optional_parameter :endian, :hide
|
110
124
|
|
111
125
|
# Creates a new Struct.
|
112
126
|
def initialize(params = {}, env = nil)
|
@@ -114,7 +128,7 @@ module BinData
|
|
114
128
|
|
115
129
|
# create instances of the fields
|
116
130
|
@fields = param(:fields).collect do |type, name, params|
|
117
|
-
klass =
|
131
|
+
klass = klass_lookup(type)
|
118
132
|
raise TypeError, "unknown type '#{type}' for #{self}" if klass.nil?
|
119
133
|
if methods.include?(name)
|
120
134
|
raise NameError.new("field '#{name}' shadows an existing method",name)
|
data/spec/float_spec.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__)) + '/spec_common'
|
4
|
+
require 'bindata/float'
|
5
|
+
|
6
|
+
context "A FloatLe" do
|
7
|
+
setup do
|
8
|
+
@obj = BinData::FloatLe.new
|
9
|
+
@obj.value = Math::PI
|
10
|
+
|
11
|
+
@io = StringIO.new
|
12
|
+
end
|
13
|
+
|
14
|
+
specify "should write the expected value" do
|
15
|
+
@obj.write(@io)
|
16
|
+
@io.rewind
|
17
|
+
|
18
|
+
@io.read.should == [Math::PI].pack('e')
|
19
|
+
end
|
20
|
+
|
21
|
+
specify "should read the same value as written" do
|
22
|
+
@obj.write(@io)
|
23
|
+
@io.rewind
|
24
|
+
|
25
|
+
# check that we read in the same data that was written
|
26
|
+
@obj.read(@io)
|
27
|
+
@obj.value.should be_close(Math::PI, 0.000001)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "A FloatBe" do
|
32
|
+
setup do
|
33
|
+
@obj = BinData::FloatBe.new
|
34
|
+
@obj.value = Math::PI
|
35
|
+
|
36
|
+
@io = StringIO.new
|
37
|
+
end
|
38
|
+
|
39
|
+
specify "should write the expected value" do
|
40
|
+
@obj.write(@io)
|
41
|
+
@io.rewind
|
42
|
+
|
43
|
+
@io.read.should == [Math::PI].pack('g')
|
44
|
+
end
|
45
|
+
|
46
|
+
specify "should read the same value as written" do
|
47
|
+
@obj.write(@io)
|
48
|
+
@io.rewind
|
49
|
+
|
50
|
+
# check that we read in the same data that was written
|
51
|
+
@obj.read(@io)
|
52
|
+
@obj.value.should be_close(Math::PI, 0.000001)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "A DoubleLe" do
|
57
|
+
setup do
|
58
|
+
@obj = BinData::DoubleLe.new
|
59
|
+
@obj.value = Math::PI
|
60
|
+
|
61
|
+
@io = StringIO.new
|
62
|
+
end
|
63
|
+
|
64
|
+
specify "should write the expected value" do
|
65
|
+
@obj.write(@io)
|
66
|
+
@io.rewind
|
67
|
+
|
68
|
+
@io.read.should == [Math::PI].pack('E')
|
69
|
+
end
|
70
|
+
|
71
|
+
specify "should read the same value as written" do
|
72
|
+
@obj.write(@io)
|
73
|
+
@io.rewind
|
74
|
+
|
75
|
+
# check that we read in the same data that was written
|
76
|
+
@obj.read(@io)
|
77
|
+
@obj.value.should be_close(Math::PI, 0.000000000000000001)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
context "A DoubleBe" do
|
83
|
+
setup do
|
84
|
+
@obj = BinData::DoubleBe.new
|
85
|
+
@obj.value = Math::PI
|
86
|
+
|
87
|
+
@io = StringIO.new
|
88
|
+
end
|
89
|
+
|
90
|
+
specify "should write the expected value" do
|
91
|
+
@obj.write(@io)
|
92
|
+
@io.rewind
|
93
|
+
|
94
|
+
@io.read.should == [Math::PI].pack('G')
|
95
|
+
end
|
96
|
+
|
97
|
+
specify "should read the same value as written" do
|
98
|
+
@obj.write(@io)
|
99
|
+
@io.rewind
|
100
|
+
|
101
|
+
# check that we read in the same data that was written
|
102
|
+
@obj.read(@io)
|
103
|
+
@obj.value.should be_close(Math::PI, 0.000000000000000001)
|
104
|
+
end
|
105
|
+
end
|
data/spec/int_spec.rb
CHANGED
@@ -9,7 +9,9 @@ context "All signed integers" do
|
|
9
9
|
BinData::Int16le,
|
10
10
|
BinData::Int16be,
|
11
11
|
BinData::Int32le,
|
12
|
-
BinData::Int32be
|
12
|
+
BinData::Int32be,
|
13
|
+
BinData::Int64le,
|
14
|
+
BinData::Int64be].each do |klass|
|
13
15
|
klass.new.value.should eql(0)
|
14
16
|
end
|
15
17
|
end
|
@@ -21,6 +23,8 @@ context "All signed integers" do
|
|
21
23
|
[2, true, BinData::Int16be],
|
22
24
|
[4, false, BinData::Int32le],
|
23
25
|
[4, true, BinData::Int32be],
|
26
|
+
[8, false, BinData::Int64le],
|
27
|
+
[8, true, BinData::Int64be],
|
24
28
|
].each do |nbytes, big_endian, klass|
|
25
29
|
gen_int_test_data(nbytes, big_endian).each do |val, clamped_val, str|
|
26
30
|
test_read_write(klass, val, clamped_val, str)
|
@@ -35,7 +39,9 @@ context "All unsigned integers" do
|
|
35
39
|
BinData::Uint16le,
|
36
40
|
BinData::Uint16be,
|
37
41
|
BinData::Uint32le,
|
38
|
-
BinData::Uint32be
|
42
|
+
BinData::Uint32be,
|
43
|
+
BinData::Uint64le,
|
44
|
+
BinData::Uint64be].each do |klass|
|
39
45
|
klass.new.value.should eql(0)
|
40
46
|
end
|
41
47
|
end
|
@@ -47,6 +53,8 @@ context "All unsigned integers" do
|
|
47
53
|
[2, true, BinData::Uint16be],
|
48
54
|
[4, false, BinData::Uint32le],
|
49
55
|
[4, true, BinData::Uint32be],
|
56
|
+
[8, false, BinData::Uint64le],
|
57
|
+
[8, true, BinData::Uint64be],
|
50
58
|
].each do |nbytes, big_endian, klass|
|
51
59
|
gen_uint_test_data(nbytes, big_endian).each do |val, clamped_val, str|
|
52
60
|
test_read_write(klass, val, clamped_val, str)
|
data/spec/struct_spec.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require File.expand_path(File.dirname(__FILE__)) + '/spec_common'
|
4
|
-
require 'bindata
|
5
|
-
require 'bindata/int'
|
4
|
+
require 'bindata'
|
6
5
|
|
7
6
|
context "A Struct with hidden fields" do
|
8
7
|
context_setup do
|
@@ -72,6 +71,16 @@ context "Defining a Struct" do
|
|
72
71
|
BinData::Struct.new(:fields => [[:int8, :object_id]])
|
73
72
|
}.should raise_error(NameError)
|
74
73
|
end
|
74
|
+
|
75
|
+
specify "should fail on unknown endian" do
|
76
|
+
lambda {
|
77
|
+
eval <<-END
|
78
|
+
class BadEndian < BinData::Struct
|
79
|
+
endian 'a bad value'
|
80
|
+
end
|
81
|
+
END
|
82
|
+
}.should raise_error(ArgumentError)
|
83
|
+
end
|
75
84
|
end
|
76
85
|
|
77
86
|
context "A Struct with multiple fields" do
|
@@ -202,3 +211,37 @@ context "A Struct with nested structs" do
|
|
202
211
|
end
|
203
212
|
end
|
204
213
|
|
214
|
+
context "A Struct with an endian defined" do
|
215
|
+
context_setup do
|
216
|
+
eval <<-END
|
217
|
+
class StructWithEndian < BinData::Struct
|
218
|
+
endian :little
|
219
|
+
|
220
|
+
uint16 :a
|
221
|
+
float :b
|
222
|
+
array :c, :type => :int8, :initial_length => 2
|
223
|
+
choice :d, :choices => [ [:uint16], [:uint32] ], :selection => 1
|
224
|
+
struct :e, :fields => [ [:uint16, :f], [:uint32be, :g] ]
|
225
|
+
end
|
226
|
+
END
|
227
|
+
@obj = StructWithEndian.new
|
228
|
+
end
|
229
|
+
|
230
|
+
specify "should use correct endian" do
|
231
|
+
@obj.a = 1
|
232
|
+
@obj.b = 2.0
|
233
|
+
@obj.c[0] = 3
|
234
|
+
@obj.c[1] = 4
|
235
|
+
@obj.d = 5
|
236
|
+
@obj.e.f = 6
|
237
|
+
@obj.e.g = 7
|
238
|
+
|
239
|
+
expected = [1, 2.0, 3, 4, 5, 6, 7].pack('veCCVvN')
|
240
|
+
|
241
|
+
io = StringIO.new
|
242
|
+
@obj.write(io)
|
243
|
+
|
244
|
+
io.rewind
|
245
|
+
io.read.should == expected
|
246
|
+
end
|
247
|
+
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: bindata
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2007-03-
|
6
|
+
version: 0.6.0
|
7
|
+
date: 2007-03-28 00:00:00 +08:00
|
8
8
|
summary: A declarative way to read and write binary file formats
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -47,6 +47,7 @@ files:
|
|
47
47
|
- spec/spec_common.rb
|
48
48
|
- spec/array_spec.rb
|
49
49
|
- spec/struct_spec.rb
|
50
|
+
- spec/float_spec.rb
|
50
51
|
- lib/bindata
|
51
52
|
- lib/bindata.rb
|
52
53
|
- lib/bindata/int.rb
|
@@ -59,6 +60,7 @@ files:
|
|
59
60
|
- lib/bindata/choice.rb
|
60
61
|
- lib/bindata/lazy.rb
|
61
62
|
- lib/bindata/single.rb
|
63
|
+
- lib/bindata/float.rb
|
62
64
|
test_files: []
|
63
65
|
|
64
66
|
rdoc_options:
|