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 CHANGED
@@ -1,5 +1,11 @@
1
1
  = BinData Changelog
2
2
 
3
+ == Version 0.6.0 (2007-03-28)
4
+
5
+ * Added 64 bit integers.
6
+ * Added floating point numbers.
7
+ * Added endian keyword to Struct to reduce the amount of typing needed.
8
+
3
9
  == Version 0.5.1 (2007-03-21)
4
10
 
5
11
  * Updated documentation.
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?
@@ -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.5.1"
13
+ VERSION = "0.6.0"
13
14
  end
@@ -35,7 +35,7 @@ module BinData
35
35
  super(params, env)
36
36
 
37
37
  type, el_params = param(:type)
38
- klass = self.class.lookup(type)
38
+ klass = klass_lookup(type)
39
39
  raise TypeError, "unknown type '#{type}' for #{self}" if klass.nil?
40
40
 
41
41
  @element_list = nil
@@ -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
@@ -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 = self.class.lookup(choice_type)
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
@@ -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 BaseUint #:nodoc: all
8
-
9
- def value=(val)
10
- super(clamp(val))
11
- end
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
- private
13
+ int2uint = "val = val & #{(1 << nbits) - 1}"
14
+ uint2int = "val = ((val & #{1 << (nbits - 1)}).zero?) ? " +
15
+ "val & #{max} : -(((~val) & #{max}) + 1)"
15
16
 
16
- def sensible_default
17
- 0
18
- end
17
+ read = create_read_code(nbits, endian)
18
+ to_s = create_to_s_code(nbits, endian)
19
19
 
20
- def val_to_str(val)
21
- _val_to_str(clamp(val))
20
+ define_methods(klass, nbits / 8, clamp, read, to_s, int2uint, uint2int)
22
21
  end
23
22
 
24
- # Clamps +val+ to the range 0 .. max_val
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 << (nbytes * 8)) - 1
30
- val = min if 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
- module BaseInt #:nodoc: all
37
- def uint2int(val)
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
- def int2uint(val)
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 value=(val)
51
- super(clamp(val))
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
- private
56
-
57
- def sensible_default
58
- 0
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 val_to_str(val)
62
- _val_to_str(int2uint(clamp(val)))
63
- end
64
-
65
- def read_val(io)
66
- uint2int(_read_val(io))
67
- end
68
-
69
- # Clamps +val+ to the range min_val .. max_val, where min and max
70
- # are the largest representable integers.
71
- def clamp(val)
72
- nbytes = val_num_bytes(0)
73
- max = (1 << (nbytes * 8 - 1)) - 1
74
- min = -(max + 1)
75
- val = min if val < min
76
- val = max if val > max
77
- val
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
- include BaseUint
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
- include BaseUint
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
- include BaseUint
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
- include BaseUint
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
- include BaseUint
121
- private
122
- def val_num_bytes(val) 4 end
123
- def read_val(io) readbytes(io,4).unpack("N")[0] end
124
- def _val_to_str(val) [val].pack("N") end
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
- include BaseInt
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
- include BaseInt
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
- include BaseInt
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
- include BaseInt
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
- include BaseInt
166
- private
167
- def val_num_bytes(val) 4 end
168
- def _read_val(io) readbytes(io,4).unpack("N")[0] end
169
- def _val_to_str(val) [val].pack("N") end
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
@@ -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
@@ -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 = self.class.lookup(type)
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)
@@ -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
@@ -9,7 +9,9 @@ context "All signed integers" do
9
9
  BinData::Int16le,
10
10
  BinData::Int16be,
11
11
  BinData::Int32le,
12
- BinData::Int32be].each do |klass|
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].each do |klass|
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)
@@ -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/struct'
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.5.1
7
- date: 2007-03-21 00:00:00 +09:00
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: