bindata 1.4.3 → 1.4.4

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/manual.md CHANGED
@@ -40,17 +40,18 @@ 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: 2011-10-01
43
+ Last updated: 2012-06-21
44
44
 
45
45
  ## License
46
46
 
47
47
  BinData is released under the same license as Ruby.
48
48
 
49
- Copyright © 2007 - 2011 [Dion Mendel](mailto:dion@lostrealm.com)
49
+ Copyright © 2007 - 2012 [Dion Mendel](mailto:dion@lostrealm.com)
50
50
 
51
51
  ## Donate
52
52
 
53
- Want to donate? My favourite local charity is [Perth Raptor Care](http://care.raptor.id.au/help.html#PAL).
53
+ Want to donate? My favourite local charity is
54
+ [Perth Raptor Care](http://care.raptor.id.au/help.html#PAL).
54
55
 
55
56
  ---------------------------------------------------------------------------
56
57
 
@@ -72,8 +73,8 @@ BinData declarations are easy to read. Here's an example.
72
73
 
73
74
  class MyFancyFormat < BinData::Record
74
75
  stringz :comment
75
- uint8 :num, :check_value => lambda { value.even? }
76
- array :some_ints, :type => :int32be, :initial_length => :num_ints
76
+ uint8 :len
77
+ array :data, :type => :int32be, :initial_length => :len
77
78
  end
78
79
  {:ruby}
79
80
 
@@ -82,22 +83,21 @@ This fancy format describes the following collection of data:
82
83
  `:comment`
83
84
  : A zero terminated string
84
85
 
85
- `:num`
86
- : An unsigned 8bit integer which must by even
86
+ `:len`
87
+ : An unsigned 8bit integer
87
88
 
88
- `:some_ints`
89
+ `:data`
89
90
  : A sequence of unsigned 32bit big endian integers. The number of
90
- integers is given by the value of `:num`
91
+ integers is given by the value of `:len`
91
92
 
92
93
  The BinData declaration matches the English description closely.
93
94
  Compare the above declaration with the equivalent `#unpack` code to read
94
95
  such a data record.
95
96
 
96
97
  def read_fancy_format(io)
97
- comment, num_ints, rest = io.read.unpack("Z*Ca*")
98
- raise ArgumentError, "ints must be even" unless num_ints.even?
99
- some_ints = rest.unpack("N#{num_ints}")
100
- {:comment => comment, :num_ints => num_ints, :some_ints => *some_ints}
98
+ comment, len, rest = io.read.unpack("Z*Ca*")
99
+ data = rest.unpack("N#{len}")
100
+ {:comment => comment, :len => len, :data => *data}
101
101
  end
102
102
  {:ruby}
103
103
 
@@ -111,147 +111,6 @@ underlying binary data representation.
111
111
 
112
112
  ---------------------------------------------------------------------------
113
113
 
114
- # Common Operations
115
-
116
- There are operations common to all BinData types, including user defined
117
- ones. These are summarised here.
118
-
119
- ## Reading and writing
120
-
121
- `::read(io)`
122
-
123
- : Creates a BinData object and reads its value from the given string
124
- or `IO`. The newly created object is returned.
125
-
126
- obj = BinData::Int8.read("\xff")
127
- obj.snapshot #=> -1
128
- {:ruby}
129
-
130
- `#read(io)`
131
-
132
- : Reads and assigns binary data read from `io`.
133
-
134
- obj = BinData::Stringz.new
135
- obj.read("string 1\0string 2\0")
136
- obj #=> "string 1"
137
- {:ruby}
138
-
139
- `#write(io)`
140
-
141
- : Writes the binary data representation of the object to `io`.
142
-
143
- File.open("...", "wb") do |io|
144
- obj = BinData::Uint64be.new(568290145640170)
145
- obj.write(io)
146
- end
147
- {:ruby}
148
-
149
- `#to_binary_s`
150
-
151
- : Returns the binary data representation of this object as a string.
152
-
153
- obj = BinData::Uint16be.new(4660)
154
- obj.to_binary_s #=> "\022\064"
155
- {:ruby}
156
-
157
- ## Manipulating
158
-
159
- `#assign(value)`
160
-
161
- : Assigns the given value to this object. `value` can be of the same
162
- format as produced by `#snapshot`, or it can be a compatible data
163
- object.
164
-
165
- arr = BinData::Array.new(:type => :uint8)
166
- arr.assign([1, 2, 3, 4])
167
- arr.snapshot #=> [1, 2, 3, 4]
168
- {:ruby}
169
-
170
- `#clear`
171
-
172
- : Resets this object to its initial state.
173
-
174
- obj = BinData::Int32be.new(:initial_value => 42)
175
- obj.assign(50)
176
- obj.clear
177
- obj #=> 42
178
- {:ruby}
179
-
180
- `#clear?`
181
-
182
- : Returns whether this object is in its initial state.
183
-
184
- arr = BinData::Array.new(:type => :uint16be, :initial_length => 5)
185
- arr[3] = 42
186
- arr.clear? #=> false
187
-
188
- arr[3].clear
189
- arr.clear? #=> true
190
- {:ruby}
191
-
192
- ## Inspecting
193
-
194
- `#num_bytes`
195
-
196
- : Returns the number of bytes required for the binary data
197
- representation of this object.
198
-
199
- arr = BinData::Array.new(:type => :uint16be, :initial_length => 5)
200
- arr[0].num_bytes #=> 2
201
- arr.num_bytes #=> 10
202
- {:ruby}
203
-
204
- `#snapshot`
205
-
206
- : Returns the value of this object as primitive Ruby objects
207
- (numerics, strings, arrays and hashs). The output of `#snapshot`
208
- may be useful for serialization or as a reduced memory usage
209
- representation.
210
-
211
- obj = BinData::Uint8.new(2)
212
- obj.class #=> BinData::Uint8
213
- obj + 3 #=> 5
214
-
215
- obj.snapshot #=> 2
216
- obj.snapshot.class #=> Fixnum
217
- {:ruby}
218
-
219
- `#offset`
220
-
221
- : Returns the offset of this object with respect to the most distant
222
- ancestor structure it is contained within. This is most likely to
223
- be used with arrays and records.
224
-
225
- class Tuple < BinData::Record
226
- int8 :a
227
- int8 :b
228
- end
229
-
230
- arr = BinData::Array.new(:type => :tuple, :initial_length => 3)
231
- arr[2].b.offset #=> 5
232
- {:ruby}
233
-
234
- `#rel_offset`
235
-
236
- : Returns the offset of this object with respect to the parent
237
- structure it is contained within. Compare this to `#offset`.
238
-
239
- class Tuple < BinData::Record
240
- int8 :a
241
- int8 :b
242
- end
243
-
244
- arr = BinData::Array.new(:type => :tuple, :initial_length => 3)
245
- arr[2].b.rel_offset #=> 1
246
- {:ruby}
247
-
248
- `#inspect`
249
-
250
- : Returns a human readable representation of this object. This is a
251
- shortcut to #snapshot.inspect.
252
-
253
- ---------------------------------------------------------------------------
254
-
255
114
  # Records
256
115
 
257
116
  The general format of a BinData record declaration is a class containing
@@ -288,8 +147,8 @@ Here are some examples of legal values for parameters.
288
147
  The simplest case is when the value is a literal value, such as `5`.
289
148
 
290
149
  If the value is not a literal, it is expected to be a lambda. The
291
- lambda will be evaluated in the context of the parent, in this case the
292
- parent is an instance of `MyName`.
150
+ lambda will be evaluated in the context of the parent. In this case
151
+ the parent is an instance of `MyName`.
293
152
 
294
153
  If the value is a symbol, it is taken as syntactic sugar for a lambda
295
154
  containing the value of the symbol.
@@ -407,28 +266,8 @@ first and the length afterwards.
407
266
 
408
267
  ## Nested Records
409
268
 
410
- Records can be used as a mean of grouping together related data. Rather
411
- than declaring a single flat record, a nested structure can be used to
412
- document this grouping.
413
-
414
- class Coord < BinData::Record
415
- endian :little
416
- double :x
417
- double :z
418
- double :y
419
- end
420
-
421
- class LabeledCoord < BinData::Record
422
- string :label, :length => 20
423
- coord :coord
424
- end
425
-
426
- pos = LabeledCoord.new(:label => "red leader")
427
- pos.coord.assign(:x => 2.0, :y => 0, :z => -1.57)
428
- {:ruby}
429
-
430
- BinData supports anonymous nested records. The previous example could
431
- also be declared using the `struct` keyword as follows:
269
+ BinData supports anonymous nested records. The `struct` keyword declares
270
+ a nested structure that can be used to imply a grouping of related data.
432
271
 
433
272
  class LabeledCoord < BinData::Record
434
273
  string :label, :length => 20
@@ -440,38 +279,24 @@ also be declared using the `struct` keyword as follows:
440
279
  double :y
441
280
  end
442
281
  end
443
- {:ruby}
444
-
445
- ## Bitfields
446
282
 
447
- Most types in a record are byte oriented. Bitfields allow us to access
448
- individual bits in an octet stream.
449
-
450
- Sometimes a bitfield has unused elements such as
451
-
452
- class RecordWithBitfield < BinData::Record
453
- bit1 :foo
454
- bit1 :bar
455
- bit1 :baz
456
- bit5 :unused
457
-
458
- stringz :qux
459
- end
283
+ pos = LabeledCoord.new(:label => "red leader")
284
+ pos.coord.assign(:x => 2.0, :y => 0, :z => -1.57)
460
285
  {:ruby}
461
286
 
462
- The problem with specifying an unused field is that the size of this
463
- field must be manually counted. This is a potential source of errors.
464
-
465
- BinData provides a shortcut to skip to the next byte boundary with the
466
- `resume_byte_alignment` keyword.
287
+ This nested structure can be put in its own class and reused.
288
+ The above example can also be declared as:
467
289
 
468
- class RecordWithBitfield < BinData::Record
469
- bit1 :foo
470
- bit1 :bar
471
- bit1 :baz
472
- resume_byte_alignment
290
+ class Coord < BinData::Record
291
+ endian :little
292
+ double :x
293
+ double :z
294
+ double :y
295
+ end
473
296
 
474
- stringz :qux
297
+ class LabeledCoord < BinData::Record
298
+ string :label, :length => 20
299
+ coord :coord
475
300
  end
476
301
  {:ruby}
477
302
 
@@ -525,7 +350,7 @@ Examples of individual usage:
525
350
  fl * int16 #=> 2557.90320057996
526
351
  {:ruby}
527
352
 
528
- There are several parameters that are specific to primitives.
353
+ There are several parameters that are specific to all primitives.
529
354
 
530
355
  `:initial_value`
531
356
 
@@ -548,12 +373,23 @@ There are several parameters that are specific to primitives.
548
373
  pi = BinData::FloatLe.new(:value => Math::PI)
549
374
  pi.assign(3)
550
375
  puts pi #=> 3.14159265358979
376
+
377
+
378
+ class IntList < BinData::Record
379
+ uint8 :len, :value => lambda { data.length }
380
+ array :data, :type => :uint32be
381
+ end
382
+
383
+ list = IntList.new([1, 2, 3])
384
+ list.len #=> 3
551
385
  {:ruby}
552
386
 
553
387
  `:check_value`
554
388
 
555
389
  : When reading, will raise a `ValidityError` if the value read does
556
- not match the value of this parameter.
390
+ not match the value of this parameter. This is useful when
391
+ [debugging](#debugging), rather than as a general error detection
392
+ system.
557
393
 
558
394
  obj = BinData::String.new(:check_value => lambda { /aaa/ =~ value })
559
395
  obj.read("baaa!") #=> "baaa!"
@@ -708,16 +544,16 @@ details.
708
544
 
709
545
  ### Fixed Sized Strings
710
546
 
711
- Fixed sized strings may have a set length. If an assigned value is
712
- shorter than this length, it will be padded to this length. If no
713
- length is set, the length is taken to be the length of the assigned
547
+ Fixed sized strings may have a set length (in bytes). If an assigned
548
+ value is shorter than this length, it will be padded to this length. If
549
+ no length is set, the length is taken to be the length of the assigned
714
550
  value.
715
551
 
716
552
  There are several parameters that are specific to fixed sized strings.
717
553
 
718
554
  `:read_length`
719
555
 
720
- : The length to use when reading a value.
556
+ : The length in bytes to use when reading a value.
721
557
 
722
558
  obj = BinData::String.new(:read_length => 5)
723
559
  obj.read("abcdefghij")
@@ -742,13 +578,13 @@ There are several parameters that are specific to fixed sized strings.
742
578
  obj #=> "abcdef"
743
579
  {:ruby}
744
580
 
745
- `:pad_char`
581
+ `:pad_byte`
746
582
 
747
- : The character to use when padding a string to a set length. Valid
748
- values are `Integers` and `Strings` of length 1.
749
- `"\0"` is the default.
583
+ : Defaults to `"\0"`. The character to use when padding a string to a
584
+ set length. Valid values are `Integers` and `Strings` of one byte.
585
+ Multi byte padding is not supported.
750
586
 
751
- obj = BinData::String.new(:length => 6, :pad_char => 'A')
587
+ obj = BinData::String.new(:length => 6, :pad_byte => 'A')
752
588
  obj.assign("abcd")
753
589
  obj.snapshot #=> "abcdAA"
754
590
  obj.to_binary_s #=> "abcdAA"
@@ -757,7 +593,7 @@ There are several parameters that are specific to fixed sized strings.
757
593
  `:trim_padding`
758
594
 
759
595
  : Boolean, default `false`. If set, the value of this string will
760
- have all pad_chars trimmed from the end of the string. The value
596
+ have all pad_bytes trimmed from the end of the string. The value
761
597
  will not be trimmed when writing.
762
598
 
763
599
  obj = BinData::String.new(:length => 6, :trim_value => true)
@@ -769,7 +605,7 @@ There are several parameters that are specific to fixed sized strings.
769
605
  ### Zero Terminated Strings
770
606
 
771
607
  These strings are modelled on the C style of string - a sequence of
772
- bytes terminated by a null (`"\0"`) character.
608
+ bytes terminated by a null (`"\0"`) byte.
773
609
 
774
610
  obj = BinData::Stringz.new
775
611
  obj.read("abcd\000efgh")
@@ -780,8 +616,8 @@ bytes terminated by a null (`"\0"`) character.
780
616
 
781
617
  ## User Defined Primitive Types
782
618
 
783
- Most user defined types will be Records, but occasionally we'd like to
784
- create a custom type of primitive.
619
+ Most user defined types will be Records but occasionally we'd like to
620
+ create a custom primitive type.
785
621
 
786
622
  Let us revisit the Pascal String example.
787
623
 
@@ -818,6 +654,58 @@ We create this type of custom string by inheriting from
818
654
  end
819
655
  {:ruby}
820
656
 
657
+ A user defined primitive type has both an internal (binary structure)
658
+ and an external (ruby interface) representation. The internal
659
+ representation is encapsulated and inaccessible from the external ruby
660
+ interface.
661
+
662
+ Consider a LispBool type that uses `:t` for true and `nil` for false.
663
+ The binary representation is a signed byte with value `1` for true and
664
+ `-1` for false.
665
+
666
+ class LispBool < BinData::Primitive
667
+ int8 :val
668
+
669
+ def get
670
+ case self.val
671
+ when 1
672
+ :t
673
+ when -1
674
+ nil
675
+ else
676
+ nil # unknown value, default to false
677
+ end
678
+ end
679
+
680
+ def set(v)
681
+ case v
682
+ when :t
683
+ self.val = 1
684
+ when nil
685
+ self.val = -1
686
+ else
687
+ self.val = -1 # unknown value, default to false
688
+ end
689
+ end
690
+ end
691
+
692
+ b = LispBool.new
693
+
694
+ b.assign(:t)
695
+ b.to_binary_s #=> "\001"
696
+
697
+ b.read("\xff")
698
+ b.snapshot #=> nil
699
+ {:ruby}
700
+
701
+ `#read` and `#write` use the internal representation. `#assign` and
702
+ `#snapshot` use the external representation. Mixing them up will lead
703
+ to undefined behaviour.
704
+
705
+ b = LispBool.new
706
+ b.assign(1) #=> undefined. Don't do this.
707
+ {:ruby}
708
+
821
709
  ### Advanced User Defined Primitive Types
822
710
 
823
711
  Sometimes a user defined primitive type can not easily be declaratively
@@ -896,27 +784,32 @@ Here is an example of a big integer implementation.
896
784
 
897
785
  ---------------------------------------------------------------------------
898
786
 
899
- # Arrays
787
+ # Compound Types
788
+
789
+ Compound types contain more that a single value. These types are
790
+ Records, Arrays and Choices.
791
+
792
+ ## Arrays
900
793
 
901
794
  A BinData array is a list of data objects of the same type. It behaves
902
795
  much the same as the standard Ruby array, supporting most of the common
903
796
  methods.
904
797
 
905
- ## Array syntax
798
+ ### Array syntax
906
799
 
907
800
  When instantiating an array, the type of object it contains must be
908
801
  specified. The two different ways of declaring this are the `:type`
909
802
  parameter and the block form.
910
803
 
911
804
  class A < BinData::Record
912
- array :numbers, :type => :uint8, :initial_length => 3
805
+ array :numbers, :type => :uint8, :initial_length => 3
913
806
  end
914
807
  -vs-
915
808
 
916
809
  class A < BinData::Record
917
- array :numbers, :initial_length => 3 do
918
- uint8
919
- end
810
+ array :numbers, :initial_length => 3 do
811
+ uint8
812
+ end
920
813
  end
921
814
  {:ruby}
922
815
 
@@ -930,15 +823,29 @@ array type has parameters, the block form becomes easier to read.
930
823
  -vs-
931
824
 
932
825
  class A < BinData::Record
933
- array :numbers, :initial_length => 3 do
934
- uint8 :initial_value => :index
935
- end
826
+ array :numbers, :initial_length => 3 do
827
+ uint8 :initial_value => :index
828
+ end
829
+ end
830
+ {:ruby}
831
+
832
+ An array can also be declared as a custom type by moving the contents of
833
+ the block into a custom class. The above example could alternatively be
834
+ declared as:
835
+
836
+ class NumberArray < BinData::Array
837
+ uint8 :initial_value => :index
838
+ end
839
+
840
+ class A < BinData::Record
841
+ number_array :numbers, :initial_length => 3
936
842
  end
937
843
  {:ruby}
938
844
 
845
+
939
846
  If the block form has multiple types declared, they are interpreted as
940
- the contents of an anonymous `struct`. To illustrate this, consider the
941
- following representation of a polygon.
847
+ the contents of an [anonymous `struct`](#nested_records). To illustrate
848
+ this, consider the following representation of a polygon.
942
849
 
943
850
  class Polygon < BinData::Record
944
851
  endian :little
@@ -956,7 +863,7 @@ following representation of a polygon.
956
863
  triangle.points << {:x => 5, :y => 6}
957
864
  {:ruby}
958
865
 
959
- ## Array parameters
866
+ ### Array parameters
960
867
 
961
868
  There are two different parameters that specify the length of the array.
962
869
 
@@ -999,9 +906,7 @@ There are two different parameters that specify the length of the array.
999
906
  obj.snapshot #=> [2, 3, 4, 5, 6, 7]
1000
907
  {:ruby}
1001
908
 
1002
- ---------------------------------------------------------------------------
1003
-
1004
- # Choices
909
+ ## Choices
1005
910
 
1006
911
  A Choice is a collection of data objects of which only one is active at
1007
912
  any particular time. Method calls will be delegated to the active
@@ -1009,7 +914,7 @@ choice. The possible types of objects that a choice contains is
1009
914
  controlled by the `:choices` parameter, while the `:selection` parameter
1010
915
  specifies the active choice.
1011
916
 
1012
- ## Choice syntax
917
+ ### Choice syntax
1013
918
 
1014
919
  Choices have two ways of specifying the possible data objects they can
1015
920
  contain. The `:choices` parameter or the block form. The block form is
@@ -1031,6 +936,20 @@ usually clearer and is prefered.
1031
936
  end
1032
937
  {:ruby}
1033
938
 
939
+ Like all compound types, a choice can be declared as its own type. The
940
+ above example can be declared as:
941
+
942
+ class BigLittleInt16 < BinData::Choice
943
+ int16be 0
944
+ int16le 1
945
+ end
946
+
947
+ class MyInt16 < BinData::Record
948
+ uint8 :e, :check_value => lambda { value == 0 or value == 1 }
949
+ bit_little_int_16 :int, :selection => :e
950
+ end
951
+ {:ruby}
952
+
1034
953
  The general form of the choice is
1035
954
 
1036
955
  class MyRecord < BinData::Record
@@ -1050,7 +969,7 @@ The general form of the choice is
1050
969
  choice is currently active. The key can be any ruby type (`String`,
1051
970
  `Numeric` etc) except `Symbol`.
1052
971
 
1053
- ## Choice parameters
972
+ ### Choice parameters
1054
973
 
1055
974
  `:choices`
1056
975
 
@@ -1103,7 +1022,7 @@ Examples
1103
1022
  obj.to_binary_s #=> "\000\005\000\000\000"
1104
1023
  {:ruby}
1105
1024
 
1106
- ## Default selection
1025
+ ### Default selection
1107
1026
 
1108
1027
  A key of `:default` can be specified as a default selection. If the value of the
1109
1028
  selection isn't specified then the :default will be used. The previous `MyNumber`
@@ -1122,6 +1041,147 @@ is big endian. This can be concisely written as:
1122
1041
 
1123
1042
  ---------------------------------------------------------------------------
1124
1043
 
1044
+ # Common Operations
1045
+
1046
+ There are operations common to all BinData types, including user defined
1047
+ ones. These are summarised here.
1048
+
1049
+ ## Reading and writing
1050
+
1051
+ `::read(io)`
1052
+
1053
+ : Creates a BinData object and reads its value from the given string
1054
+ or `IO`. The newly created object is returned.
1055
+
1056
+ obj = BinData::Int8.read("\xff")
1057
+ obj.snapshot #=> -1
1058
+ {:ruby}
1059
+
1060
+ `#read(io)`
1061
+
1062
+ : Reads and assigns binary data read from `io`.
1063
+
1064
+ obj = BinData::Stringz.new
1065
+ obj.read("string 1\0string 2\0")
1066
+ obj #=> "string 1"
1067
+ {:ruby}
1068
+
1069
+ `#write(io)`
1070
+
1071
+ : Writes the binary data representation of the object to `io`.
1072
+
1073
+ File.open("...", "wb") do |io|
1074
+ obj = BinData::Uint64be.new(568290145640170)
1075
+ obj.write(io)
1076
+ end
1077
+ {:ruby}
1078
+
1079
+ `#to_binary_s`
1080
+
1081
+ : Returns the binary data representation of this object as a string.
1082
+
1083
+ obj = BinData::Uint16be.new(4660)
1084
+ obj.to_binary_s #=> "\022\064"
1085
+ {:ruby}
1086
+
1087
+ ## Manipulating
1088
+
1089
+ `#assign(value)`
1090
+
1091
+ : Assigns the given value to this object. `value` can be of the same
1092
+ format as produced by `#snapshot`, or it can be a compatible data
1093
+ object.
1094
+
1095
+ arr = BinData::Array.new(:type => :uint8)
1096
+ arr.assign([1, 2, 3, 4])
1097
+ arr.snapshot #=> [1, 2, 3, 4]
1098
+ {:ruby}
1099
+
1100
+ `#clear`
1101
+
1102
+ : Resets this object to its initial state.
1103
+
1104
+ obj = BinData::Int32be.new(:initial_value => 42)
1105
+ obj.assign(50)
1106
+ obj.clear
1107
+ obj #=> 42
1108
+ {:ruby}
1109
+
1110
+ `#clear?`
1111
+
1112
+ : Returns whether this object is in its initial state.
1113
+
1114
+ arr = BinData::Array.new(:type => :uint16be, :initial_length => 5)
1115
+ arr[3] = 42
1116
+ arr.clear? #=> false
1117
+
1118
+ arr[3].clear
1119
+ arr.clear? #=> true
1120
+ {:ruby}
1121
+
1122
+ ## Inspecting
1123
+
1124
+ `#num_bytes`
1125
+
1126
+ : Returns the number of bytes required for the binary data
1127
+ representation of this object.
1128
+
1129
+ arr = BinData::Array.new(:type => :uint16be, :initial_length => 5)
1130
+ arr[0].num_bytes #=> 2
1131
+ arr.num_bytes #=> 10
1132
+ {:ruby}
1133
+
1134
+ `#snapshot`
1135
+
1136
+ : Returns the value of this object as primitive Ruby objects
1137
+ (numerics, strings, arrays and hashs). The output of `#snapshot`
1138
+ may be useful for serialization or as a reduced memory usage
1139
+ representation.
1140
+
1141
+ obj = BinData::Uint8.new(2)
1142
+ obj.class #=> BinData::Uint8
1143
+ obj + 3 #=> 5
1144
+
1145
+ obj.snapshot #=> 2
1146
+ obj.snapshot.class #=> Fixnum
1147
+ {:ruby}
1148
+
1149
+ `#offset`
1150
+
1151
+ : Returns the offset of this object with respect to the most distant
1152
+ ancestor structure it is contained within. This is most likely to
1153
+ be used with arrays and records.
1154
+
1155
+ class Tuple < BinData::Record
1156
+ int8 :a
1157
+ int8 :b
1158
+ end
1159
+
1160
+ arr = BinData::Array.new(:type => :tuple, :initial_length => 3)
1161
+ arr[2].b.offset #=> 5
1162
+ {:ruby}
1163
+
1164
+ `#rel_offset`
1165
+
1166
+ : Returns the offset of this object with respect to the parent
1167
+ structure it is contained within. Compare this to `#offset`.
1168
+
1169
+ class Tuple < BinData::Record
1170
+ int8 :a
1171
+ int8 :b
1172
+ end
1173
+
1174
+ arr = BinData::Array.new(:type => :tuple, :initial_length => 3)
1175
+ arr[2].b.rel_offset #=> 1
1176
+ {:ruby}
1177
+
1178
+ `#inspect`
1179
+
1180
+ : Returns a human readable representation of this object. This is a
1181
+ shortcut to #snapshot.inspect.
1182
+
1183
+ ---------------------------------------------------------------------------
1184
+
1125
1185
  # Advanced Topics
1126
1186
 
1127
1187
  ## Debugging
@@ -1207,19 +1267,19 @@ Mandatory parameters must be specified when creating an instance of the
1207
1267
  type.
1208
1268
 
1209
1269
  class Polygon < BinData::Record
1210
- mandatory_parameter :num_edges
1270
+ mandatory_parameter :num_vertices
1211
1271
 
1212
1272
  uint8 :num, :value => lambda { vertices.length }
1213
- array :vertices, :initial_length => :num_edges do
1273
+ array :vertices, :initial_length => :num_vertices do
1214
1274
  int8 :x
1215
1275
  int8 :y
1216
1276
  end
1217
1277
  end
1218
1278
 
1219
1279
  triangle = Polygon.new
1220
- #=> raises ArgumentError: parameter 'num_edges' must be specified in Polygon
1280
+ #=> raises ArgumentError: parameter 'num_vertices' must be specified in Polygon
1221
1281
 
1222
- triangle = Polygon.new(:num_edges => 3)
1282
+ triangle = Polygon.new(:num_vertices => 3)
1223
1283
  triangle.snapshot #=> {"num" => 3, "vertices" =>
1224
1284
  [{"x"=>0, "y"=>0}, {"x"=>0, "y"=>0}, {"x"=>0, "y"=>0}]}
1225
1285
  {:ruby}
@@ -1337,14 +1397,44 @@ do not stream well as they must be buffered by the client before being
1337
1397
  processed. Consider using an explicit length when creating a new file format
1338
1398
  as it is easier to work with.
1339
1399
 
1340
- ## Bit-aligned Records
1400
+ ## Advanced Bitfields
1401
+
1402
+ Most types in a record are byte oriented. [Bitfields](#bit_based_integers)
1403
+ allow access to individual bits in an octet stream.
1404
+
1405
+ Sometimes a bitfield has unused elements such as
1406
+
1407
+ class RecordWithBitfield < BinData::Record
1408
+ bit1 :foo
1409
+ bit1 :bar
1410
+ bit1 :baz
1411
+ bit5 :unused
1412
+
1413
+ stringz :qux
1414
+ end
1415
+ {:ruby}
1416
+
1417
+ The problem with specifying an unused field is that the size of this
1418
+ field must be manually counted. This is a potential source of errors.
1341
1419
 
1342
- Most structured binary data is byte-aligned. Any bitfields that occur,
1343
- usually start and end on a byte boundary. But occasionally you will
1344
- come across a format where primitive types (string and numerics) are not
1345
- aligned on byte boundaries.
1420
+ BinData provides a shortcut to skip to the next byte boundary with the
1421
+ `resume_byte_alignment` keyword.
1346
1422
 
1347
- class CrazyAlignment < BinData::Record
1423
+ class RecordWithBitfield < BinData::Record
1424
+ bit1 :foo
1425
+ bit1 :bar
1426
+ bit1 :baz
1427
+ resume_byte_alignment
1428
+
1429
+ stringz :qux
1430
+ end
1431
+ {:ruby}
1432
+
1433
+ Occasionally you will come across a format where primitive types (string
1434
+ and numerics) are not aligned on byte boundaries but are to be packed in
1435
+ the bit stream.
1436
+
1437
+ class PackedRecord < BinData::Record
1348
1438
  bit4 :a
1349
1439
  string :b, :length => 2 # note: byte-aligned
1350
1440
  bit1 :c
@@ -1352,8 +1442,8 @@ aligned on byte boundaries.
1352
1442
  bit3 :e
1353
1443
  end
1354
1444
 
1355
- c = CrazyAlignment.read("\xff" * 10)
1356
- c.to_binary_s #=> "\360\377\377\200\377\377\340"
1445
+ obj = PackedRecord.read("\xff" * 10)
1446
+ obj.to_binary_s #=> "\360\377\377\200\377\377\340"
1357
1447
  {:ruby}
1358
1448
 
1359
1449
  The above declaration does not work as expected because BinData's
@@ -1368,7 +1458,7 @@ versions of `string` and `int16le`.
1368
1458
  bit_aligned
1369
1459
  end
1370
1460
 
1371
- class CrazyAlignment < BinData::Record
1461
+ class PackedRecord < BinData::Record
1372
1462
  bit4 :a
1373
1463
  bit_string :b, :length => 2
1374
1464
  bit1 :c
@@ -1376,8 +1466,8 @@ versions of `string` and `int16le`.
1376
1466
  bit3 :e
1377
1467
  end
1378
1468
 
1379
- c = CrazyAlignment.read("\xff" * 10)
1380
- c.to_binary_s #=> "\377\377\377\377\377"
1469
+ obj = PackedRecord.read("\xff" * 10)
1470
+ obj.to_binary_s #=> "\377\377\377\377\377"
1381
1471
  {:ruby}
1382
1472
 
1383
1473
  ---------------------------------------------------------------------------
@@ -1465,6 +1555,9 @@ lists](http://bindata.rubyforge.org/svn/trunk/examples/list.rb).
1465
1555
 
1466
1556
  # Alternatives
1467
1557
 
1558
+ This section is purely historic. All the alternatives to BinData are
1559
+ no longer actively maintained.
1560
+
1468
1561
  There are several alternatives to BinData. Below is a comparison
1469
1562
  between BinData and its alternatives.
1470
1563