bin_struct 0.5.2 → 0.5.3
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +2 -2
- data/lib/bin_struct/abstract_tlv.rb +39 -16
- data/lib/bin_struct/array.rb +46 -16
- data/lib/bin_struct/bit_attr.rb +41 -28
- data/lib/bin_struct/cstring.rb +15 -12
- data/lib/bin_struct/enum.rb +9 -9
- data/lib/bin_struct/int.rb +31 -29
- data/lib/bin_struct/int_string.rb +13 -12
- data/lib/bin_struct/length_from.rb +2 -2
- data/lib/bin_struct/oui.rb +1 -1
- data/lib/bin_struct/string.rb +6 -5
- data/lib/bin_struct/struct.rb +122 -77
- data/lib/bin_struct/structable.rb +1 -1
- data/lib/bin_struct/version.rb +1 -1
- data/lib/bin_struct.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d31367b8cbffd8fd978aab672f493f0d2e1fc099daf19a4cc596ff54f862c43a
|
|
4
|
+
data.tar.gz: dbd457e23e12953f89576c4dc2790b56486d0da3c37dbdc92d3e1103710995c4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 801697a0c78ee32edc0925e5bcf46efed24b91ae5404dd633c98a27dea80db4983c2634a1743983d8a6e310d73937b2c5a0aaa4808f8088d3fb5a5052577fcc8
|
|
7
|
+
data.tar.gz: 1a046d96ed17805e20928e60cceb8607d34055a7cd4b67bf4cacea3d80ded1d9c2044be480d21f4e21b92fe16b57a1653a21897b36d66244c440dfe0e1106bda
|
data/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
4
4
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
5
5
|
|
|
6
|
+
## 0.5.3 - 2026-01-07
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- Ensure `BitAttr` internal integer is always up to date.
|
|
11
|
+
- Clean up yard doc.
|
|
12
|
+
|
|
13
|
+
### Removed
|
|
14
|
+
|
|
15
|
+
- Remove support for Ruby < 3.1
|
|
16
|
+
|
|
6
17
|
## 0.5.2 - 2025-08-14
|
|
7
18
|
|
|
8
19
|
### Fixed
|
data/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
[](https://badge.fury.io/rb/bin_struct)
|
|
2
|
-
[](https://ci.codeberg.org/repos/15063)
|
|
3
3
|
|
|
4
4
|
# BinStruct
|
|
5
5
|
|
|
6
|
-
BinStruct provides a simple way to create and dissect binary data. It is an extraction from [PacketGen](https://
|
|
6
|
+
BinStruct provides a simple way to create and dissect binary data. It is an extraction from [PacketGen](https://codeberg.org/lemontree55/packetgen) 3.x Fields.
|
|
7
7
|
|
|
8
8
|
## Installation
|
|
9
9
|
|
|
@@ -74,12 +74,13 @@ module BinStruct
|
|
|
74
74
|
# rubocop:disable Metrics/ParameterLists
|
|
75
75
|
|
|
76
76
|
# Generate a TLV class
|
|
77
|
-
# @param [Class]
|
|
78
|
-
# @param [Class]
|
|
79
|
-
# @param [Class]
|
|
80
|
-
# @param [
|
|
77
|
+
# @param type_class [Class] Class to use for +type+
|
|
78
|
+
# @param length_class [Class] Class to use for +length+
|
|
79
|
+
# @param value_class [Class] Class to use for +value+
|
|
80
|
+
# @param aliases [Hash{Symbol=>Symbol}] define aliases with key an alias to an existing accessor (the value)
|
|
81
|
+
# @param attr_order [::String] gives attribute order. Each character in [T,L,V] MUST be present once,
|
|
81
82
|
# in the desired order.
|
|
82
|
-
# @param [::String]
|
|
83
|
+
# @param attr_in_length [::String] give attributes to compute length on.
|
|
83
84
|
# @return [Class]
|
|
84
85
|
# @raise [Error] Called on {AbstractTLV} subclass
|
|
85
86
|
def create(type_class: Int8Enum, length_class: Int8, value_class: String,
|
|
@@ -109,7 +110,7 @@ module BinStruct
|
|
|
109
110
|
# rubocop:enable Metrics/ParameterLists
|
|
110
111
|
|
|
111
112
|
# On inheritage, copy aliases and attr_in_length
|
|
112
|
-
# @param [Class]
|
|
113
|
+
# @param klass [Class] inheriting class
|
|
113
114
|
# @return [void]
|
|
114
115
|
# @since 0.4.0
|
|
115
116
|
# @author LemonTree55
|
|
@@ -126,9 +127,10 @@ module BinStruct
|
|
|
126
127
|
end
|
|
127
128
|
|
|
128
129
|
# Derive a new TLV class from an existing one
|
|
129
|
-
# @param [Class,nil]
|
|
130
|
-
# @param [Class,nil]
|
|
131
|
-
# @param [Class,nil]
|
|
130
|
+
# @param type_class [Class,nil] New class to use for +type+. Unchanged if +nil+.
|
|
131
|
+
# @param length_class [Class,nil] New class to use for +length+. Unchanged if +nil+.
|
|
132
|
+
# @param value_class [Class,nil] New class to use for +value+. Unchanged if +nil+.
|
|
133
|
+
# @param aliases [Hash{Symbol=>Symbol}] define aliases with key an alias to an existing accessor (the value)
|
|
132
134
|
# @return [Class]
|
|
133
135
|
# @raise [Error] Called on {AbstractTLV} class
|
|
134
136
|
# @since 0.4.0
|
|
@@ -167,7 +169,7 @@ module BinStruct
|
|
|
167
169
|
|
|
168
170
|
# @abstract Should only be called on real TLV classes, created by {.create}.
|
|
169
171
|
# Set enum hash for {#type} attribute.
|
|
170
|
-
# @param [Hash{::String, Symbol => Integer}]
|
|
172
|
+
# @param hsh [Hash{::String, Symbol => Integer}] enum hash
|
|
171
173
|
# @return [void]
|
|
172
174
|
def define_type_enum(hsh)
|
|
173
175
|
attr_defs[:type][:options][:enum].clear
|
|
@@ -176,7 +178,7 @@ module BinStruct
|
|
|
176
178
|
|
|
177
179
|
# @abstract Should only be called on real TLV classes, created by {.create}.
|
|
178
180
|
# Set default value for {#type} attribute.
|
|
179
|
-
# @param [Integer,::String,Symbol,nil] default
|
|
181
|
+
# @param default [Integer,::String,Symbol,nil] default value from +hsh+ for type
|
|
180
182
|
# @return [void]
|
|
181
183
|
def define_type_default(default)
|
|
182
184
|
attr_defs[:type][:default] = default
|
|
@@ -184,12 +186,19 @@ module BinStruct
|
|
|
184
186
|
|
|
185
187
|
private
|
|
186
188
|
|
|
189
|
+
# Check +attr_in_length+ and raise if it contains unknown characters
|
|
190
|
+
# @param attr_in_length [::String]
|
|
191
|
+
# @return [void]
|
|
192
|
+
# @raise [Error] +attr_in_length+ contains unsupported characters
|
|
187
193
|
def check_attr_in_length(attr_in_length)
|
|
188
194
|
return if /^[TLV]{1,3}$/.match?(attr_in_length)
|
|
189
195
|
|
|
190
|
-
raise 'attr_in_length must only contain T, L and/or V characters'
|
|
196
|
+
raise Error, 'attr_in_length must only contain T, L and/or V characters'
|
|
191
197
|
end
|
|
192
198
|
|
|
199
|
+
# @param attr_order [::String]
|
|
200
|
+
# @return [void]
|
|
201
|
+
# @raise [Error] +attr_order+ contains unsupported characters
|
|
193
202
|
def check_attr_order(attr_order)
|
|
194
203
|
if attr_order.match(/^[TLV]{3,3}$/) &&
|
|
195
204
|
(attr_order[0] != attr_order[1]) &&
|
|
@@ -198,9 +207,16 @@ module BinStruct
|
|
|
198
207
|
return
|
|
199
208
|
end
|
|
200
209
|
|
|
201
|
-
raise 'attr_order must contain all three letters TLV, each once'
|
|
210
|
+
raise Error, 'attr_order must contain all three letters TLV, each once'
|
|
202
211
|
end
|
|
203
212
|
|
|
213
|
+
# Set TLV classes and order on +klass+
|
|
214
|
+
# @param klass [Class]
|
|
215
|
+
# @param attr_order [::String]
|
|
216
|
+
# @param type_class [Class]
|
|
217
|
+
# @param length_class [Class]
|
|
218
|
+
# @param value_class [Class]
|
|
219
|
+
# @return [AbstractTLV]
|
|
204
220
|
def generate_attributes(klass, attr_order, type_class, length_class, value_class)
|
|
205
221
|
attr_order.each_char do |attr_type|
|
|
206
222
|
case attr_type
|
|
@@ -218,6 +234,10 @@ module BinStruct
|
|
|
218
234
|
end
|
|
219
235
|
end
|
|
220
236
|
|
|
237
|
+
# Define given +aliases+ on +klass+
|
|
238
|
+
# @param klass [Class]
|
|
239
|
+
# @param aliases [Hash{Symbol=>Symbol}]
|
|
240
|
+
# @return [void]
|
|
221
241
|
def generate_aliases_for(klass, aliases)
|
|
222
242
|
aliases.each do |al, orig|
|
|
223
243
|
klass.instance_eval do
|
|
@@ -243,7 +263,7 @@ module BinStruct
|
|
|
243
263
|
|
|
244
264
|
# @abstract Should only be called on real TLV classes, created by {.create}.
|
|
245
265
|
# Return a new instance of a real TLV class.
|
|
246
|
-
# @param [Hash]
|
|
266
|
+
# @param options [Hash]
|
|
247
267
|
# @option options [Integer] :type
|
|
248
268
|
# @option options [Integer] :length
|
|
249
269
|
# @option options [Object] :value
|
|
@@ -261,12 +281,13 @@ module BinStruct
|
|
|
261
281
|
|
|
262
282
|
# @abstract Should only be called on real TLV class instances.
|
|
263
283
|
# Populate object from a binary string
|
|
264
|
-
# @param [::String,nil]
|
|
284
|
+
# @param str [::String,nil]
|
|
265
285
|
# @return [AbstractTLV] self
|
|
266
286
|
def read(str)
|
|
267
287
|
return self if str.nil?
|
|
268
288
|
|
|
269
289
|
idx = 0
|
|
290
|
+
str = str.b
|
|
270
291
|
attributes.each do |attr_name|
|
|
271
292
|
attr = self[attr_name]
|
|
272
293
|
length = attr_name == :value ? real_length : attr.sz
|
|
@@ -279,7 +300,7 @@ module BinStruct
|
|
|
279
300
|
|
|
280
301
|
# @abstract Should only be called on real TLV class instances.
|
|
281
302
|
# Set +value+. May set +length+ if value is a {Types::String}.
|
|
282
|
-
# @param [Object]
|
|
303
|
+
# @param val [Object]
|
|
283
304
|
# @return [Object]
|
|
284
305
|
def value=(val)
|
|
285
306
|
if val.is_a?(self[:value].class)
|
|
@@ -320,6 +341,8 @@ module BinStruct
|
|
|
320
341
|
|
|
321
342
|
private
|
|
322
343
|
|
|
344
|
+
# Compute length to set in length attribute
|
|
345
|
+
# @return [::Integer]
|
|
323
346
|
def real_length
|
|
324
347
|
length = self.length
|
|
325
348
|
length -= self[:type].sz if @attr_in_length.include?('T')
|
data/lib/bin_struct/array.rb
CHANGED
|
@@ -39,7 +39,7 @@ module BinStruct
|
|
|
39
39
|
|
|
40
40
|
# @!method [](index)
|
|
41
41
|
# Return the element at +index+.
|
|
42
|
-
# @param [Integer]
|
|
42
|
+
# @param index [Integer]
|
|
43
43
|
# @return [Object]
|
|
44
44
|
# @!method clear
|
|
45
45
|
# Clear array.
|
|
@@ -77,7 +77,7 @@ module BinStruct
|
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
# Define type of objects in set. Used by {#read} and {#push}.
|
|
80
|
-
# @param [Class]
|
|
80
|
+
# @param klass [Class]
|
|
81
81
|
# @return [void]
|
|
82
82
|
def set_of(klass)
|
|
83
83
|
@klass = klass
|
|
@@ -85,7 +85,7 @@ module BinStruct
|
|
|
85
85
|
end
|
|
86
86
|
# rubocop:enable Naming/AccessorMethodName
|
|
87
87
|
|
|
88
|
-
# @param [Hash]
|
|
88
|
+
# @param options [Hash]
|
|
89
89
|
# @option options [Int] counter Int object used as a counter for this set
|
|
90
90
|
# @example counter example
|
|
91
91
|
# # Define a counter
|
|
@@ -113,11 +113,12 @@ module BinStruct
|
|
|
113
113
|
# Initialize array for copy:
|
|
114
114
|
# * duplicate internal array.
|
|
115
115
|
# @note Associated counter, if any, is not duplicated
|
|
116
|
-
def initialize_copy(
|
|
116
|
+
def initialize_copy(*)
|
|
117
117
|
@array = @array.dup
|
|
118
118
|
end
|
|
119
119
|
|
|
120
120
|
# Check equality. Equality is checked on underlying array.
|
|
121
|
+
# @param other [Object]
|
|
121
122
|
# @return [Boolean]
|
|
122
123
|
def ==(other)
|
|
123
124
|
@array == case other
|
|
@@ -137,7 +138,7 @@ module BinStruct
|
|
|
137
138
|
end
|
|
138
139
|
|
|
139
140
|
# Delete an object from this array. Update associated counter if any
|
|
140
|
-
# @param [Object]
|
|
141
|
+
# @param obj [Object]
|
|
141
142
|
# @return [Object] deleted object
|
|
142
143
|
def delete(obj)
|
|
143
144
|
deleted = @array.delete(obj)
|
|
@@ -146,7 +147,7 @@ module BinStruct
|
|
|
146
147
|
end
|
|
147
148
|
|
|
148
149
|
# Delete element at +index+. Update associated counter if any
|
|
149
|
-
# @param [Integer]
|
|
150
|
+
# @param index [Integer]
|
|
150
151
|
# @return [Object,nil] deleted object
|
|
151
152
|
def delete_at(index)
|
|
152
153
|
deleted = @array.delete_at(index)
|
|
@@ -158,7 +159,7 @@ module BinStruct
|
|
|
158
159
|
# declared by subclasses.
|
|
159
160
|
# Add an object to this array. Do not update associated counter. If associated must be incremented, use
|
|
160
161
|
# {#<<}
|
|
161
|
-
# @param [Object]
|
|
162
|
+
# @param obj [Object] type depends on subclass
|
|
162
163
|
# @return [self]
|
|
163
164
|
# @see #<<
|
|
164
165
|
def push(obj)
|
|
@@ -176,7 +177,7 @@ module BinStruct
|
|
|
176
177
|
# declared by subclasses.
|
|
177
178
|
# Add an object to this array, and increment associated counter, if any. If associated counter must not be
|
|
178
179
|
# incremented, use {#push}.
|
|
179
|
-
# @param [Object]
|
|
180
|
+
# @param obj [Object] type depends on subclass
|
|
180
181
|
# @return [self]
|
|
181
182
|
# @see #push
|
|
182
183
|
def <<(obj)
|
|
@@ -186,7 +187,7 @@ module BinStruct
|
|
|
186
187
|
end
|
|
187
188
|
|
|
188
189
|
# Populate object from a string or from an array of hashes
|
|
189
|
-
# @param [::String, ::Array<Hash>]
|
|
190
|
+
# @param data [::String, ::Array<Hash>]
|
|
190
191
|
# @return [self]
|
|
191
192
|
def read(data)
|
|
192
193
|
clear
|
|
@@ -227,6 +228,8 @@ module BinStruct
|
|
|
227
228
|
|
|
228
229
|
# rubocop:disable Metrics/CyclomaticComplexity
|
|
229
230
|
|
|
231
|
+
# @param str [::String]
|
|
232
|
+
# @return [void]
|
|
230
233
|
def read_from_string(str)
|
|
231
234
|
return self if str.nil? || @counter&.to_i&.zero?
|
|
232
235
|
|
|
@@ -239,6 +242,8 @@ module BinStruct
|
|
|
239
242
|
end
|
|
240
243
|
# rubocop:enable Metrics/CyclomaticComplexity
|
|
241
244
|
|
|
245
|
+
# @param ary [::Array<Hash{Symbol=>Object}>]
|
|
246
|
+
# @return [void]
|
|
242
247
|
def read_from_array(ary)
|
|
243
248
|
return self if ary.empty?
|
|
244
249
|
|
|
@@ -247,6 +252,11 @@ module BinStruct
|
|
|
247
252
|
end
|
|
248
253
|
end
|
|
249
254
|
|
|
255
|
+
# @abstract Subclasses may override this method to customize {#<<}, {#push} and {#read}.
|
|
256
|
+
# A default implementation is provided.
|
|
257
|
+
# This method instanciate a {.set_of_klass} object from +hsh+.
|
|
258
|
+
# @param hsh [Hash{Symbol=>Object}]
|
|
259
|
+
# @return [Object] an object of (sub)class {.set_of_klass}
|
|
250
260
|
def record_from_hash(hsh)
|
|
251
261
|
obj_klass = self.class.set_of_klass
|
|
252
262
|
unless obj_klass
|
|
@@ -254,15 +264,25 @@ module BinStruct
|
|
|
254
264
|
'class should define #record_from_hash or declare type of elements in set with .set_of'
|
|
255
265
|
end
|
|
256
266
|
|
|
257
|
-
obj = obj_klass.new(hsh)
|
|
267
|
+
obj = obj_klass.new(hsh)
|
|
258
268
|
klass = real_type(obj)
|
|
259
269
|
klass == obj_klass ? obj : klass.new(hsh)
|
|
260
270
|
end
|
|
261
271
|
|
|
272
|
+
# @abstract Subclasses may override thi method to customize {#<<}, {#push} and {#read}.
|
|
273
|
+
# A default implementation is provided.
|
|
274
|
+
# Return real type for +_obj+. Here, always return {.set_of_klass}.
|
|
275
|
+
# @param _obj [Object] not used here but may be by subclasses
|
|
276
|
+
# @return [Object] an object of class {.set_of_class}
|
|
262
277
|
def real_type(_obj)
|
|
263
278
|
self.class.set_of_klass
|
|
264
279
|
end
|
|
265
280
|
|
|
281
|
+
# @abstract Subclasses may override thi method to customize {#<<}, {#push} and {#read}.
|
|
282
|
+
# A default implementation is provided.
|
|
283
|
+
# Instanicate an object to put in self from a String
|
|
284
|
+
# @param str [::String] not used here but may be by subclasses
|
|
285
|
+
# @return [Object] an object of class {.set_of_class}
|
|
266
286
|
def create_object_from_str(str)
|
|
267
287
|
klass = self.class.set_of_klass
|
|
268
288
|
obj = klass.new.read(str)
|
|
@@ -277,17 +297,22 @@ module BinStruct
|
|
|
277
297
|
end
|
|
278
298
|
|
|
279
299
|
# @private
|
|
300
|
+
# Mixin to define common methods to all +ArrayOfInt*+ classes.
|
|
280
301
|
module ArrayOfIntMixin
|
|
302
|
+
# Read data from an Array and instanciate an {Int} type (from {.set_of_klass}) for each element and put it in self.
|
|
303
|
+
# @param ary [::Array<Integer>]
|
|
304
|
+
# @return [void]
|
|
281
305
|
def read_from_array(ary)
|
|
282
306
|
return self if ary.empty?
|
|
283
307
|
|
|
308
|
+
inner_klass = self.class.set_of_klass
|
|
284
309
|
ary.each do |i|
|
|
285
|
-
self <<
|
|
310
|
+
self << inner_klass.new(value: i)
|
|
286
311
|
end
|
|
287
312
|
end
|
|
288
313
|
end
|
|
289
314
|
|
|
290
|
-
# Specialized {Array} to handle
|
|
315
|
+
# Specialized {Array} to handle series of {Int8}.
|
|
291
316
|
# @example
|
|
292
317
|
# ary = BinStruct::ArrayOfInt8.new
|
|
293
318
|
# ary.read([0, 1, 2])
|
|
@@ -297,10 +322,11 @@ module BinStruct
|
|
|
297
322
|
# ary.map(&:to_i) #=> [5, 6]
|
|
298
323
|
class ArrayOfInt8 < Array
|
|
299
324
|
include ArrayOfIntMixin
|
|
325
|
+
|
|
300
326
|
set_of Int8
|
|
301
327
|
end
|
|
302
328
|
|
|
303
|
-
# Specialized {Array} to handle
|
|
329
|
+
# Specialized {Array} to handle series of {Int16}.
|
|
304
330
|
# @example
|
|
305
331
|
# ary = BinStruct::ArrayOfInt16.new
|
|
306
332
|
# ary.read([0, 1, 2])
|
|
@@ -310,10 +336,11 @@ module BinStruct
|
|
|
310
336
|
# ary.map(&:to_i) #=> [0x0506]
|
|
311
337
|
class ArrayOfInt16 < Array
|
|
312
338
|
include ArrayOfIntMixin
|
|
339
|
+
|
|
313
340
|
set_of Int16
|
|
314
341
|
end
|
|
315
342
|
|
|
316
|
-
# Specialized {Array} to handle
|
|
343
|
+
# Specialized {Array} to handle series of {Int16le}.
|
|
317
344
|
# @example
|
|
318
345
|
# ary = BinStruct::ArrayOfInt16le.new
|
|
319
346
|
# ary.read([0, 1, 2])
|
|
@@ -323,10 +350,11 @@ module BinStruct
|
|
|
323
350
|
# ary.map(&:to_i) #=> [0x0605]
|
|
324
351
|
class ArrayOfInt16le < Array
|
|
325
352
|
include ArrayOfIntMixin
|
|
353
|
+
|
|
326
354
|
set_of Int16le
|
|
327
355
|
end
|
|
328
356
|
|
|
329
|
-
# Specialized {Array} to handle
|
|
357
|
+
# Specialized {Array} to handle series of {Int32}.
|
|
330
358
|
# @example
|
|
331
359
|
# ary = BinStruct::ArrayOfInt32.new
|
|
332
360
|
# ary.read([0, 1, 2])
|
|
@@ -336,10 +364,11 @@ module BinStruct
|
|
|
336
364
|
# ary.map(&:to_i) #=> [0x00000506]
|
|
337
365
|
class ArrayOfInt32 < BinStruct::Array
|
|
338
366
|
include ArrayOfIntMixin
|
|
367
|
+
|
|
339
368
|
set_of Int32
|
|
340
369
|
end
|
|
341
370
|
|
|
342
|
-
# Specialized {Array} to handle
|
|
371
|
+
# Specialized {Array} to handle series of {Int32le}.
|
|
343
372
|
# @example
|
|
344
373
|
# ary = BinStruct::ArrayOfInt32le.new
|
|
345
374
|
# ary.read([0, 1, 2])
|
|
@@ -349,6 +378,7 @@ module BinStruct
|
|
|
349
378
|
# ary.map(&:to_i) #=> [0x06050000]
|
|
350
379
|
class ArrayOfInt32le < BinStruct::Array
|
|
351
380
|
include ArrayOfIntMixin
|
|
381
|
+
|
|
352
382
|
set_of Int32le
|
|
353
383
|
end
|
|
354
384
|
end
|
data/lib/bin_struct/bit_attr.rb
CHANGED
|
@@ -34,6 +34,7 @@ module BinStruct
|
|
|
34
34
|
attr_reader :width
|
|
35
35
|
|
|
36
36
|
# @private
|
|
37
|
+
# @todo Ruby 3.2: replace Struct by Data
|
|
37
38
|
Parameters = Struct.new(:width, :fields, :int)
|
|
38
39
|
|
|
39
40
|
class << self
|
|
@@ -44,13 +45,13 @@ module BinStruct
|
|
|
44
45
|
attr_reader :parameters
|
|
45
46
|
|
|
46
47
|
# @private
|
|
47
|
-
# @return [::Array
|
|
48
|
+
# @return [::Array<Symbol>]
|
|
48
49
|
attr_reader :bit_methods
|
|
49
50
|
|
|
50
51
|
# Create a new {BitAttr} subclass with specified parameters
|
|
51
|
-
# @param [Integer]
|
|
52
|
-
# @param [
|
|
53
|
-
# @param [Hash{Symbol=>Integer}]
|
|
52
|
+
# @param width [Integer] size of bitfields in bits. Must be a size of an {Int} (8, 16, 24, 32 or 64 bits).
|
|
53
|
+
# @param endian [Symbol] endianess of bit attribute as an integer (:big, :little or :native)
|
|
54
|
+
# @param fields [Hash{Symbol=>Integer}] hash associating field names with their size. Total size MUST be equal
|
|
54
55
|
# to +width+.
|
|
55
56
|
# @return [Class]
|
|
56
57
|
# @raise [ArgumentError] raise if:
|
|
@@ -78,12 +79,16 @@ module BinStruct
|
|
|
78
79
|
@cache = {}
|
|
79
80
|
end
|
|
80
81
|
|
|
81
|
-
# @param [::Array]
|
|
82
|
+
# @param params [::Array]
|
|
82
83
|
# @return [::String]
|
|
83
84
|
def compute_hash(*params)
|
|
84
85
|
Digest::MD5.digest(Marshal.dump(params))
|
|
85
86
|
end
|
|
86
87
|
|
|
88
|
+
# @param width [::Integer]
|
|
89
|
+
# @param endian [Symbol] :little,:big or:native
|
|
90
|
+
# @param fields [Hash{Symbol=>Integer}]
|
|
91
|
+
# @return [Class] subclass of {BitAttr} with given parameters
|
|
87
92
|
def create_subclass(width, endian, fields)
|
|
88
93
|
klass = Class.new(self) do
|
|
89
94
|
int_klass = BinStruct.const_get("Int#{width}")
|
|
@@ -95,8 +100,8 @@ module BinStruct
|
|
|
95
100
|
klass
|
|
96
101
|
end
|
|
97
102
|
|
|
98
|
-
# @param [Class] {BitAttr} subclass
|
|
99
|
-
# @param [Hash{Symbol => Integer}]
|
|
103
|
+
# @param klass [Class] {BitAttr} subclass
|
|
104
|
+
# @param fields [Hash{Symbol => Integer}]
|
|
100
105
|
# @return [void]
|
|
101
106
|
def define_methods(klass, fields)
|
|
102
107
|
define_str = +''
|
|
@@ -109,9 +114,9 @@ module BinStruct
|
|
|
109
114
|
define_str << "def #{name}?; @data[#{name.inspect}] != 0; end\n"
|
|
110
115
|
klass.bit_methods << :"#{name}?"
|
|
111
116
|
define_str << "def #{name}=(val); v = case val when TrueClass; 1 when FalseClass; 0 else val end; " \
|
|
112
|
-
"@data[#{name.inspect}] = v; end\n"
|
|
117
|
+
"@data[#{name.inspect}] = v; @int.value = compute_integer; end\n"
|
|
113
118
|
else
|
|
114
|
-
define_str << "def #{name}=(val); @data[#{name.inspect}] = val; end\n"
|
|
119
|
+
define_str << "def #{name}=(val); @data[#{name.inspect}] = val; @int.value = compute_integer; end\n"
|
|
115
120
|
end
|
|
116
121
|
end
|
|
117
122
|
klass.class_eval(define_str)
|
|
@@ -119,11 +124,11 @@ module BinStruct
|
|
|
119
124
|
end
|
|
120
125
|
|
|
121
126
|
# Initialize bit attribute
|
|
122
|
-
# @param [Hash{Symbol=>Integer}]
|
|
127
|
+
# @param values [Hash{Symbol=>Integer}] initialization values for fields, where keys are field names and values are
|
|
123
128
|
# initialization values
|
|
124
129
|
# @return [self]
|
|
125
130
|
# @raise [NotImplementedError] raised when called on {BitAttr} class
|
|
126
|
-
def initialize(
|
|
131
|
+
def initialize(values = {})
|
|
127
132
|
parameters = self.class.parameters
|
|
128
133
|
raise NotImplementedError, "#initialize may only be called on subclass of #{self.class}" if parameters.nil?
|
|
129
134
|
|
|
@@ -131,19 +136,19 @@ module BinStruct
|
|
|
131
136
|
@fields = parameters.fields
|
|
132
137
|
@int = parameters.int.dup
|
|
133
138
|
@data = {}
|
|
134
|
-
@bit_methods = []
|
|
135
139
|
|
|
136
140
|
parameters.fields.each_key do |name|
|
|
137
|
-
@data[name] =
|
|
141
|
+
@data[name] = values[name] || 0
|
|
138
142
|
end
|
|
139
|
-
@
|
|
143
|
+
@int.value = compute_integer
|
|
140
144
|
end
|
|
141
145
|
|
|
142
|
-
|
|
146
|
+
# Dup internal @data hash
|
|
147
|
+
def initialize_copy(*)
|
|
143
148
|
@data = @data.dup
|
|
144
149
|
end
|
|
145
150
|
|
|
146
|
-
# @return [::Array
|
|
151
|
+
# @return [::Array<Symbol>]
|
|
147
152
|
def bit_methods
|
|
148
153
|
self.class.bit_methods
|
|
149
154
|
end
|
|
@@ -162,7 +167,7 @@ module BinStruct
|
|
|
162
167
|
end
|
|
163
168
|
|
|
164
169
|
# Populate bit attribute from +str+
|
|
165
|
-
# @param [#to_s,nil]
|
|
170
|
+
# @param str [#to_s,nil]
|
|
166
171
|
# @return [self]
|
|
167
172
|
def read(str)
|
|
168
173
|
return self if str.nil?
|
|
@@ -174,30 +179,26 @@ module BinStruct
|
|
|
174
179
|
# Give integer associated to this attribute
|
|
175
180
|
# @return [Integer]
|
|
176
181
|
def to_i
|
|
177
|
-
|
|
178
|
-
@fields.each do |name, size|
|
|
179
|
-
v <<= size
|
|
180
|
-
v |= @data[name]
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
v
|
|
182
|
+
@int.to_i
|
|
184
183
|
end
|
|
185
184
|
alias to_human to_i
|
|
186
185
|
|
|
187
186
|
# Return binary string
|
|
188
187
|
# @return [::String]
|
|
189
188
|
def to_s
|
|
190
|
-
@int.value = to_i
|
|
191
189
|
@int.to_s
|
|
192
190
|
end
|
|
193
191
|
|
|
194
192
|
# Set fields from associated integer
|
|
195
|
-
# @param [#to_i]
|
|
193
|
+
# @param value [#to_i]
|
|
196
194
|
# @return [self]
|
|
197
195
|
def from_human(value)
|
|
198
|
-
|
|
196
|
+
ivalue = value.to_i
|
|
197
|
+
@int.value = ivalue
|
|
198
|
+
compute_data(ivalue)
|
|
199
199
|
end
|
|
200
200
|
|
|
201
|
+
# @return [::String]
|
|
201
202
|
def format_inspect
|
|
202
203
|
str = @int.format_inspect << "\n"
|
|
203
204
|
str << @data.map { |name, value| "#{name}:#{value}" }.join(' ')
|
|
@@ -205,7 +206,7 @@ module BinStruct
|
|
|
205
206
|
|
|
206
207
|
private
|
|
207
208
|
|
|
208
|
-
# @param [Integer]
|
|
209
|
+
# @param value [Integer]
|
|
209
210
|
# @return [self]
|
|
210
211
|
def compute_data(value)
|
|
211
212
|
@fields.reverse_each do |name, size|
|
|
@@ -215,5 +216,17 @@ module BinStruct
|
|
|
215
216
|
|
|
216
217
|
self
|
|
217
218
|
end
|
|
219
|
+
|
|
220
|
+
# Compute integer from fields
|
|
221
|
+
# @return [Integer]
|
|
222
|
+
def compute_integer
|
|
223
|
+
v = 0
|
|
224
|
+
@fields.each do |name, size|
|
|
225
|
+
v <<= size
|
|
226
|
+
v |= @data[name]
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
v
|
|
230
|
+
end
|
|
218
231
|
end
|
|
219
232
|
end
|
data/lib/bin_struct/cstring.rb
CHANGED
|
@@ -22,11 +22,11 @@ module BinStruct
|
|
|
22
22
|
# @!method [](index)
|
|
23
23
|
# @overload [](index)
|
|
24
24
|
# Return the character at +index+.
|
|
25
|
-
# @param [Integer]
|
|
25
|
+
# @param index [Integer]
|
|
26
26
|
# @overload [](start, length)
|
|
27
27
|
# Return the substring starting at +start+ with +length+ length.
|
|
28
|
-
# @param [Integer]
|
|
29
|
-
# @param [Integer]
|
|
28
|
+
# @param start [Integer]
|
|
29
|
+
# @param length [Integer]
|
|
30
30
|
# @return [::String,nil]
|
|
31
31
|
# @!method length
|
|
32
32
|
# Return string length (without null-terminator)
|
|
@@ -49,8 +49,8 @@ module BinStruct
|
|
|
49
49
|
# @return [Encoding]
|
|
50
50
|
# @!method index(substring, offset = 0)
|
|
51
51
|
# Returns the Integer index of the first occurrence of the given substring, or +nil+ if none found.
|
|
52
|
-
# @param [::String]
|
|
53
|
-
# @param [Integer]
|
|
52
|
+
# @param substring [::String]
|
|
53
|
+
# @param offset [Integer]
|
|
54
54
|
# @return [Integer,nil]
|
|
55
55
|
# @!method empty?
|
|
56
56
|
# Return +true+ is string is empty.
|
|
@@ -77,7 +77,7 @@ module BinStruct
|
|
|
77
77
|
# @return [Integer,nil]
|
|
78
78
|
attr_reader :static_length
|
|
79
79
|
|
|
80
|
-
# @param [Hash]
|
|
80
|
+
# @param options [Hash]
|
|
81
81
|
# @option options [Integer] :static_length set a static length for this string
|
|
82
82
|
# @option options [::String] :value string value (default to +""+)
|
|
83
83
|
def initialize(options = {})
|
|
@@ -86,12 +86,12 @@ module BinStruct
|
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
# Populate self from binary string
|
|
89
|
-
# @param [#to_s]
|
|
89
|
+
# @param str [#to_s]
|
|
90
90
|
# @return [self]
|
|
91
91
|
def read(str)
|
|
92
92
|
s = str.to_s
|
|
93
93
|
s = s[0, static_length] if static_length?
|
|
94
|
-
register_internal_string
|
|
94
|
+
register_internal_string(s)
|
|
95
95
|
remove_null_character
|
|
96
96
|
self
|
|
97
97
|
end
|
|
@@ -109,10 +109,10 @@ module BinStruct
|
|
|
109
109
|
end
|
|
110
110
|
|
|
111
111
|
# Append the given string to CString
|
|
112
|
-
# @param [#to_s]
|
|
112
|
+
# @param str [#to_s]
|
|
113
113
|
# @return [self]
|
|
114
114
|
def <<(str)
|
|
115
|
-
@string << str.to_s
|
|
115
|
+
@string << str.to_s.b
|
|
116
116
|
remove_null_character
|
|
117
117
|
self
|
|
118
118
|
end
|
|
@@ -134,7 +134,7 @@ module BinStruct
|
|
|
134
134
|
end
|
|
135
135
|
|
|
136
136
|
# Populate CString from a human readable string
|
|
137
|
-
# @param [::String]
|
|
137
|
+
# @param str [::String]
|
|
138
138
|
# @return [self]
|
|
139
139
|
def from_human(str)
|
|
140
140
|
read(str)
|
|
@@ -148,12 +148,15 @@ module BinStruct
|
|
|
148
148
|
|
|
149
149
|
private
|
|
150
150
|
|
|
151
|
+
# @param str [::String]
|
|
152
|
+
# @return [void]
|
|
151
153
|
def register_internal_string(str)
|
|
152
154
|
@string = str.b
|
|
153
155
|
end
|
|
154
156
|
|
|
157
|
+
# @return [void]
|
|
155
158
|
def remove_null_character
|
|
156
|
-
idx = string.index(0
|
|
159
|
+
idx = string.index("\0")
|
|
157
160
|
register_internal_string(string[0, idx]) unless idx.nil?
|
|
158
161
|
end
|
|
159
162
|
end
|