bindata 1.4.5 → 1.5.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.

@@ -1,5 +1,15 @@
1
1
  = BinData Changelog
2
2
 
3
+ == Version 1.5.0 (2013-05-21)
4
+
5
+ * Moved to github.
6
+ * Updated to Ruby 2.0
7
+ * Arrays now accept BinData object factories for :type (feature request by
8
+ Matt Dainty).
9
+ * Dynamically generated BinData objects can use the :name parameter to
10
+ register themselves.
11
+ * Remove functionality that has been deprecated for two years.
12
+
3
13
  == Version 1.4.5 (2012-07-24)
4
14
 
5
15
  * Added the :pad_front option for padding to occur at the front of a String.
@@ -22,7 +32,7 @@
22
32
 
23
33
  == Version 1.4.2 (2011-08-06)
24
34
 
25
- * =~ now works for strings.
35
+ * \=~ now works for strings.
26
36
 
27
37
  == Version 1.4.1 (2011-06-20)
28
38
 
@@ -1,3 +1,9 @@
1
+ = 1.5.0
2
+
3
+ Finally moved the source code to github.
4
+
5
+ Deprecated functionality has been removed to cleanup the codebase.
6
+
1
7
  = 1.4.4
2
8
 
3
9
  == Deprecations
@@ -31,7 +37,7 @@ It should be changed to:
31
37
  uint8 :initial_value => :initial_element_value
32
38
  end
33
39
 
34
- See http://bindata.rubyforge.org/#extending_existing_types for details.
40
+ See http://bindata.rubyforge.org/manual.html#extending_existing_types for details.
35
41
 
36
42
  = 1.3.0
37
43
 
