bindata 1.2.2 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of bindata might be problematic. Click here for more details.

Files changed (52) hide show
  1. data/ChangeLog +12 -0
  2. data/NEWS +53 -0
  3. data/Rakefile +2 -1
  4. data/examples/NBT.txt +149 -0
  5. data/examples/ip_address.rb +1 -2
  6. data/examples/list.rb +124 -0
  7. data/examples/nbt.rb +195 -0
  8. data/lib/bindata.rb +4 -3
  9. data/lib/bindata/alignment.rb +86 -0
  10. data/lib/bindata/array.rb +21 -29
  11. data/lib/bindata/base.rb +82 -81
  12. data/lib/bindata/base_primitive.rb +66 -48
  13. data/lib/bindata/choice.rb +18 -28
  14. data/lib/bindata/deprecated.rb +17 -0
  15. data/lib/bindata/dsl.rb +25 -15
  16. data/lib/bindata/int.rb +2 -2
  17. data/lib/bindata/io.rb +8 -6
  18. data/lib/bindata/offset.rb +91 -0
  19. data/lib/bindata/primitive.rb +22 -11
  20. data/lib/bindata/record.rb +40 -10
  21. data/lib/bindata/sanitize.rb +15 -30
  22. data/lib/bindata/string.rb +16 -17
  23. data/lib/bindata/stringz.rb +0 -1
  24. data/lib/bindata/struct.rb +17 -6
  25. data/lib/bindata/trace.rb +52 -0
  26. data/lib/bindata/wrapper.rb +28 -6
  27. data/manual.haml +56 -10
  28. data/manual.md +318 -113
  29. data/spec/alignment_spec.rb +61 -0
  30. data/spec/array_spec.rb +139 -178
  31. data/spec/base_primitive_spec.rb +86 -111
  32. data/spec/base_spec.rb +200 -172
  33. data/spec/bits_spec.rb +45 -53
  34. data/spec/choice_spec.rb +91 -87
  35. data/spec/deprecated_spec.rb +36 -14
  36. data/spec/float_spec.rb +16 -68
  37. data/spec/int_spec.rb +26 -27
  38. data/spec/io_spec.rb +105 -105
  39. data/spec/lazy_spec.rb +50 -50
  40. data/spec/primitive_spec.rb +36 -36
  41. data/spec/record_spec.rb +134 -134
  42. data/spec/registry_spec.rb +34 -38
  43. data/spec/rest_spec.rb +8 -11
  44. data/spec/skip_spec.rb +9 -17
  45. data/spec/spec_common.rb +4 -0
  46. data/spec/string_spec.rb +92 -115
  47. data/spec/stringz_spec.rb +41 -74
  48. data/spec/struct_spec.rb +132 -153
  49. data/spec/system_spec.rb +115 -60
  50. data/spec/wrapper_spec.rb +63 -31
  51. data/tasks/pkg.rake +1 -1
  52. metadata +15 -7
@@ -13,37 +13,20 @@ module BinData
13
13
  # SanitizedParameters is a hash-like collection of parameters. Its purpose
14
14
  # it to recursively sanitize the parameters of an entire BinData object chain
15
15
  # at a single time.
16
- class SanitizedParameters
16
+ class SanitizedParameters < Hash
17
17
 
18
18
  def initialize(parameters, the_class)
19
+ parameters.each_pair { |key, value| self[key.to_sym] = value }
20
+
19
21
  @all_sanitized = false
20
22
  @the_class = the_class
21
-
22
- @parameters = {}
23
- parameters.each { |key, value| @parameters[key.to_sym] = value }
24
-
25
23
  ensure_no_nil_values
26
24
  end
27
25
 
28
- def length
29
- @parameters.size
30
- end
31
- alias_method :size, :length
32
-
33
- def [](key)
34
- @parameters[key]
35
- end
36
-
37
- def []=(key, value)
38
- @parameters[key] = value unless @all_sanitized
39
- end
40
-
41
- def has_parameter?(key)
42
- @parameters.has_key?(key)
43
- end
26
+ alias_method :has_parameter?, :has_key?
44
27
 
45
28
  def needs_sanitizing?(key)
46
- parameter = @parameters[key]
29
+ parameter = self[key]
47
30
 
48
31
  parameter and not parameter.is_a?(SanitizedParameter)
49
32
  end
@@ -67,9 +50,9 @@ module BinData
67
50
 
68
51
  def move_unknown_parameters_to(dest)
69
52
  unless @all_sanitized
