bin_struct 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d5412a49a789a410de1120e6cbcbf55a7bd07783846a4e2f4cf9bc14eac76bfd
4
- data.tar.gz: 9ae9eabeb7c3fe672e8ba229bc116c9a72bf26c7b1fd9eace52bb0f8036f0fea
3
+ metadata.gz: 5a90f75409d497521af8957e89577a4e8b7c14211e5343aa9126a71ef413d759
4
+ data.tar.gz: b07e2bf73d2cb1f4b7be4340944cd52df4382fc94f171607357adf10ddc7a914
5
5
  SHA512:
6
- metadata.gz: 8fa11b03a84dca208c63d23358187b575982f5331d5c1da7fdd7c2343505ed932bc884a440b23589943d4eb5d9f78f942d77e8b271bef919277536a0ab9ab3b7
7
- data.tar.gz: ecd4e847f6dc8392b759b8ef7a23df05191c697bb471a1ef8c685e12009be544b2dac4f8d77a944190a607b26216d90bd034742c95f9b2034b2701c4ec726602
6
+ metadata.gz: 6acd7aeb0516bf6692ae5971aecb10c8ae685936f24302d909ff16f055118a68588876409819d0ba966e4f3a7b524b194e58713bfb0ccaef95eb542fca221bb3
7
+ data.tar.gz: 790bf0b81cef084c030e0412731e3b0b852815fa1f66f5d28564278579e12b7e3fd3ef3674c6f36dd32bc792e1c248f7f20b3f65f505d3193f370b2d8c6f1d88
data/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
- ## [Unreleased]
1
+ # Changelog
2
2
 
3
- ## [0.1.0] - 2024-07-13
3
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
4
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
+
6
+ ## 0.2.0 - 2024-07-21
7
+
8
+ ### Changed
9
+
10
+ - `BinStruct::Fields` renamed into `BinStruct::Struct`, and `*field*` methods are renamed into `*attr*` or `*attributes*`.
11
+ - `BinStruct::Struct#inspect`: add a title line.
12
+
13
+ ### Fixed
14
+
15
+ - Fix `BinStruct::ArrayOfInt#read_from_array` by using `value:` option.
16
+ - Fix `BinStruct::IntString#calc_length` by using `#from_human` instead of `#read`.
17
+ - `BinStruct::String#to_s`: force binary encoding.
18
+ - `BinStruct::String#<<`: force binary encoding on argument before catenating.
19
+
20
+ ## 0.1.0 - 2024-07-13
4
21
 
5
22
  - Initial release
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # BinStruct
2
2
 