@@ -0,0 +1,54 @@
1
+ # What is BinData?
2
+
3
+ Do you ever find yourself writing code like this?
4
+
5
+ ```ruby
6
+ io = File.open(...)
7
+ len = io.read(2).unpack("v")
8
+ name = io.read(len)
9
+ width, height = io.read(8).unpack("VV")
10
+ puts "Rectangle #{name} is #{width} x #{height}"
11
+ ```
12
+
13
+ It’s ugly, violates DRY and feels like you’re writing Perl, not Ruby.
14
+
15
+ There is a better way. Here’s how you’d write the above using BinData.
16
+
17
+ ```ruby
18
+ class Rectangle < BinData::Record
19
+ endian :little
20
+ uint16 :len
21
+ string :name, :read_length => :len
22
+ uint32 :width
23
+ uint32 :height
24
+ end
25
+
26
+ io = File.open(...)
27
+ r = Rectangle.read(io)
28
+ puts "Rectangle #{r.name} is #{r.width} x #{r.height}"
29
+ ```
30
+
31
+ BinData makes it easy to create new data types. It supports all the common
32
+ primitive datatypes that are found in structured binary data formats. Support
33
+ for dependent and variable length fields is built in.
34
+
35
+ # Installation
36
+
37
+ $ sudo gem install bindata
38
+
39
+ -or-
40
+
41
+ $ sudo ruby setup.rb
42
+
43
+ # Documentation
44
+
45
+ [http://bindata.rubyforge.org/manual.html](http://bindata.rubyforge.org/manual.html)
46
+
47
+ -or-
48
+
49
+ $ rake manual
50
+
51
+ # Contact
52
+
53
+ If you have any queries / bug reports / suggestions, please contact me
54
+ (Dion Mendel) via email at dion@lostrealm.com
@@ -1,5 +1,5 @@
1
1
  # BinData -- Binary data manipulator.
2
- # Copyright (c) 2007 - 2012 Dion Mendel.
2
+ # Copyright (c) 2007 - 2013 Dion Mendel.
3
3
 
4
4
  require 'bindata/array'
5
5
  require 'bindata/bits'
@@ -15,7 +15,6 @@ require 'bindata/string'
15
15
  require 'bindata/stringz'
16
16
  require 'bindata/struct'
17
17
  require 'bindata/trace'
18
- require 'bindata/wrapper'
19
18
  require 'bindata/alignment'
20
19
  require 'bindata/deprecated'
21
20
 
@@ -24,13 +23,13 @@ require 'bindata/deprecated'
24
23
  # A declarative way to read and write structured binary data.
25
24
  #
26
25
  # A full reference manual is available online at
27
- # http://bindata.rubyforge.org.
26
+ # http://bindata.rubyforge.org/manual.html
28
27
  #
29
28
  # == License
30
29
  #
31
30
  # BinData is released under the same license as Ruby.
32
31
  #
33
- # Copyright (c) 2007 - 2012 Dion Mendel.
32
+ # Copyright (c) 2007 - 2013 Dion Mendel.
34
33
  module BinData
35
- VERSION = "1.4.5"
34
+ VERSION = "1.5.0"
36
35
  end
@@ -82,6 +82,9 @@ module BinData
82
82
  # Register all subclasses of this class.
83
83
  register_subclasses
84
84
 
85
+ # The registered name may be provided explicitly.
86
+ optional_parameter :name
87
+
85
88
  # Creates a new data object.
86
89
  #
87
90
  # Args are optional, but if present, must be in the following order.
@@ -93,12 +96,27 @@ module BinData
93
96
  #
94
97
  # +parent+ is the parent data object (e.g. struct, array, choice) this
95
98
  # object resides under.
99
+ #
100
+ # == Parameters
101
+ #
102
+ # Parameters may be provided at initialisation to control the behaviour of
103
+ # an object. These params are:
104
+ #
105
+ # <tt>:name</tt>:: The name that this object can be referred to may be
106
+ # set explicitly. This is only useful when dynamically
107
+ # generating types.
108
+ # <code><pre>
109
+ # BinData::Struct.new(:name => :my_struct, :fields => ...)
110
+ # array = BinData::Array.new(:type => :my_struct)
111
+ # </pre></code>
112
+ #
96
113
  def initialize(*args)
97
114
  value, parameters, parent = extract_args(args)
98
115
 
99
116
  @params = SanitizedParameters.sanitize(parameters, self.class)
100
117
  @parent = parent
101
118
 
119
+ register_prototype
102
120
  add_methods_for_check_or_adjust_offset
103
121
 
104
122
  initialize_shared_instance
@@ -111,7 +129,7 @@ module BinData
111
129
 
112
130
  # Creates a new data object based on this instance.
113
131
  #
114
- # All parameters will be be duplicated. Use this method
132
+ # All parameters will be be duplicated. Use this method
115
133
  # when creating multiple objects with the same parameters.
116
134
  def new(value = nil, parent = nil)
117
135
  obj = clone
@@ -265,6 +283,12 @@ module BinData
265
283
  self.class.arg_extractor.extract(self.class, the_args)
266
284
  end
267
285
 
286
+ def register_prototype
287
+ if has_parameter?(:name)
288
+ RegisteredClasses.register(get_parameter(:name), self)
289
+ end
290
+ end
291
+
268
292
  def furthest_ancestor
269
293
  if parent.nil?
270
294
  self
@@ -275,6 +299,14 @@ module BinData
275
299
  end
276
300
  end
277
301
 
302
+ def binary_string(str)
303
+ if str.respond_to?(:force_encoding)
304
+ str.dup.force_encoding(Encoding::BINARY)
305
+ else
306
+ str.dup
307
+ end
308
+ end
309
+
278
310
  ###########################################################################
279
311
  # To be implemented by subclasses
280
312
 
@@ -18,15 +18,27 @@ end
18
18
  module BinData
19
19
  class Base
20
20
 
21
- alias_method :initialize_without_deprecation, :initialize
22
- def initialize_with_deprecation(*args)
21
+ # Don't override initialize. If you are defining a new kind of datatype
22
+ # (list, array, choice etc) then put your initialization code in
23
+ # #initialize_instance. This is because BinData objects can be initialized
24
+ # as prototypes and your initialization code may not be called.
25
+ #
26
+ # If you're subclassing BinData::Record, you are definitely doing the wrong
27
+ # thing. Read the documentation on how to use BinData.
28
+ # http://bindata.rubyforge.org/manual.html#records
29
+ alias_method :initialize_without_warning, :initialize
30
+ def initialize_with_warning(*args)
23
31
  owner = method(:initialize).owner
24
32
  if owner != BinData::Base
25
- fail "implementing #initialize on #{owner} is not allowed.\nEither downgrade to BinData 1.2.2, or rename #initialize to #initialize_instance."
33
+ msg = "Don't override #initialize on #{owner}."
34
+ if %w(BinData::Base BinData::BasePrimitive).include? self.class.superclass.name
35
+ msg += "\nrename #initialize to #initialize_instance."
36
+ end
37
+ fail msg
26
38
  end
27
- initialize_without_deprecation(*args)
39
+ initialize_without_warning(*args)
28
40
  end
29
- alias_method :initialize, :initialize_with_deprecation
41
+ alias_method :initialize, :initialize_with_warning
30
42
 
31
43
  def initialize_instance(*args)
32
44
  unless args.empty?
@@ -34,55 +46,5 @@ module BinData
34
46
  end
35
47
  end
36
48
 
37
- class << self
38
- def register_self
39
- warn "#{caller[0]} `register_self' is no longer needed as of BinData 1.3.2. You can delete this line"
40
- end
41
-
42
- def register(name, class_to_register)
43
- warn "#{caller[0]} `register' is no longer needed as of BinData 1.3.2. You can delete this line"
44
- end
45
- end
46
-
47
- def _do_read(io)
48
- warn "#{caller[0]} `_do_read(io)' is deprecated as of BinData 1.3.0. Replace with `do_read(io)'"
49
- do_read(io)
50
- end
51
-
52
- def _do_write(io)
53
- warn "#{caller[0]} `_do_write(io)' is deprecated as of BinData 1.3.0. Replace with `do_write(io)'"
54
- do_write(io)
55
- end
56
-
57
- def _do_num_bytes
58
- warn "#{caller[0]} `_do_num_bytes' is deprecated as of BinData 1.3.0. Replace with `do_num_bytes'"
59
- do_num_bytes
60
- end
61
-
62
- def _assign(val)
63
- warn "#{caller[0]} `_assign(val)' is deprecated as of BinData 1.3.0. Replace with `assign(val)'"
64
- assign(val)
65
- end
66
-
67
- def _snapshot
68
- warn "#{caller[0]} `_snapshot' is deprecated as of BinData 1.3.0. Replace with `snapshot'"
69
- snapshot
70
- end
71
- end
72
-
73
- class SingleValue
74
- class << self
75
- def inherited(subclass) #:nodoc:
76
- fail "BinData::SingleValue is deprecated. Downgrade to BinData 0.11.1.\nYou will need to make changes to your code before you can use BinData >= 1.0.0"
77
- end
78
- end
79
- end
80
-
81
- class MultiValue
82
- class << self
83
- def inherited(subclass) #:nodoc:
84
- fail "BinData::MultiValue is deprecated. Downgrade to BinData 0.11.1.\nYou will need to make changes to your code before you can use BinData >= 1.0.0"
85
- end
86
- end
87
49
  end
88
50
  end
@@ -90,8 +90,6 @@ module BinData
90
90
  to_choice_params
91
91
  when :primitive
92
92
  to_struct_params
93
- when :wrapper
94
- raise "Wrapper is deprecated"
95
93
  else
96
94
  raise "unknown parser type #{@parser_type}"
97
95
  end
@@ -122,8 +120,6 @@ module BinData
122
120
  [:multiple_fields, :all_or_none_fieldnames, :sanitize_fields, :fieldnames_are_values]
123
121
  when :primitive
124
122
  [:multiple_fields, :optional_fieldnames, :sanitize_fields]
125
- when :wrapper
126
- [:only_one_field, :no_fieldnames]
127
123
  else
128
124
  raise "unknown parser type #{parser_type}"
129
125
  end
@@ -7,7 +7,7 @@ module BinData
7
7
 
8
8
  # Creates a StringIO around +str+.
9
9
  def self.create_string_io(str = "")
10
- if RUBY_VERSION >= "1.9"
10
+ if str.respond_to?(:force_encoding)
11
11
  str = str.dup.force_encoding(Encoding::BINARY)
12
12
  end
13
13
  StringIO.new(str)
@@ -19,7 +19,7 @@ module BinData
19
19
  # +io+ is a string it will be automatically wrapped in an StringIO object.
20
20
  #
21
21
  # The IO can handle bitstreams in either big or little endian format.
22
- #
22
+ #
23
23
  # M byte1 L M byte2 L
24
24
  # S 76543210 S S fedcba98 S
25
25
  # B B B B
@@ -123,7 +123,7 @@ module BinData
123
123
  def self.invalid_parameter_names
124
124
  unless defined? @invalid_names
125
125
  all_names = LazyEvaluator.instance_methods(true) + Kernel.methods
126
- allowed_names = ["type", :type] # ruby 1.8 vs 1.9
126
+ allowed_names = ["name", "type", :name, :type] # ruby 1.8 vs 1.9
127
127
  invalid_names = (all_names - allowed_names).uniq
128
128
  @invalid_names = Hash[*invalid_names.collect { |key| [key.to_sym, true] }.flatten]
129
129
  end
@@ -16,11 +16,11 @@ module BinData
16
16
  # class PascalString < BinData::Primitive
17
17
  # uint8 :len, :value => lambda { data.length }
18
18
  # string :data, :read_length => :len
19
- #
19
+ #
20
20
  # def get
21
21
  # self.data
22
22
  # end
23
- #
23
+ #
24
24
  # def set(v)
25
25
  # self.data = v
26
26
  # end
@@ -10,8 +10,18 @@ module BinData
10
10
  endian = endian.endian if endian.respond_to? :endian
11
11
  obj_params ||= {}
12
12
 
13
- @obj_class = RegisteredClasses.lookup(obj_type, endian)
14
- @obj_params = SanitizedParameters.new(obj_params, @obj_class, endian)
13
+ if BinData::Base === obj_type
14
+ obj_class = obj_type
15
+ else
16
+ obj_class = RegisteredClasses.lookup(obj_type, endian)
17
+ end
18
+
19
+ if BinData::Base === obj_class
20
+ @factory = obj_class
21
+ else
22
+ @obj_class = obj_class
23
+ @obj_params = SanitizedParameters.new(obj_params, @obj_class, endian)
24
+ end
15
25
  end
16
26
 
17
27
  def instantiate(value = nil, parent = nil)
@@ -76,24 +76,17 @@ module BinData
76
76
  private
77
77
 
78
78
  def sanitized_pad_byte(byte)
79
- result = byte.is_a?(Integer) ? byte.chr : byte_string(byte.to_s.dup)
80
- if result.length > 1
79
+ result = byte.is_a?(Integer) ? byte.chr : byte.to_s
80
+ len = result.respond_to?(:bytesize) ? result.bytesize : result.length
81
+ if len > 1
81
82
  raise ArgumentError, ":pad_byte must not contain more than 1 byte"
82
83
  end
83
84
  result
84
85
  end
85
-
86
- def byte_string(str)
87
- if RUBY_VERSION >= "1.9"
88
- str.force_encoding(Encoding::BINARY)
89
- else
90
- str
91
- end
92
- end
93
86
  end
94
87
 
95
88
  def assign(val)
96
- super(byte_string(val.dup))
89
+ super(binary_string(val))
97
90
  end
98
91
 
99
92
  def snapshot
@@ -110,16 +103,8 @@ module BinData
110
103
  #---------------
111
104
  private
112
105
 
113
- def byte_string(str)
114
- if RUBY_VERSION >= "1.9"
115
- str.force_encoding(Encoding::BINARY)
116
- else
117
- str
118
- end
119
- end
120
-
121
106
  def clamp_to_length(str)
122
- str = byte_string(str)
107
+ str = binary_string(str)
123
108
 
124
109
  len = eval_parameter(:length) || str.length
125
110
  if str.length == len
@@ -29,8 +29,7 @@ module BinData
29
29
  optional_parameters :max_length
30
30
 
31
31
  def assign(val)
32
- val = val.dup.force_encoding(Encoding::BINARY) if RUBY_VERSION >= "1.9"
33
- super(val)
32
+ super(binary_string(val))
34
33
  end
35
34
 
36
35
  def snapshot
@@ -67,8 +66,7 @@ module BinData
67
66
  end
68
67
 
69
68
  def trim_and_zero_terminate(str)
70
- str.force_encoding(Encoding::BINARY) if RUBY_VERSION >= "1.9"
71
-
69
+ str = binary_string(str)
72
70
  str = truncate_after_first_zero_byte(str)
73
71
  str = trim_to(str, eval_parameter(:max_length))
74
72
  append_zero_byte_if_needed(str)
@@ -163,7 +163,7 @@ module BinData
163
163
  end
164
164
 
165
165
  def snapshot
166
- snapshot = Snapshot.new(field_names)
166
+ snapshot = Snapshot.new
167
167
  field_names.each do |name|
168
168
  obj = find_obj_for_name(name)
169
169
  snapshot[name] = obj.snapshot if include_obj(obj)
@@ -303,7 +303,7 @@ module BinData
303
303
  elsif val.nil?
304
304
  {}
305
305
  else
306
- hash = Snapshot.new(field_names)
306
+ hash = Snapshot.new
307
307
  val.each_pair { |k,v| hash[k] = v }
308
308
  hash
309
309
  end
@@ -330,18 +330,20 @@ module BinData
330
330
  not obj.has_parameter?(:onlyif) or obj.eval_parameter(:onlyif)
331
331
  end
332
332
 
333
- # A hash that can be accessed via attributes.
334
- class Snapshot < ::Hash #:nodoc:
335
- def initialize(order = [])
336
- @order = order.compact
337
- end
338
-
339
- if RUBY_VERSION <= "1.9"
333
+ if RUBY_VERSION <= "1.9"
334
+ module OrderedHash #:nodoc:
340
335
  def keys
336
+ @order ||= []
341
337
  k = super
342
338
  @order & k
343
339
  end
344
340
 
341
+ def []=(key, value)
342
+ @order ||= []
343
+ @order << key
344
+ super(key, value)
345
+ end
346
+
345
347
  def each
346
348
  keys.each do |k|
347
349
  yield [k, self[k]]
@@ -354,6 +356,11 @@ module BinData
354
356
  end
355
357
  end
356
358
  end
359
+ end
360
+
361
+ # A hash that can be accessed via attributes.
362
+ class Snapshot < ::Hash #:nodoc:
363
+ include OrderedHash if RUBY_VERSION <= "1.9"
357
364
 
358
365
  def has_key?(key)
359
366
  super(key.to_s)
@@ -354,6 +354,11 @@
354
354
  Extending existing Types
355
355
  .acc-section
356
356
  .acc-content
357
+ %li
358
+ %a{ :href => "#dynamically_creating_types" }
359
+ Dynamically creating Types
360
+ .acc-section
361
+ .acc-content
357
362
  %li
358
363
  %a{ :href => "#skipping_over_unused_data" }
359
364
  Skipping over unused data
data/manual.md CHANGED
@@ -40,13 +40,17 @@ manipulating.
40
40
  It supports all the common datatypes that are found in structured binary
41
41
  data. Support for dependent and variable length fields is built in.
42
42
 
43
- Last updated: 2012-07-24
43
+ Last updated: 2013-05-21
44
+
45
+ ## Source code
46
+
47
+ [BinData](http://github.com/dmendel/bindata) is hosted on Github.
44
48
 
45
49
  ## License
46
50
 
47
51
  BinData is released under the same license as Ruby.
48
52
 
49
- Copyright &copy; 2007 - 2012 [Dion Mendel](mailto:dion@lostrealm.com)
53
+ Copyright &copy; 2007 - 2013 [Dion Mendel](mailto:dion@lostrealm.com)
50
54
 
51
55
  ## Donate
52
56
 
@@ -57,13 +61,14 @@ Want to donate? My favourite local charity is
57
61
 
58
62
  # Installation
59
63
 
60
- You can install BinData via rubygems.
64
+ You can install BinData via rubygems (recommended).
61
65
 
62
66
  gem install bindata
63
67
 
64
- Alternatively, visit the
65
- [download](http://rubyforge.org/frs/?group_id=3252) page and download
66
- BinData as a tar file.
68
+ or as source package.
69
+
70
+ git clone http://github.com/dmendel/bindata.git
71
+ cd bindata && ruby setup.rb
67
72
 
68
73
  ---------------------------------------------------------------------------
69
74
 
@@ -1357,6 +1362,20 @@ We can also use the block form syntax:
1357
1362
  end
1358
1363
  {:ruby}
1359
1364
 
1365
+ ## Dynamically creating Types
1366
+
1367
+ Sometimes the format of a record is not known until runtime. You can use the
1368
+ `BinData::Struct` class to dynamically create a new type. To be able to reuse
1369
+ this type, you can give it a name.
1370
+
1371
+ # Dynamically create my_new_type
1372
+ BinData::Struct.new(:name => :my_new_type,
1373
+ :fields => [ [:int8, :a], [:int8, :b] ])
1374
+
1375
+ # Create an array of these types
1376
+ array = BinData::Array.new(:type => :my_new_type)
1377
+ {:ruby}
1378
+
1360
1379
  ## Skipping over unused data
1361
1380
 
1362
1381
  Some structures contain binary data that is irrelevant to your purposes.
@@ -1559,7 +1578,7 @@ decided by the `protocol` field.
1559
1578
  Modelling this structure can be difficult when the nesting is recursive, e.g.
1560
1579
  IP tunneling. Here is an example of the simplest possible recursive TLV structure,
1561
1580
  a [list that can contains atoms or other
1562
- lists](http://bindata.rubyforge.org/svn/trunk/examples/list.rb).
1581
+ lists](http://github.com/dmendel/bindata/blob/master/examples/list.rb).
1563
1582
 
1564
1583
  ---------------------------------------------------------------------------
1565
1584
 
@@ -30,6 +30,12 @@ describe BinData::Array, "when instantiating" do
30
30
  args = {:initial_length => 3, :read_until => lambda { false } }
31
31
  expect { BinData::Array.new(args) }.to raise_error(ArgumentError)
32
32
  end
33
+
34
+ it "accepts BinData::Base as :type" do
35
+ obj = BinData::Int8.new(:initial_value => 5)
36
+ array = BinData::Array.new(:type => obj, :initial_length => 1)
37
+ array.should == [5]
38
+ end
33
39
  end
34
40
 
35
41
  describe BinData::Array, "with no elements" do
@@ -4,24 +4,6 @@ require File.expand_path(File.join(File.dirname(__FILE__), "spec_common"))
4
4
  require File.expand_path(File.join(File.dirname(__FILE__), "example"))
5
5
  require 'bindata'
6
6
 
7
- describe BinData::SingleValue, "when defining" do
8
- it "fails when inheriting from deprecated SingleValue" do
9
- expect {
10
- class SubclassSingleValue < BinData::SingleValue
11
- end
12
- }.to raise_error
13
- end
14
- end
15
-
16
- describe BinData::MultiValue, "when defining" do
17
- it "fails inheriting from deprecated MultiValue" do
18
- expect {
19
- class SubclassMultiValue < BinData::MultiValue
20
- end
21
- }.to raise_error
22
- end
23
- end
24
-
25
7
  describe BinData::Base, "when defining" do
26
8
  it "fails if #initialize is overridden" do
27
9
  class BaseWithInitialize < BinData::Base
@@ -46,75 +28,4 @@ describe BinData::Base, "when defining" do
46
28
  BaseWithInitializeInstance.new
47
29
  }.not_to raise_error
48
30
  end
49
-
50
- it "handles deprecated #register_self method" do
51
- expect {
52
- class DeprecatedRegisterSelfBase < BinData::Base
53
- register_self
54
- end
55
- }.not_to raise_error
56
- end
57
-
58
- it "handles deprecated #register method" do
59
- expect {
60
- class DeprecatedRegisterBase < BinData::Base
61
- register(self.name, self)
62
- end
63
- }.not_to raise_error
64
- end
65
-
66
- it "handles deprecated #register method for subclasses" do
67
- expect {
68
- class DeprecatedSuperBase < BinData::Base
69
- def self.inherited(subclass)
70
- register(subclass.name, subclass)
71
- end
72
- end
73
-
74
- class DeprecatedSubBase < DeprecatedSuperBase
75
- end
76
- }.not_to raise_error
77
- end
78
-
79
- it "handles deprecated #register method with custom calling" do
80
- expect {
81
- class DeprecatedCustomBase < BinData::Base
82
- register(name, Object)
83
- end
84
- }.not_to raise_error
85
- end
86
- end
87
-
88
- describe BinData::Base do
89
- class DeprecatedBase < BinData::Base
90
- end
91
-
92
- subject { DeprecatedBase.new }
93
- let(:io) { "abcde" }
94
-
95
- it "forwards _do_read to do_read" do
96
- subject.should_receive(:do_read).with(io)
97
- subject._do_read(io)
98
- end
99
-
100
- it "forwards _do_write to do_write" do
101
- subject.should_receive(:do_write).with(io)
102
- subject._do_write(io)
103
- end
104
-
105
- it "forwards _do_num_bytes to do_num_bytes" do
106
- subject.should_receive(:do_num_bytes)
107
- subject._do_num_bytes
108
- end
109
-
110
- it "forwards _assign to assign" do
111
- val = 3
112
- subject.should_receive(:assign).with(val)
113
- subject._assign(val)
114
- end
115
-
116
- it "forwards _snapshot to snapshot" do
117
- subject.should_receive(:snapshot)
118
- subject._snapshot
119
- end
120
31
  end
@@ -129,7 +129,7 @@ shared_examples "All Integers" do
129
129
  end
130
130
 
131
131
  def int_to_binary_str(val)
132
- str = ""
132
+ str = binary("")
133
133
  v = val & ((1 << (@nbytes * 8)) - 1)
134
134
  @nbytes.times do
135
135
  str.concat(v & 0xff)
@@ -49,3 +49,10 @@ def raise_error_on_line(exception, line, &block)
49
49
  end
50
50
  end
51
51
 
52
+ def binary(str)
53
+ if str.respond_to?(:force_encoding)
54
+ str.dup.force_encoding(Encoding::BINARY)
55
+ else
56
+ str
57
+ end
58
+ end
@@ -269,7 +269,7 @@ describe BinData::String, "with Ruby 1.9 encodings" do
269
269
  end
270
270
 
271
271
  subject { UTF8String.new }
272
- let(:binary_str) { "\xC3\x85\xC3\x84\xC3\x96" }
272
+ let(:binary_str) { binary("\xC3\x85\xC3\x84\xC3\x96") }
273
273
  let(:utf8_str) { binary_str.dup.force_encoding('UTF-8') }
274
274
 
275
275
  it "stores assigned values as binary" do
@@ -338,3 +338,13 @@ describe BinData::Struct, "with nested endian" do
338
338
  subject.d.should == 4
339
339
  end
340
340
  end
341
+
342
+ describe BinData::Struct, "with dynamically named types" do
343
+ it "instantiates" do
344
+ dyn = BinData::Struct.new(:name => :my_struct, :fields => [[:int8, :a, {:initial_value => 3}]])
345
+
346
+ obj = BinData::Struct.new(:fields => [[:my_struct, :v]])
347
+
348
+ obj.v.a.should == 3
349
+ end
350
+ end
@@ -9,12 +9,12 @@ begin
9
9
  s.summary = 'A declarative way to read and write binary file formats'
10
10
  s.author = 'Dion Mendel'
11
11
  s.email = 'dion@lostrealm.com'
12
- s.homepage = 'http://bindata.rubyforge.org'
12
+ s.homepage = 'http://github.com/dmendel/bindata'
13
13
  s.rubyforge_project = 'bindata'
14
14
  s.require_path = 'lib'
15
15
  s.has_rdoc = true
16
- s.extra_rdoc_files = ['NEWS']
17
- s.rdoc_options << '--main' << 'NEWS'
16
+ s.extra_rdoc_files = ['NEWS.rdoc']
17
+ s.rdoc_options << '--main' << 'NEWS.rdoc'
18
18
  s.files = PKG_FILES
19
19
  s.add_development_dependency('rspec', [">= 2.10.0"])
20
20
  s.add_development_dependency('haml')
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bindata
3
3
  version: !ruby/object:Gem::Version
4
- hash: 13
4
+ hash: 3
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
- - 4
9
8
  - 5
10
- version: 1.4.5
9
+ - 0
10
+ version: 1.5.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Dion Mendel
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-07-24 00:00:00 Z
18
+ date: 2013-05-21 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: rspec
@@ -89,14 +89,14 @@ executables: []
89
89
  extensions: []
90
90
 
91
91
  extra_rdoc_files:
92
- - NEWS
92
+ - NEWS.rdoc
93
93
  files:
94
- - ChangeLog
95
- - NEWS
94
+ - NEWS.rdoc
96
95
  - COPYING
96
+ - README.md
97
97
  - BSDL
98
- - README
99
98
  - Rakefile
99
+ - ChangeLog.rdoc
100
100
  - INSTALL
101
101
  - examples/ip_address.rb
102
102
  - examples/list.rb
@@ -124,7 +124,6 @@ files:
124
124
  - spec/string_spec.rb
125
125
  - spec/base_spec.rb
126
126
  - spec/registry_spec.rb
127
- - spec/wrapper_spec.rb
128
127
  - spec/skip_spec.rb
129
128
  - spec/float_spec.rb
130
129
  - lib/bindata/count_bytes_remaining.rb
@@ -144,7 +143,6 @@ files:
144
143
  - lib/bindata/base_primitive.rb
145
144
  - lib/bindata/struct.rb
146
145
  - lib/bindata/bits.rb
147
- - lib/bindata/wrapper.rb
148
146
  - lib/bindata/offset.rb
149
147
  - lib/bindata/record.rb
150
148
  - lib/bindata/dsl.rb
@@ -161,13 +159,13 @@ files:
161
159
  - setup.rb
162
160
  - manual.haml
163
161
  - manual.md
164
- homepage: http://bindata.rubyforge.org
162
+ homepage: http://github.com/dmendel/bindata
165
163
  licenses: []
166
164
 
167
165
  post_install_message:
168
166
  rdoc_options:
169
167
  - --main
170
- - NEWS
168
+ - NEWS.rdoc
171
169
  require_paths:
172
170
  - lib
173
171
  required_ruby_version: !ruby/object:Gem::Requirement
data/README DELETED
@@ -1,50 +0,0 @@
1
- = What is BinData?
2
-
3
- Do you ever find yourself writing code like this?
4
-
5
- io = File.open(...)
6
- len = io.read(2).unpack("v")
7
- name = io.read(len)
8
- width, height = io.read(8).unpack("VV")
9
- puts "Rectangle #{name} is #{width} x #{height}"
10
-
11
- It’s ugly, violates DRY and feels like you’re writing Perl, not Ruby.
12
-
13
- There is a better way. Here’s how you’d write the above using BinData.
14
-
15
- class Rectangle < BinData::Record
16
- endian :little
17
- uint16 :len
18
- string :name, :read_length => :len
19
- uint32 :width
20
- uint32 :height
21
- end
22
-
23
- io = File.open(...)
24
- r = Rectangle.read(io)
25
- puts "Rectangle #{r.name} is #{r.width} x #{r.height}"
26
-
27
- BinData makes it easy to create new data types. It supports all the common
28
- primitive datatypes that are found in structured binary data formats. Support
29
- for dependent and variable length fields is built in.
30
-
31
- = Installation
32
-
33
- $ sudo gem install bindata
34
-
35
- -or-
36
-
37
- $ sudo ruby setup.rb
38
-
39
- = Documentation
40
-
41
- http://bindata.rubyforge.org/
42
-
43
- -or-
44
-
45
- $ rake manual
46
-
47
- = Contact
48
-
49
- If you have any queries / bug reports / suggestions, please contact me
50
- (Dion Mendel) via email at dion@lostrealm.com
@@ -1,121 +0,0 @@
1
- require 'bindata/base'
2
- require 'bindata/dsl'
3
-
4
- module BinData
5
- class SanitizedParameters < Hash
6
- def move_unknown_parameters_to(dest)
7
- unused_keys = keys - @the_class.accepted_parameters.all
8
- unused_keys.each do |key|
9
- dest[key] = delete(key)
10
- end
11
- end
12
- end
13
-
14
- # A Wrapper allows the creation of new BinData types that
15
- # provide default parameters.
16
- #
17
- # require 'bindata'
18
- #
19
- # class Uint8Array < BinData::Wrapper
20
- # default_parameter :initial_element_value => 0
21
- #
22
- # array :initial_length => 2 do
23
- # uint8 :initial_value => :initial_element_value
24
- # end
25
- # end
26
- #
27
- # arr = Uint8Array.new
28
- # arr.snapshot #=> [0, 0]
29
- #
30
- # arr = Uint8Array.new(:initial_length => 5, :initial_element_value => 3)
31
- # arr.snapshot #=> [3, 3, 3, 3 ,3]
32
- #
33
- class Wrapper < BinData::Base
34
- include DSLMixin
35
-
36
- unregister_self
37
- dsl_parser :wrapper
38
-
39
- class << self
40
- def sanitize_parameters!(params) #:nodoc:
41
- raise "no wrapped type was specified in #{self}" if fields[0].nil?
42
-
43
- wrapped_type = fields[0].type
44
- wrapped_params = fields[0].params.dup
45
-
46
- params.move_unknown_parameters_to(wrapped_params)
47
-
48
- params.endian = endian unless endian.nil?
49
- params[:wrapped] = params.create_sanitized_object_prototype(wrapped_type, wrapped_params)
50
-
51
- wrapped_class = params[:wrapped].instance_variable_get(:@obj_class)
52
- warn "BinData::Wrapper is deprecated as of BinData 1.3.2. #{self} should derive from #{wrapped_class}\n See http://bindata.rubyforge.org/#extending_existing_types"
53
- end
54
- end
55
-
56
- mandatory_parameter :wrapped
57
-
58
- def initialize_instance
59
- prototype = get_parameter(:wrapped)
60
- @wrapped = prototype.instantiate(nil, self)
61
- end
62
-
63
- def clear #:nodoc:
64
- @wrapped.clear
65
- end
66
-
67
- def clear? #:nodoc:
68
- @wrapped.clear?
69
- end
70
-
71
- def assign(val)
72
- @wrapped.assign(val)
73
- end
74
-
75
- def snapshot
76
- @wrapped.snapshot
77
- end
78
-
79
- def respond_to?(symbol, include_private = false) #:nodoc:
80
- @wrapped.respond_to?(symbol, include_private) || super
81
- end
82
-
83
- def method_missing(symbol, *args, &block) #:nodoc:
84
- @wrapped.__send__(symbol, *args, &block)
85
- end
86
-
87
- def do_read(io) #:nodoc:
88
- @wrapped.do_read(io)
89
- end
90
-
91
- def do_write(io) #:nodoc
92
- @wrapped.do_write(io)
93
- end
94
-
95
- def do_num_bytes #:nodoc:
96
- @wrapped.do_num_bytes
97
- end
98
-
99
- #---------------
100
- private
101
-
102
- def extract_args(args)
103
- klass = wrapped_class
104
- if klass
105
- klass.arg_extractor.extract(klass, args)
106
- else
107
- super
108
- end
109
- end
110
-
111
- def wrapped_class
112
- return nil if self.class.fields[0].nil?
113
-
114
- begin
115
- RegisteredClasses.lookup(self.class.fields[0].type, self.class.endian)
116
- rescue BinData::UnRegisteredTypeError
117
- nil
118
- end
119
- end
120
- end
121
- end
@@ -1,185 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require File.expand_path(File.join(File.dirname(__FILE__), "spec_common"))
4
- require 'bindata'
5
-
6
- describe BinData::Wrapper do
7
- it "is not registered" do
8
- expect {
9
- BinData::RegisteredClasses.lookup("Wrapper")
10
- }.to raise_error(BinData::UnRegisteredTypeError)
11
- end
12
- end
13
-
14
- describe BinData::Wrapper, "with errors" do
15
- it "does not wrap more than one type" do
16
- lambda {
17
- class WrappedMultipleTypes < BinData::Wrapper
18
- uint8
19
- uint8
20
- end
21
- }.should raise_error_on_line(SyntaxError, 3) { |err|
22
- err.message.should == "attempting to wrap more than one type in #{WrappedMultipleTypes}"
23
- }
24
- end
25
-
26
- it "fails if wrapped type has a name" do
27
- lambda {
28
- class WrappedWithName < BinData::Wrapper
29
- uint8 :a
30
- end
31
- }.should raise_error_on_line(SyntaxError, 2) { |err|
32
- err.message.should == "field must not have a name in #{WrappedWithName}"
33
- }
34
- end
35
-
36
- it "fails if no types to wrap" do
37
- class WrappedNoTypes < BinData::Wrapper
38
- end
39
-
40
- lambda {
41
- WrappedNoTypes.new
42
- }.should raise_error(RuntimeError) { |err|
43
- err.message.should == "no wrapped type was specified in #{WrappedNoTypes}"
44
- }
45
- end
46
- end
47
-
48
- describe BinData::Wrapper, "around a Primitive" do
49
- class WrappedPrimitive < BinData::Wrapper
50
- default_parameter :a => 3
51
-
52
- uint8 :initial_value => :a
53
- end
54
-
55
- it "accesses custom parameter" do
56
- subject = WrappedPrimitive.new
57
- subject.assign(3)
58
- subject.should == 3
59
- end
60
-
61
- it "overrides custom default parameter" do
62
- subject = WrappedPrimitive.new(:a => 5)
63
- subject.should == 5
64
- end
65
-
66
- it "overrides parameter" do
67
- subject = WrappedPrimitive.new(:initial_value => 7)
68
- subject.should == 7
69
- end
70
-
71
- it "clears" do
72
- subject = WrappedPrimitive.new
73
- subject.assign(3)
74
- subject.should_not be_clear
75
-
76
- subject.clear
77
- subject.should be_clear
78
- end
79
-
80
- it "reads" do
81
- subject = WrappedPrimitive.new
82
- subject.assign(3)
83
- str = subject.to_binary_s
84
-
85
- WrappedPrimitive.read(str).should == 3
86
- end
87
-
88
- it "respond_to and forward messages to the wrapped object" do
89
- subject = WrappedPrimitive.new
90
- subject.assign(5)
91
-
92
- subject.should respond_to(:to_int)
93
- subject.to_int.should == 5
94
- end
95
- end
96
-
97
- describe BinData::Wrapper, "around an Array" do
98
- class WrappedIntArray < BinData::Wrapper
99
- endian :big
100
- default_parameter :initial_element_value => 0
101
- array do
102
- uint16 :initial_value => :initial_element_value
103
- end
104
- end
105
-
106
- it "forwards parameters" do
107
- subject = WrappedIntArray.new(:initial_length => 7)
108
- subject.length.should == 7
109
- end
110
-
111
- it "overrides default parameters" do
112
- subject = WrappedIntArray.new(:initial_length => 3, :initial_element_value => 5)
113
- subject.to_binary_s.should == "\x00\x05\x00\x05\x00\x05"
114
- end
115
- end
116
-
117
- describe BinData::Wrapper, "around a Choice" do
118
- class WrappedChoice < BinData::Wrapper
119
- endian :big
120
- choice :choices => { 'a' => :uint8, 'b' => :uint16 }
121
- end
122
-
123
- it "forwards parameters" do
124
- subject = WrappedChoice.new(:selection => 'b')
125
- subject.num_bytes.should == 2
126
- end
127
- end
128
-
129
- describe BinData::Wrapper, "inside a Record" do
130
- class WrappedUint32le < BinData::Wrapper
131
- uint32le
132
- end
133
-
134
- class RecordWithWrapped < BinData::Record
135
- wrapped_uint32le :a, :onlyif => false, :value => 1
136
- wrapped_uint32le :b, :onlyif => true, :value => 2
137
- end
138
-
139
- it "handles onlyif" do
140
- subject = RecordWithWrapped.new
141
- subject.should == {'b' => 2}
142
- end
143
- end
144
-
145
- describe BinData::Wrapper, "around a Record" do
146
- class RecordToBeWrapped < BinData::Record
147
- default_parameter :arg => 3
148
- uint8 :a, :initial_value => :arg
149
- uint8 :b
150
- end
151
-
152
- class WrappedRecord < BinData::Wrapper
153
- record_to_be_wrapped
154
- end
155
-
156
- it "forwards parameters" do
157
- subject = WrappedRecord.new(:arg => 5)
158
- subject.a.should == 5
159
- end
160
-
161
- it "assigns value" do
162
- subject = WrappedRecord.new(:b => 5)
163
- subject.b.should == 5
164
- end
165
-
166
- it "assigns value and forward parameters" do
167
- subject = WrappedRecord.new({:b => 5}, :arg => 7)
168
- subject.a.should == 7
169
- subject.b.should == 5
170
- end
171
- end
172
-
173
- describe BinData::Wrapper, "derived classes" do
174
- class ParentDerivedWrapper < BinData::Wrapper
175
- uint32le
176
- end
177
-
178
- class ChildDerivedWrapper < ParentDerivedWrapper
179
- end
180
-
181
- it "wraps" do
182
- a = ChildDerivedWrapper.new
183
- a.num_bytes.should == 4
184
- end
185
- end