70
- unused_keys = @parameters.keys - @the_class.accepted_parameters.all
53
+ unused_keys = keys - @the_class.accepted_parameters.all
71
54
  unused_keys.each do |key|
72
- dest[key] = @parameters.delete(key)
55
+ dest[key] = delete(key)
73
56
  end
74
57
  end
75
58
  end
@@ -85,7 +68,7 @@ module BinData
85
68
  private
86
69
 
87
70
  def ensure_no_nil_values
88
- @parameters.each do |key, value|
71
+ each do |key, value|
89
72
  if value.nil?
90
73
  raise ArgumentError,
91
74
  "parameter '#{key}' has nil value in #{@the_class}"
@@ -95,7 +78,7 @@ module BinData
95
78
 
96
79
  def merge_default_parameters!
97
80
  @the_class.default_parameters.each do |key, value|
98
- @parameters[key] ||= value
81
+ self[key] ||= value
99
82
  end
100
83
  end
101
84
 
@@ -215,8 +198,10 @@ module BinData
215
198
  end
216
199
  end
217
200
 
218
- def instantiate(parent = nil)
219
- @obj_class.new(@obj_params, parent)
201
+ def instantiate(value = nil, parent = nil)
202
+ @factory ||= @obj_class.new(@obj_params)
203
+
204
+ @factory.new(value, parent)
220
205
  end
221
206
  end
222
207
  #----------------------------------------------------------------------------
@@ -228,8 +213,8 @@ module BinData
228
213
  end
229
214
  attr_reader :name
230
215
 
231
- def instantiate(parent = nil)
232
- @prototype.instantiate(parent)
216
+ def instantiate(value = nil, parent = nil)
217
+ @prototype.instantiate(value, parent)
233
218
  end
234
219
  end
235
220
  #----------------------------------------------------------------------------
@@ -10,24 +10,24 @@ module BinData
10
10
  #
11
11
  # obj = BinData::String.new(:read_length => 5)
12
12
  # obj.read(data)
13
- # obj.value #=> "abcde"
13
+ # obj #=> "abcde"
14
14
  #
15
15
  # obj = BinData::String.new(:length => 6)
16
16
  # obj.read(data)
17
- # obj.value #=> "abcdef"
18
- # obj.value = "abcdefghij"
19
- # obj.value #=> "abcdef"
20
- # obj.value = "abcd"
21
- # obj.value #=> "abcd\000\000"
17
+ # obj #=> "abcdef"
18
+ # obj.assign("abcdefghij")
19
+ # obj #=> "abcdef"
20
+ # obj.assign("abcd")
21
+ # obj #=> "abcd\000\000"
22
22
  #
23
23
  # obj = BinData::String.new(:length => 6, :trim_padding => true)
24
- # obj.value = "abcd"
25
- # obj.value #=> "abcd"
24
+ # obj.assign("abcd")
25
+ # obj #=> "abcd"
26
26
  # obj.to_binary_s #=> "abcd\000\000"
27
27
  #
28
28
  # obj = BinData::String.new(:length => 6, :pad_char => 'A')
29
- # obj.value = "abcd"
30
- # obj.value #=> "abcdAA"
29
+ # obj.assign("abcd")
30
+ # obj #=> "abcdAA"
31
31
  # obj.to_binary_s #=> "abcdAA"
32
32
  #
33
33
  # == Parameters
@@ -83,12 +83,11 @@ module BinData
83
83
  end
84
84
 
85
85
  def snapshot
86
- # override to ensure length and optionally trim padding
86
+ # override to trim padding
87
87
  result = super
88
- if has_parameter?(:length)
89
- result = truncate_or_pad_to_length(result)
90
- end
91
- if get_parameter(:trim_padding) == true
88
+ result = clamp_to_length(result)
89
+
90
+ if get_parameter(:trim_padding)
92
91
  result = trim_padding(result)
93
92
  end
94
93
  result
@@ -97,7 +96,7 @@ module BinData
97
96
  #---------------
98
97
  private
99
98
 
100
- def truncate_or_pad_to_length(str)
99
+ def clamp_to_length(str)
101
100
  len = eval_parameter(:length) || str.length
102
101
  if str.length == len
103
102
  str
@@ -113,7 +112,7 @@ module BinData
113
112
  end
114
113
 
115
114
  def value_to_binary_string(val)
116
- truncate_or_pad_to_length(val)
115
+ clamp_to_length(val)
117
116
  end
118
117
 
119
118
  def read_and_return_value(io)
@@ -14,7 +14,6 @@ module BinData
14
14
  # obj = BinData::Stringz.new