3
- BinStruct provides a simple ways to create and dissect binary data. It is an extraction from [PacketGen](https://github.com/lemontree55/packetgen) fields.
3
+ BinStruct provides a simple way to create and dissect binary data. It is an extraction from [PacketGen](https://github.com/lemontree55/packetgen) 3.x Fields.
4
4
 
5
5
  ## Installation
6
6
 
@@ -2,28 +2,28 @@
2
2
 
3
3
  # This file is part of BinStruct
4
4
  # See https://github.com/lemontree55/bin_struct for more informations
5
+ # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
5
6
  # Copyright (C) 2024 LemonTree55 <lenontree@proton.me>
6
7
  # This program is published under MIT license.
7
8
 
9
+ # BinStruct module
10
+ # @author LemonTree55
8
11
  module BinStruct
9
- # This class is an abstract class to define type-length-value data.
10
- #
11
- # This class supersedes {TLV} class, which is not well defined on some corner
12
- # cases.
12
+ # @abstract Base class to define type-length-value data.
13
13
  #
14
14
  # ===Usage
15
15
  # To simply define a new TLV class, do:
16
16
  # MyTLV = PacketGen::Types::AbstractTLV.create
17
17
  # MyTLV.define_type_enum 'one' => 1, 'two' => 2
18
- # This will define a new +MyTLV+ class, subclass of {Fields}. This class will
19
- # define 3 fields:
18
+ # This will define a new +MyTLV+ class, subclass of {AbstractTLV}. This class will
19
+ # define 3 attributes:
20
20
  # * +#type+, as a {Int8Enum} by default,
21
21
  # * +#length+, as a {Int8} by default,
22
22
  # * and +#value+, as a {String} by default.
23
23
  # +.define_type_enum+ is, here, necessary to define enum hash to be used
24
24
  # for +#type+ accessor, as this one is defined as an {Enum}.
25
25
  #
26
- # This class may then be used as older {TLV} class:
26
+ # This new defined class may now be easily used:
27
27
  # tlv = MyTLV.new(type: 1, value: 'abcd') # automagically set #length from value
28
28
  # tlv.type #=> 1
29
29
  # tlv.human_type #=> 'one'
@@ -31,7 +31,7 @@ module BinStruct
31
31
  # tlv.value #=> "abcd"
32
32
  #
33
33
  # ===Advanced usage
34
- # Each field's type may be changed at generating TLV class:
34
+ # Each attribute's type may be changed at generating TLV class:
35
35
  # MyTLV = PacketGen::Types::AbstractTLV.create(type_class: PacketGen::Types::Int16,
36
36
  # length_class: PacketGen::Types::Int16,
37
37
  # value_class: PacketGen::Header::IP::Addr)
@@ -42,7 +42,7 @@ module BinStruct
42
42
  # tlv.to_s #=> "\x00\x01\x00\x04\x01\x02\x03\x04"
43
43
  #
44
44
  # Some aliases may also be defined. For example, to create a TLV type
45
- # whose +type+ field should be named +code+:
45
+ # whose +type+ attribute should be named +code+:
46
46
  # MyTLV = PacketGen::Types::AbstractTLV.create(type_class: PacketGen::Types::Int16,
47
47
  # length_class: PacketGen::Types::Int16,
48
48
  # aliases: { code: :type })
@@ -52,20 +52,20 @@ module BinStruct
52
52
  # tlv.length #=> 4
53
53
  # tlv.value #=> 'abcd'
54
54
  #
55
- # @author Sylvain Daubert
56
- # @since 3.1.0
57
- # @since 3.1.1 add +:aliases+ keyword to {#initialize}
58
- class AbstractTLV < Fields
59
- include Fieldable
55
+ # @author Sylvain Daubert (2016-2024)
56
+ # @author LemonTree55
57
+ class AbstractTLV < Struct
58
+ include Structable
60
59
 
61
60
  # @private
62
- FIELD_TYPES = { 'T' => :type, 'L' => :length, 'V' => :value }.freeze
61
+ ATTR_TYPES = { 'T' => :type, 'L' => :length, 'V' => :value }.freeze
63
62
 
64
63
  class << self
64
+ # Aliases defined in {.create}
65
65
  # @return [Hash]
66
66
  attr_accessor :aliases
67
67
  # @private
68
- attr_accessor :field_in_length
68
+ attr_accessor :attr_in_length
69
69
 
70
70
  # rubocop:disable Metrics/ParameterLists
71
71
 
@@ -73,14 +73,12 @@ module BinStruct
73
73
  # @param [Class] type_class Class to use for +type+
74
74
  # @param [Class] length_class Class to use for +length+
75
75
  # @param [Class] value_class Class to use for +value+
76
- # @param [String] field_order give field order. Each character in [T,L,V] MUST be present once,
76
+ # @param [::String] attr_order gives attribute order. Each character in [T,L,V] MUST be present once,
77
77
  # in the desired order.
78
- # @param [String] field_in_length give fields to compute length on.
78
+ # @param [::String] attr_in_length give attributes to compute length on.
79
79
  # @return [Class]
80
- # @since 3.1.4 Add +header_in_length+ parameter
81
- # @since 3.3.1 Add +field_order+ and +field_in_length' parameters. Deprecate +header_in_length+ parameter.
82
80
  def create(type_class: Int8Enum, length_class: Int8, value_class: String,
83
- aliases: {}, field_order: 'TLV', field_in_length: 'V')
81
+ aliases: {}, attr_order: 'TLV', attr_in_length: 'V')
84
82
  unless equal?(AbstractTLV)
85
83
  raise Error,
86
84
  '.create cannot be called on a subclass of PacketGen::Types::AbstractTLV'
@@ -88,11 +86,11 @@ module BinStruct
88
86
 
89
87
  klass = Class.new(self)
90
88
  klass.aliases = aliases
91
- klass.field_in_length = field_in_length
89
+ klass.attr_in_length = attr_in_length
92
90
 
93
- check_field_in_length(field_in_length)
94
- check_field_order(field_order)
95
- generate_fields(klass, field_order, type_class, length_class, value_class)
91
+ check_attr_in_length(attr_in_length)
92
+ check_attr_order(attr_order)
93
+ generate_attributes(klass, attr_order, type_class, length_class, value_class)
96
94
 
97
95
  aliases.each do |al, orig|
98
96
  klass.instance_eval do
@@ -106,87 +104,93 @@ module BinStruct
106
104
  # rubocop:enable Metrics/ParameterLists
107
105
 
108
106
  # @!attribute type
109
- # @abstract Type attribute for real TLV class
107
+ # @abstract
108
+ # Type attribute for real TLV class
110
109
  # @return [Integer]
111
110
  # @!attribute length
112
- # @abstract Length attribute for real TLV class
111
+ # @abstract
112
+ # Length attribute for real TLV class
113
113
  # @return [Integer]
114
114
  # @!attribute value
115
- # @abstract Value attribute for real TLV class
115
+ # @abstract
116
+ # Value attribute for real TLV class
116
117
  # @return [Object]
117
118
 
118
119
  # @abstract Should only be called on real TLV classes, created by {.create}.
119
- # Set enum hash for {#type} field.
120
- # @param [Hash{String, Symbol => Integer}] hsh enum hash
120
+ # Set enum hash for {#type} attribute.
121
+ # @param [Hash{::String, Symbol => Integer}] hsh enum hash
121
122
  # @return [void]
122
123
  def define_type_enum(hsh)
123
- field_defs[:type][:options][:enum].clear
124
- field_defs[:type][:options][:enum].merge!(hsh)
124
+ attr_defs[:type][:options][:enum].clear
125
+ attr_defs[:type][:options][:enum].merge!(hsh)
125
126
  end
126
127
 
127
128
  # @abstract Should only be called on real TLV classes, created by {.create}.
128
- # Set default value for {#type} field.
129
- # @param [Integer,String,Symbol,nil] default default value from +hsh+ for type
129
+ # Set default value for {#type} attribute.
130
+ # @param [Integer,::String,Symbol,nil] default default value from +hsh+ for type
130
131
  # @return [void]
131
- # @since 3.4.0
132
132
  def define_type_default(default)
133
- field_defs[:type][:default] = default
133
+ attr_defs[:type][:default] = default
134
134
  end
135
135
 
136
136
  private
137
137
 
138
- def check_field_in_length(field_in_length)
139
- return if /^[TLV]{1,3}$/.match?(field_in_length)
138
+ def check_attr_in_length(attr_in_length)
139
+ return if /^[TLV]{1,3}$/.match?(attr_in_length)
140
140
 
141
- raise 'field_in_length must only contain T, L and/or V characters'
141
+ raise 'attr_in_length must only contain T, L and/or V characters'
142
142
  end
143
143
 
144
- def check_field_order(field_order)
145
- if field_order.match(/^[TLV]{3,3}$/) &&
146
- (field_order[0] != field_order[1]) &&
147
- (field_order[0] != field_order[2]) &&
148
- (field_order[1] != field_order[2])
144
+ def check_attr_order(attr_order)
145
+ if attr_order.match(/^[TLV]{3,3}$/) &&
146
+ (attr_order[0] != attr_order[1]) &&
147
+ (attr_order[0] != attr_order[2]) &&
148
+ (attr_order[1] != attr_order[2])
149
149
  return
150
150
  end
151
151
 
152
- raise 'field_order must contain all three letters TLV, each once'
152
+ raise 'attr_order must contain all three letters TLV, each once'
153
153
  end
154
154
 
155
- def generate_fields(klass, field_order, type_class, length_class, value_class)
156
- field_order.each_char do |field_type|
157
- case field_type
155
+ def generate_attributes(klass, attr_order, type_class, length_class, value_class)
156
+ attr_order.each_char do |attr_type|
157
+ case attr_type
158
158
  when 'T'
159
159
  if type_class < Enum
160
- klass.define_field(:type, type_class, enum: {})
160
+ klass.define_attr(:type, type_class, enum: {})
161
161
  else
162
- klass.define_field(:type, type_class)
162
+ klass.define_attr(:type, type_class)
163
163
  end
164
164
  when 'L'
165
- klass.define_field(:length, length_class)
165
+ klass.define_attr(:length, length_class)
166
166
  when 'V'
167
- klass.define_field(:value, value_class)
167
+ klass.define_attr(:value, value_class)
168
168
  end
169
169
  end
170
170
  end
171
171
  end
172
172
 
173
173
  # @!attribute type
174
- # @abstract Type attribute
174
+ # @abstract
175
+ # Type attribute
175
176
  # @return [Integer]
176
177
  # @!attribute length
177
- # @abstract Length
178
+ # @abstract
179
+ # Length attribute
178
180
  # @return [Integer]
179
181
  # @!attribute value
180
- # @abstract Value attribute
182
+ # @abstract
183
+ # Value attribute
181
184
  # @return [Object]enum
182
185
 
183
186
  # @abstract Should only be called on real TLV classes, created by {.create}.
187
+ # Return a new instance of a real TLV class.
184
188
  # @param [Hash] options
185
189
  # @option options [Integer] :type
186
190
  # @option options [Integer] :length
187
191
  # @option options [Object] :value
188
192
  def initialize(options = {})
189
- @field_in_length = self.class.field_in_length
193
+ @attr_in_length = self.class.attr_in_length
190
194
  self.class.aliases.each do |al, orig|
191
195
  options[orig] = options[al] if options.key?(al)
192
196
  end
@@ -199,17 +203,17 @@ module BinStruct
199
203
 
200
204
  # @abstract Should only be called on real TLV class instances.
201
205
  # Populate object from a binary string
202
- # @param [String,nil] str
203
- # @return [Fields] self
206
+ # @param [::String,nil] str
207
+ # @return [AbstractTLV] self
204
208
  def read(str)
205
209
  return self if str.nil?
206
210
 
207
211
  idx = 0
208
- fields.each do |field_name|
209
- field = self[field_name]
210
- length = field_name == :value ? real_length : field.sz
211
- field.read(str[idx, length])
212
- idx += field.sz
212
+ attributes.each do |attr_name|
213
+ attr = self[attr_name]
214
+ length = attr_name == :value ? real_length : attr.sz
215
+ attr.read(str[idx, length])
216
+ idx += attr.sz
213
217
  end
214
218
 
215
219
  self
@@ -219,7 +223,6 @@ module BinStruct
219
223
  # Set +value+. May set +length+ if value is a {Types::String}.
220
224
  # @param [Object] val
221
225
  # @return [Object]
222
- # @since 3.4.0 Base on field's +#from_human+ method
223
226
  def value=(val)
224
227
  if val.is_a?(self[:value].class)
225
228
  self[:value] = val
@@ -233,27 +236,26 @@ module BinStruct
233
236
 
234
237
  # @abstract Should only be called on real TLV class instances.
235
238
  # Get human-readable type
236
- # @return [String]
239
+ # @return [::String]
237
240
  def human_type
238
241
  self[:type].to_human.to_s
239
242
  end
240
243
 
241
244
  # @abstract Should only be called on real TLV class instances.
242
- # @return [String]
245
+ # @return [::String]
243
246
  def to_human
244
247
  my_value = self[:value].is_a?(String) ? self[:value].inspect : self[:value].to_human
245
248
  'type:%s,length:%u,value:%s' % [human_type, length, my_value]
246
249
  end
247
250
 
248
251
  # Calculate length
249
- # @return [void]
250
- # @since 3.4.0
252
+ # @return [Integer]
251
253
  def calc_length
252
- fil = @field_in_length
254
+ ail = @attr_in_length
253
255
 
254
256
  length = 0
255
- fil.each_char do |field_type|
256
- length += self[FIELD_TYPES[field_type]].sz
257
+ ail.each_char do |attr_type|
258
+ length += self[ATTR_TYPES[attr_type]].sz
257
259
  end
258
260
  self.length = length
259
261
  end
@@ -262,8 +264,8 @@ module BinStruct
262
264
 
263
265
  def real_length
264
266
  length = self.length
265
- length -= self[:type].sz if @field_in_length.include?('T')
266
- length -= self[:length].sz if @field_in_length.include?('L')
267
+ length -= self[:type].sz if @attr_in_length.include?('T')
268
+ length -= self[:length].sz if @attr_in_length.include?('L')
267
269
  length
268
270
  end
269
271
  end
@@ -9,10 +9,15 @@
9
9
  require 'forwardable'
10
10
 
11
11
  module BinStruct
12
- # @abstract Base class to define set of {Fields} subclasses.
12
+ # @abstract Base class to define set of {Struct} subclasses.
13
+ #
14
+ # This class mimics regular Ruby Array, but it is {Structable} and responds to {LengthFrom}.
15
+ #
16
+ # Concrete subclasses may define 2 private methods:
17
+ #
13
18
  # == #record_from_hash
14
- # Subclasses should define private method +#record_from_hash+. This method
15
- # is called by {#push} to add an object to the set.
19
+ # This method
20
+ # is called by {#push} and {#<<} to add an object to the set.
16
21
  #
17
22
  # A default method is defined by {Array}: it calls constructor of class defined
18
23
  # by {.set_of}.
@@ -24,16 +29,17 @@ module BinStruct
24
29
  #
25
30
  # Default behaviour of this method is to return argument's class.
26
31
  #
27
- # @author Sylvain Daubert
32
+ # @author Sylvain Daubert (2016-2024)
33
+ # @author LemonTree55
28
34
  class Array
29
35
  extend Forwardable
30
36
  include Enumerable
31
- include Fieldable
37
+ include Structable
32
38
  include LengthFrom
33
39
 
34
40
  # @!method [](index)
35
41
  # Return the element at +index+.
36
- # @param [integer] index
42
+ # @param [Integer] index
37
43
  # @return [Object]
38
44
  # @!method clear
39
45
  # Clear array.
@@ -41,10 +47,10 @@ module BinStruct
41
47
  # @!method each
42
48
  # Calls the given block once for each element in self, passing that
43
49
  # element as a parameter. Returns the array itself.
44
- # @return [Array]
50
+ # @return [::Array]
45
51
  # @method empty?
46
52
  # Return +true+ if contains no element.
47
- # @return [Booelan]
53
+ # @return [Boolean]
48
54
  # @!method first
49
55
  # Return first element
50
56
  # @return [Object]
@@ -58,14 +64,13 @@ module BinStruct
58
64
  alias length size
59
65
 
60
66
  # Separator used in {#to_human}.
61
- # May be ovverriden by subclasses
67
+ # May be overriden by subclasses
62
68
  HUMAN_SEPARATOR = ','
63
69
 
64
70
  # rubocop:disable Naming/AccessorMethodName
65
71
  class << self
66
72
  # Get class set with {.set_of}.
67
73
  # @return [Class]
68
- # @since 3.0.0
69
74
  def set_of_klass
70
75
  @klass
71
76
  end
@@ -89,10 +94,13 @@ module BinStruct
89
94
 
90
95
  # Initialize array for copy:
91
96
  # * duplicate internal array.
97
+ # @note Associated counter, if any, is not duplicated
92
98
  def initialize_copy(_other)
93
99
  @array = @array.dup
94
100
  end
95
101
 
102
+ # Check equality. Equality is checked on underlying array.
103
+ # @return [Boolean]
96
104
  def ==(other)
97
105
  @array == case other
98
106
  when Array
@@ -118,7 +126,7 @@ module BinStruct
118
126
  deleted
119
127
  end
120
128
 
121
- # Delete element at +index+.
129
+ # Delete element at +index+. Update associated counter if any
122
130
  # @param [Integer] index
123
131
  # @return [Object,nil] deleted object
124
132
  def delete_at(index)
@@ -129,13 +137,14 @@ module BinStruct
129
137
 
130
138
  # @abstract depend on private method +#record_from_hash+ which should be
131
139
  # declared by subclasses.
132
- # Add an object to this array
140
+ # Add an object to this array. Do not update associated counter.
133
141
  # @param [Object] obj type depends on subclass
134
- # @return [Array] self
142
+ # @return [self]
143
+ # @see #<<
135
144
  def push(obj)
136
145
  obj = case obj
137
146
  when Hash
138
- record_from_hash obj
147
+ record_from_hash(obj)
139
148
  else
140
149
  obj
141
150
  end
@@ -147,15 +156,15 @@ module BinStruct
147
156
  # declared by subclasses.
148
157
  # Add an object to this array, and increment associated counter, if any
149
158
  # @param [Object] obj type depends on subclass
150
- # @return [Array] self
159
+ # @return [self]
151
160
  def <<(obj)
152
- push obj
161
+ push(obj)
153
162
  @counter&.from_human(@counter.to_i + 1)
154
163
  self
155
164
  end
156
165
 
157
166
  # Populate object from a string or from an array of hashes
158
- # @param [String, Array<Hash>] data
167
+ # @param [::String, ::Array<Hash>] data
159
168
  # @return [self]
160
169
  def read(data)
161
170
  clear
@@ -174,20 +183,20 @@ module BinStruct
174
183
  to_s.size
175
184
  end
176
185
 
177
- # Return an Array
186
+ # Return underlying Ruby Array
178
187
  # @return [::Array]
179
188
  def to_a
180
189
  @array
181
190
  end
182
191
 
183
192
  # Get binary string
184
- # @return [String]
193
+ # @return [::String]
185
194
  def to_s
186
195
  @array.map(&:to_s).join
187
196
  end
188
197
 
189
198
  # Get a human readable string
190
- # @return [String]
199
+ # @return [::String]
191
200
  def to_human
192
201
  @array.map(&:to_human).join(self.class::HUMAN_SEPARATOR)
193
202
  end
@@ -251,36 +260,36 @@ module BinStruct
251
260
  return self if ary.empty?
252
261
 
253
262
  ary.each do |i|
254
- self << self.class.set_of_klass.new(i)
263
+ self << self.class.set_of_klass.new(value: i)
255
264
  end
256
265
  end
257
266
  end
258
267
 
259
- # Specialized array to handle serie of {Int8}.
268
+ # Specialized {Array} to handle serie of {Int8}.
260
269
  class ArrayOfInt8 < Array
261
270
  include ArrayOfIntMixin
262
271
  set_of Int8
263
272
  end
264
273
 
265
- # Specialized array to handle serie of {Int16}.
274
+ # Specialized {Array} to handle serie of {Int16}.
266
275
  class ArrayOfInt16 < Array
267
276
  include ArrayOfIntMixin
268
277
  set_of Int16
269
278
  end
270
279
 
271
- # Specialized array to handle serie of {Int16le}.
280
+ # Specialized {Array} to handle serie of {Int16le}.
272
281
  class ArrayOfInt16le < Array
273
282
  include ArrayOfIntMixin
274
283
  set_of Int16le
275
284
  end
276
285
 
277
- # Specialized array to handle serie of {Int32}.
286
+ # Specialized {Array} to handle serie of {Int32}.
278
287
  class ArrayOfInt32 < BinStruct::Array
279
288
  include ArrayOfIntMixin
280
289
  set_of Int32
281
290
  end
282
291
 
283
- # Specialized array to handle serie of {Int32le}.
292
+ # Specialized {Array} to handle serie of {Int32le}.
284
293
  class ArrayOfInt32le < BinStruct::Array
285
294
  include ArrayOfIntMixin
286
295
  set_of Int32le
@@ -10,19 +10,68 @@ require 'forwardable'
10
10
 
11
11
  module BinStruct
12
12
  # This class handles null-terminated strings (aka C strings).
13
- # @author Sylvain Daubert
14
- # @since 3.1.6 no more a subclass or regular String
13
+ # @author Sylvain Daubert (2016-2024)
14
+ # @author LemonTree55
15
15
  class CString
16
16
  extend Forwardable
17
- include Fieldable
18
-
17
+ include Structable
18
+
19
+ # @!method [](index)
20
+ # @overload [](index)
21
+ # Return the character at +index+.
22
+ # @param [Integer] index
23
+ # @overload [](start, length)
24
+ # Return the substring starting at +start+ with +length+ length.
25
+ # @param [Integer] start
26
+ # @param [Integer] length
27
+ # @return [::String,nil]
28
+ # @!method length
29
+ # Return string length (without null-terminator)
30
+ # @return [Integer]
31
+ # @method size
32
+ # Return string length (without null-terminator)
33
+ # @return [Integer]
34
+ # @see #length
35
+ # @!method ==
36
+ # Check equality with underlying Ruby String
37
+ # @return [Boolean]
38
+ # @!method unpack
39
+ # Apply unpack on underlying Ruby String
40
+ # @see ::String#unpack
41
+ # @return [::Array]
42
+ # @!method force_encoding
43
+ # @see ::String#force_encoding
44
+ # @!method encoding
45
+ # @see ::String#encoding
46
+ # @return [Encoding]
47
+ # @!method index(substring, offset = 0)
48
+ # Returns the Integer index of the first occurrence of the given substring, or +nil+ if none found.
49
+ # @param [::String] substring
50
+ # @param [Integer] offset
51
+ # @return [Integer,nil]
52
+ # @!method empty?
53
+ # Return +true+ is string is empty.
54
+ # @return [Boolean]
55
+ # @!method encode(encoding, **options)
56
+ # @return [::String]
57
+ # @see ::String#encode
58
+ # @!method slice(*args)
59
+ # Returns the substring of +self+ specified by the arguments.
60
+ # @see ::String#slice
61
+ # @return [String,nil]
62
+ # @!method slice!(*args)
63
+ # Removes the substring of +self+ specified by the arguments; returns the removed substring.
64
+ # @see ::String#slice!
65
+ # @return [String,nil]
19
66
  def_delegators :@string, :[], :length, :size, :inspect, :==,
20
67
  :unpack, :force_encoding, :encoding, :index, :empty?,
21
68
  :encode, :slice, :slice!
22
69
 
70
+ # Underlying Ruby String
23
71
  # @return [::String]
24
72
  attr_reader :string
25
- # @return [Integer]
73
+ # Static length, if any
74
+ # @return [Integer,nil]
26
75
  attr_reader :static_length
27
76
 
28
77
  # @param [Hash] options
@@ -32,8 +81,9 @@ module BinStruct
32
81
  @static_length = options[:static_length]
33
82
  end
34
83
 
84
+ # Populate self from binary string
35
85
  # @param [::String] str
36
- # @return [String] self
86
+ # @return [self]
37
87
  def read(str)
38
88
  s = str.to_s
39
89
  s = s[0, static_length] if static_length?
@@ -42,8 +92,8 @@ module BinStruct
42
92
  self
43
93
  end
44
94
 
45
- # get null-terminated string
46
- # @return [String]
95
+ # Get null-terminated string
96
+ # @return [::String]
47
97
  def to_s
48
98
  if static_length?
49
99
  s = string[0, static_length - 1]
@@ -63,6 +113,7 @@ module BinStruct
63
113
  self
64
114
  end
65
115
 
116
+ # Get C String size in bytes
66
117
  # @return [Integer]
67
118
  def sz
68
119
  if static_length?
@@ -74,19 +125,19 @@ module BinStruct
74
125
 
75
126
  # Say if a static length is defined
76
127
  # @return [Boolean]
77
- # @since 3.1.6
78
128
  def static_length?
79
129
  !static_length.nil?
80
130
  end
81
131
 
82
132
  # Populate CString from a human readable string
83
- # @param [String] str
133
+ # @param [::String] str
84
134
  # @return [self]
85
135
  def from_human(str)
86
136
  read str
87
137
  end
88
138
 
89
- # @return [String]
139
+ # Get human-readable string
140
+ # @return [::String]
90
141
  def to_human
91
142
  string
92
143
  end