15
15
  # obj.read(data)
16
16
  # obj.snapshot #=> "abcd"
17
- # obj.value #=> "abcd"
18
17
  # obj.num_bytes #=> 5
19
18
  # obj.to_binary_s #=> "abcd\000"
20
19
  #
@@ -1,6 +1,11 @@
1
1
  require 'bindata/base'
2
2
 
3
3
  module BinData
4
+
5
+ class Base
6
+ optional_parameter :onlyif # Used by Struct
7
+ end
8
+
4
9
  # A Struct is an ordered collection of named data objects.
5
10
  #
6
11
  # require 'bindata'
@@ -119,7 +124,12 @@ module BinData
119
124
  end
120
125
 
121
126
  def hidden_field_names(hidden)
122
- (hidden || []).collect { |h| h.to_s }
127
+ (hidden || []).collect do |h|
128
+ unless Symbol === h
129
+ warn "Hidden field '#{h}' should be provided as a symbol. Using strings is deprecated"
130
+ end
131
+ h.to_s # TODO: change this to sym
132
+ end
123
133
  end
124
134
 
125
135
  def ensure_field_names_are_valid(field_names)
@@ -142,10 +152,11 @@ module BinData
142
152
  end
143
153
  end
144
154
 
145
- def initialize(parameters = {}, parent = nil)
146
- super
155
+ def initialize_shared_instance
156
+ @field_names = get_parameter(:fields).field_names.freeze
157
+ end
147
158
 
148
- @field_names = get_parameter(:fields).field_names
159
+ def initialize_instance
149
160
  @field_objs = []
150
161
  end
151
162
 
@@ -219,7 +230,7 @@ module BinData
219
230
 
220
231
  def do_num_bytes #:nodoc:
221
232
  instantiate_all_objs
222
- sum_num_bytes_for_all_fields.ceil
233
+ sum_num_bytes_for_all_fields
223
234
  end
224
235
 
225
236
  #---------------
@@ -258,7 +269,7 @@ module BinData
258
269
  def instantiate_obj_at(index)
259
270
  if @field_objs[index].nil?
260
271
  field = get_parameter(:fields)[index]
261
- @field_objs[index] = field.instantiate(self)
272
+ @field_objs[index] = field.instantiate(nil, self)
262
273
  end
263
274
  end
264
275
 
@@ -25,10 +25,14 @@ module BinData
25
25
  # This is useful for debugging a BinData declaration.
26
26
  def trace_reading(io = STDERR, &block)
27
27
  @tracer = Tracer.new(io)
28
+ BasePrimitive.turn_on_tracing
29
+ Choice.turn_on_tracing
28
30
  if block_given?
29
31
  begin
30
32
  block.call
31
33
  ensure
34
+ BasePrimitive.turn_off_tracing
35
+ Choice.turn_off_tracing
32
36
  @tracer = nil
33
37
  end
34
38
  end
@@ -39,4 +43,52 @@ module BinData
39
43
  end
40
44
 
41
45
  module_function :trace_reading, :trace_message
46
+
47
+ class BasePrimitive < BinData::Base
48
+ class << self
49
+ def turn_on_tracing
50
+ alias_method :hook_after_do_read, :trace_value
51
+ end
52
+
53
+ def turn_off_tracing
54
+ alias_method :hook_after_do_read, :null_method
55
+ end
56
+ end
57
+
58
+ #---------------
59
+ private
60
+
61
+ def null_method; end
62
+
63
+ def trace_value
64
+ BinData::trace_message do |tracer|
65
+ value_string = _value.inspect
66
+ tracer.trace_obj(debug_name, value_string)
67
+ end
68
+ end
69
+ end
70
+
71
+ class Choice < BinData::Base
72
+ class << self
73
+ def turn_on_tracing
74
+ alias_method :hook_before_do_read, :trace_selection
75
+ end
76
+
77
+ def turn_off_tracing
78
+ alias_method :hook_before_do_read, :null_method
79
+ end
80
+ end
81
+
82
+ #---------------
83
+ private
84
+
85
+ def null_method; end
86
+
87
+ def trace_selection
88
+ BinData::trace_message do |tracer|
89
+ selection_string = eval_parameter(:selection).inspect
90
+ tracer.trace_obj("#{debug_name}-selection-", selection_string)
91
+ end
92
+ end
93
+ end
42
94
  end
@@ -9,8 +9,10 @@ module BinData
9
9
  #
10
10
  # class Uint8Array < BinData::Wrapper
11
11
  # default_parameter :initial_element_value => 0
12
- # array :type => [:uint8, {:initial_value => :initial_element_value}],
13
- # :initial_length => 2
12
+ #
13
+ # array :initial_length => 2 do
14
+ # uint8 :initial_value => :initial_element_value
15
+ # end
14
16
  # end
15
17
  #
16
18
  # arr = Uint8Array.new
@@ -40,11 +42,9 @@ module BinData
40
42
 
41
43
  mandatory_parameter :wrapped
42
44
 
43
- def initialize(parameters = {}, parent = nil)
44
- super
45
-
45
+ def initialize_instance
46
46
  prototype = get_parameter(:wrapped)
47
- @wrapped = prototype.instantiate(self)
47
+ @wrapped = prototype.instantiate(nil, self)
48
48
  end
49
49
 
50
50
  def clear #:nodoc:
@@ -82,5 +82,27 @@ module BinData
82
82
  def do_num_bytes #:nodoc:
83
83
  @wrapped.do_num_bytes
84
84
  end
85
+
86
+ #---------------
87
+ private
88
+
89
+ def extract_args(args)
90
+ klass = wrapped_class
91
+ if klass
92
+ klass.arg_extractor.extract(klass, args)
93
+ else
94
+ super
95
+ end
96
+ end
97
+
98
+ def wrapped_class
99
+ return nil if self.class.field.nil?
100
+
101
+ begin
102
+ RegisteredClasses.lookup(self.class.field.type, self.class.endian)
103
+ rescue BinData::UnRegisteredTypeError
104
+ nil
105
+ end
106
+ end
85
107
  end
86
108
  end
@@ -2,16 +2,18 @@
2
2
  %html{ :xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en", :lang => "en" }
3
3
  %head
4
4
  %meta{ :content => "text/html; charset=iso-8859-1", "http-equiv" => "Content-Type" }
5
+ %meta{ :description =>"How to easily parse binary data in Ruby" }
6
+ %meta{ :keywords =>"ruby, parse binary data, read binary data" }
5
7
  %title
6
- BinData Reference Manual
8
+ Parsing Binary Data in Ruby - BinData Reference Manual
7
9
  :javascript
8
10
  var TINY={};function T$(i){return document.getElementById(i)}function T$$(e,p){return p.getElementsByTagName(e)}TINY.accordion=function(){function slider(n){this.n=n;this.a=[]}slider.prototype.init=function(t,e,m,o,k){var a=T$(t),i=s=0,n=a.childNodes,l=n.length;this.s=k||0;this.m=m||0;for(i;i<l;i++){var v=n[i];if(v.nodeType!=3){this.a[s]={};this.a[s].h=h=T$$(e,v)[0];this.a[s].c=c=T$$('div',v)[0];h.onclick=new Function(this.n+'.pr(0,'+s+')');if(o==s){h.className=this.s;c.style.height='auto';c.d=1}else{c.style.height=0;c.d=-1}s++}}this.l=s};slider.prototype.pr=function(f,d){for(var i=0;i<this.l;i++){var h=this.a[i].h,c=this.a[i].c,k=c.style.height;k=k=='auto'?1:parseInt(k);clearInterval(c.t);if((k!=1&&c.d==-1)&&(f==1||i==d)){c.style.height='';c.m=c.offsetHeight;c.style.height=k+'px';c.d=1;h.className=this.s;su(c,1)}else if(k>0&&(f==-1||this.m||i==d)){c.d=-1;h.className='';su(c,-1)}}};function su(c){c.t=setInterval(function(){sl(c)},20)};function sl(c){var h=c.offsetHeight,d=c.d==1?c.m-h:h;c.style.height=h+(Math.ceil(d/5)*c.d)+'px';c.style.opacity=h/c.m;c.style.filter='alpha(opacity='+h*100/c.m+')';if((c.d==1&&h>=c.m)||(c.d!=1&&h==1)){if(c.d==1){c.style.height='auto'}clearInterval(c.t)}};return{slider:slider}}();
9
11
 
10
12
  var menu1, menu2, menu3, menu4, menu5, menu6;
11
- var menu7, menu8, menu9, menu10, menu11;
13
+ var menu7, menu8, menu9, menu10, menu11, menu12, menu13;
12
14
 
13
15
  function init_accordion() {
14
- menu1 = new TINY.accordion.slider("menu1"); menu1.init("menu1","a",1,0);
16
+ menu1 = new TINY.accordion.slider("menu1"); menu1.init("menu1","a",1,-1);
15
17
  menu2 = new TINY.accordion.slider("menu2"); menu2.init("menu2","a",1,-1);
16
18
  menu3 = new TINY.accordion.slider("menu3"); menu3.init("menu3","a",1,-1);
17
19
  menu4 = new TINY.accordion.slider("menu4"); menu4.init("menu4","a",1,-1);
@@ -22,6 +24,8 @@
22
24
  menu9 = new TINY.accordion.slider("menu9"); menu9.init("menu9","a",1,-1);
23
25
  menu10 = new TINY.accordion.slider("menu10"); menu10.init("menu10","a",1,-1);
24
26
  menu11 = new TINY.accordion.slider("menu11"); menu11.init("menu11","a",1,-1);
27
+ menu12 = new TINY.accordion.slider("menu12"); menu11.init("menu12","a",1,-1);
28
+ menu13 = new TINY.accordion.slider("menu13"); menu11.init("menu13","a",1,-1);
25
29
  };
26
30
  window.onload = init_accordion;
27
31
 
@@ -125,6 +129,11 @@
125
129
  License
126
130
  .acc-section
127
131
  .acc-content
132
+ %li
133
+ %a{ :href => "#donate" }
134
+ Donate
135
+ .acc-section
136
+ .acc-content
128
137
  %li
129
138
  %a{ :href => "#installation" }
130
139
  Installation
@@ -168,13 +177,23 @@
168
177
  .acc-section
169
178
  .acc-content
170
179
  %li
171
- %a{ :href => "#optional_fields" }
172
- Optional fields
180
+ %a{ :href => "#dependencies_between_fields" }
181
+ Dependencies between fields
182
+ .acc-section
183
+ .acc-content
184
+ %li
185
+ %a{ :href => "#nested_records" }
186
+ Nested Records
173
187
  .acc-section
174
188
  .acc-content
175
189
  %li
176
- %a{ :href => "#handling_dependencies_between_fields" }
177
- Handling dependencies between fields
190
+ %a{ :href => "#bitfields" }
191
+ Bitfields
192
+ .acc-section
193
+ .acc-content
194
+ %li
195
+ %a{ :href => "#optional_fields" }
196
+ Optional fields
178
197
  .acc-section
179
198
  .acc-content
180
199
  %li
@@ -241,22 +260,49 @@
241
260
  Arrays
242
261
  .acc-section
243
262
  .acc-content
263
+ %ul.level2#menu9
264
+ %li
265
+ %a{ :href => "#array_syntax" }
266
+ Array syntax
267
+ .acc-section
268
+ .acc-content
269
+ %li
270
+ %a{ :href => "#array_parameters" }
271
+ Array parameters
272
+ .acc-section
273
+ .acc-content
244
274
  %li
245
275
  %a{ :href => "#choices" }
246
276
  Choices
247
277
  .acc-section
248
278
  .acc-content
279
+ %ul.level2#menu10
280
+ %li
281
+ %a{ :href => "#choice_syntax" }
282
+ Choice syntax
283
+ .acc-section
284
+ .acc-content
285
+ %li
286
+ %a{ :href => "#choice_parameters" }
287
+ Choice parameters
288
+ .acc-section
289
+ .acc-content
249
290
  %li
250
291
  %a{ :href => "#advanced_topics" }
251
292
  Advanced Topics
252
293
  .acc-section
253
294
  .acc-content
254
- %ul.level2#menu9
295
+ %ul.level2#menu11
255
296
  %li
256
297
  %a{ :href => "#skipping_over_unused_data" }
257
298
  Skipping over unused data
258
299
  .acc-section
259
300
  .acc-content
301
+ %li
302
+ %a{ :href => "#bitaligned_records" }
303
+ Bit-aligned Records
304
+ .acc-section
305
+ .acc-content
260
306
  %li
261
307
  %a{ :href => "#wrappers" }
262
308
  Wrappers
@@ -267,7 +313,7 @@
267
313
  Parameterizing User Defined Types
268
314
  .acc-section
269
315
  .acc-content
270
- %ul.level3#menu10
316
+ %ul.level3#menu12
271
317
  %li
272
318
  %a{ :href => "#mandatory_parameters" }
273
319
  Mandatory Parameters
@@ -283,7 +329,7 @@
283
329
  Debugging
284
330
  .acc-section
285
331
  .acc-content
286
- %ul.level3#menu11
332
+ %ul.level3#menu13
287
333
  %li
288
334
  %a{ :href => "#tracing" }
289
335
  Tracing