bin_struct 0.1.0
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 +7 -0
- data/CHANGELOG.md +5 -0
- data/README.md +18 -0
- data/lib/bin_struct/abstract_tlv.rb +270 -0
- data/lib/bin_struct/array.rb +288 -0
- data/lib/bin_struct/cstring.rb +106 -0
- data/lib/bin_struct/enum.rb +200 -0
- data/lib/bin_struct/fieldable.rb +64 -0
- data/lib/bin_struct/fields.rb +612 -0
- data/lib/bin_struct/int.rb +514 -0
- data/lib/bin_struct/int_string.rb +99 -0
- data/lib/bin_struct/length_from.rb +51 -0
- data/lib/bin_struct/oui.rb +49 -0
- data/lib/bin_struct/string.rb +94 -0
- data/lib/bin_struct/version.rb +11 -0
- data/lib/bin_struct.rb +35 -0
- metadata +71 -0
@@ -0,0 +1,514 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This file is part of BinStruct
|
4
|
+
# See https://github.com/lemontree55/bin_struct for more informations
|
5
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
6
|
+
# Copyright (C) 2024 LemonTree55 <lenontree@proton.me>
|
7
|
+
# This program is published under MIT license.
|
8
|
+
|
9
|
+
module BinStruct
|
10
|
+
# Base integer class to handle binary integers
|
11
|
+
# @abstract
|
12
|
+
# @author Sylvain Daubert
|
13
|
+
# @author LemonTree55
|
14
|
+
class Int
|
15
|
+
include Fieldable
|
16
|
+
|
17
|
+
# Integer value
|
18
|
+
# @return [Integer,nil]
|
19
|
+
attr_accessor :value
|
20
|
+
# Integer endianness
|
21
|
+
# @return [:little,:big,:native,nil]
|
22
|
+
attr_accessor :endian
|
23
|
+
# Integer size, in bytes
|
24
|
+
# @return [Integer, nil]
|
25
|
+
attr_accessor :width
|
26
|
+
# Integer default value
|
27
|
+
# @return [Integer]
|
28
|
+
attr_accessor :default
|
29
|
+
|
30
|
+
# @param [Hash] options
|
31
|
+
# @option options [Integer, nil] :value
|
32
|
+
# @option options [:little,:big,nil] :endian
|
33
|
+
# @option options [Integer,nil] :width
|
34
|
+
# @option options [Integer] :default
|
35
|
+
# @author LemonTree55
|
36
|
+
def initialize(options = {})
|
37
|
+
@value = options[:value]
|
38
|
+
@endian = options[:endian]
|
39
|
+
@width = options[:width]
|
40
|
+
@default = options[:default] || 0
|
41
|
+
end
|
42
|
+
|
43
|
+
# @abstract
|
44
|
+
# Read an Int from a binary string or an integer
|
45
|
+
# @param [#to_s] str
|
46
|
+
# @return [self]
|
47
|
+
# @raise [Error] when reading +#to_s+ objects with abstract Int class.
|
48
|
+
# @author LemonTree55
|
49
|
+
def read(str)
|
50
|
+
raise Error, 'BinStruct::Int#read is abstract' unless defined? @packstr
|
51
|
+
|
52
|
+
@value = str.to_s.unpack1(@packstr[@endian])
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
# @abstract
|
57
|
+
# @return [::String]
|
58
|
+
# @raise [Error] This is an abstrat method and must be redefined
|
59
|
+
def to_s
|
60
|
+
raise Error, 'BinStruct::Int#to_s is abstract' unless defined? @packstr
|
61
|
+
|
62
|
+
[to_i].pack(@packstr[@endian])
|
63
|
+
end
|
64
|
+
|
65
|
+
# Convert Int to Integer
|
66
|
+
# @return [Integer]
|
67
|
+
def to_i
|
68
|
+
@value || @default
|
69
|
+
end
|
70
|
+
alias to_human to_i
|
71
|
+
|
72
|
+
# @param [Integer] value
|
73
|
+
# @return [self]
|
74
|
+
def from_human(value)
|
75
|
+
@value = value
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
# Convert Int to Float
|
80
|
+
# @return [Float]
|
81
|
+
def to_f
|
82
|
+
to_i.to_f
|
83
|
+
end
|
84
|
+
|
85
|
+
# Give size in bytes of self
|
86
|
+
# @return [Integer]
|
87
|
+
def sz
|
88
|
+
width
|
89
|
+
end
|
90
|
+
|
91
|
+
# Format Int type when inspecting header or packet
|
92
|
+
# @return [String]
|
93
|
+
def format_inspect
|
94
|
+
format_str % [to_i.to_s, to_i]
|
95
|
+
end
|
96
|
+
|
97
|
+
# Return the number of bits used to encode this Int
|
98
|
+
# @return [Integer]
|
99
|
+
def nbits
|
100
|
+
width * 8
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def format_str
|
106
|
+
"%-16s (0x%0#{width * 2}x)"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# One byte unsigned integer
|
111
|
+
# @author Sylvain Daubert
|
112
|
+
# @author LemonTree55
|
113
|
+
class Int8 < Int
|
114
|
+
# @param [Hash] options
|
115
|
+
# @option options [Integer,nil] :value
|
116
|
+
# @author LemonTree55
|
117
|
+
def initialize(options = {})
|
118
|
+
options[:endian] = nil
|
119
|
+
options[:width] = 1
|
120
|
+
super
|
121
|
+
@packstr = { nil => 'C' }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# One byte signed integer
|
126
|
+
# @author Sylvain Daubert
|
127
|
+
# @author LemonTree55
|
128
|
+
class SInt8 < Int
|
129
|
+
# @param [Hash] options
|
130
|
+
# @option options [Integer,nil] :value
|
131
|
+
# @author LemonTree55
|
132
|
+
def initialize(options = {})
|
133
|
+
options[:endian] = nil
|
134
|
+
options[:width] = 1
|
135
|
+
super
|
136
|
+
@packstr = { nil => 'c' }
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# 2-byte unsigned integer
|
141
|
+
# @author Sylvain Daubert
|
142
|
+
# @author LemonTree55
|
143
|
+
class Int16 < Int
|
144
|
+
# @param [Hash] options
|
145
|
+
# @option options [Integer,nil] :value
|
146
|
+
# @option [:big, :little, :native] :endian
|
147
|
+
def initialize(options = {})
|
148
|
+
opts = { value: options[:value], endian: options[:endian] || :big, width: 2 }
|
149
|
+
super(opts)
|
150
|
+
@packstr = { big: 'n', little: 'v', native: 'S' }
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# big endian 2-byte unsigned integer
|
155
|
+
# @author Sylvain Daubert
|
156
|
+
class Int16be < Int16
|
157
|
+
undef endian=
|
158
|
+
end
|
159
|
+
|
160
|
+
# little endian 2-byte unsigned integer
|
161
|
+
# @author Sylvain Daubert
|
162
|
+
# @author LemonTree55
|
163
|
+
class Int16le < Int16
|
164
|
+
# @param [Integer,nil] value
|
165
|
+
undef endian=
|
166
|
+
|
167
|
+
# @param [Hash] options
|
168
|
+
# @option options [Integer,nil] :value
|
169
|
+
def initialize(options = {})
|
170
|
+
opts = { value: options[:value], endian: :little }
|
171
|
+
super(opts)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# native endian 2-byte unsigned integer
|
176
|
+
# @author Sylvain Daubert
|
177
|
+
# @author LemonTree55
|
178
|
+
class Int16n < Int16
|
179
|
+
# @param [Integer,nil] value
|
180
|
+
undef endian=
|
181
|
+
|
182
|
+
# @param [Hash] options
|
183
|
+
# @option options [Integer,nil] :value
|
184
|
+
# @author LemonTree55
|
185
|
+
def initialize(options = {})
|
186
|
+
opts = { value: options[:value], endian: :native }
|
187
|
+
super(opts)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# 2-byte signed integer
|
192
|
+
# @author Sylvain Daubert
|
193
|
+
# @author LemonTree55
|
194
|
+
class SInt16 < Int16
|
195
|
+
# @param [Hash] options
|
196
|
+
# @option options [Integer,nil] :value
|
197
|
+
# @author LemonTree55
|
198
|
+
def initialize(options = {})
|
199
|
+
opts = { value: options[:value], endian: options[:endian] || :big }
|
200
|
+
super(opts)
|
201
|
+
@packstr = { big: 's>', little: 's<', native: 's' }
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# big endian 2-byte signed integer
|
206
|
+
# @author Sylvain Daubert
|
207
|
+
class SInt16be < SInt16
|
208
|
+
undef endian=
|
209
|
+
end
|
210
|
+
|
211
|
+
# little endian 2-byte signed integer
|
212
|
+
# @author Sylvain Daubert
|
213
|
+
# @author LemonTree55
|
214
|
+
class SInt16le < SInt16
|
215
|
+
# @param [Integer,nil] value
|
216
|
+
undef endian=
|
217
|
+
|
218
|
+
# @param [Integer, nil] value
|
219
|
+
# @author LemonTree55
|
220
|
+
def initialize(options = {})
|
221
|
+
opts = { value: options[:value], endian: :little }
|
222
|
+
super(opts)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
# native endian 2-byte signed integer
|
227
|
+
# @author Sylvain Daubert
|
228
|
+
# @author LemonTree55
|
229
|
+
class SInt16n < SInt16
|
230
|
+
# @param [Integer,nil] value
|
231
|
+
undef endian=
|
232
|
+
|
233
|
+
# @param [Integer, nil] value
|
234
|
+
# @author LemonTree55
|
235
|
+
def initialize(options = {})
|
236
|
+
opts = { value: options[:value], endian: :native }
|
237
|
+
super(opts)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
# 3-byte unsigned integer
|
242
|
+
# @author LemonTree55
|
243
|
+
class Int24 < Int
|
244
|
+
# @param [Hash] options
|
245
|
+
# @option options [Integer,nil] :value
|
246
|
+
# @option options [:big, :little, :native] :endian
|
247
|
+
def initialize(options = {})
|
248
|
+
opts = options.slice(:value, :endian)
|
249
|
+
opts[:endian] ||= :big
|
250
|
+
opts[:width] = 3
|
251
|
+
|
252
|
+
if opts[:endian] == :native
|
253
|
+
opts[:endian] = if [1].pack('S').unpack1('n') == 1
|
254
|
+
:big
|
255
|
+
else
|
256
|
+
:little
|
257
|
+
end
|
258
|
+
end
|
259
|
+
super(opts)
|
260
|
+
end
|
261
|
+
|
262
|
+
# Read an 3-byte Int from a binary string
|
263
|
+
# @param [String] str
|
264
|
+
# @return [self]
|
265
|
+
def read(value)
|
266
|
+
return self if value.nil?
|
267
|
+
|
268
|
+
up8 = down16 = 0
|
269
|
+
if @endian == :big
|
270
|
+
up8, down16 = value.to_s.unpack('Cn')
|
271
|
+
else
|
272
|
+
down16, up8 = value.to_s.unpack('vC')
|
273
|
+
end
|
274
|
+
@value = (up8 << 16) | down16
|
275
|
+
self
|
276
|
+
end
|
277
|
+
|
278
|
+
# @author Sylvain Daubert
|
279
|
+
# @return [::String]
|
280
|
+
def to_s
|
281
|
+
up8 = to_i >> 16
|
282
|
+
down16 = to_i & 0xffff
|
283
|
+
if @endian == :big
|
284
|
+
[up8, down16].pack('Cn')
|
285
|
+
else
|
286
|
+
[down16, up8].pack('vC')
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
# big endian 3-byte unsigned integer
|
292
|
+
# @author Sylvain Daubert
|
293
|
+
class Int24be < Int24
|
294
|
+
undef endian=
|
295
|
+
end
|
296
|
+
|
297
|
+
# little endian 3-byte unsigned integer
|
298
|
+
# @author LemonTree55
|
299
|
+
class Int24le < Int24
|
300
|
+
# @param [Integer,nil] value
|
301
|
+
undef endian=
|
302
|
+
|
303
|
+
# @param [Hash] options
|
304
|
+
# @option options [Integer] :value
|
305
|
+
def initialize(options = {})
|
306
|
+
opts = { value: options[:value], endian: :little }
|
307
|
+
super(opts)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
# native endian 3-byte unsigned integer
|
312
|
+
# @author LemonTree55
|
313
|
+
class Int24n < Int24
|
314
|
+
# @param [Integer,nil] value
|
315
|
+
undef endian=
|
316
|
+
|
317
|
+
# @param [Hash] options
|
318
|
+
# @option options [Integer] :value
|
319
|
+
def initialize(options = {})
|
320
|
+
opts = { value: options[:value], endian: :little }
|
321
|
+
super(opts)
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
# 4-byte unsigned integer
|
326
|
+
# @author LemonTree55
|
327
|
+
class Int32 < Int
|
328
|
+
# @param [Hash] options
|
329
|
+
# @option options [Integer,nil] :value
|
330
|
+
# @option [:big, :little, :native] :endian
|
331
|
+
def initialize(options = {})
|
332
|
+
opts = { value: options[:value], endian: options[:endian] || :big, width: 4 }
|
333
|
+
super(opts)
|
334
|
+
@packstr = { big: 'N', little: 'V', native: 'L' }
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
# big endian 4-byte unsigned integer
|
339
|
+
# @author Sylvain Daubert
|
340
|
+
class Int32be < Int32
|
341
|
+
undef endian=
|
342
|
+
end
|
343
|
+
|
344
|
+
# little endian 4-byte unsigned integer
|
345
|
+
# @author LemonTree55
|
346
|
+
class Int32le < Int32
|
347
|
+
# @param [Integer,nil] value
|
348
|
+
undef endian=
|
349
|
+
|
350
|
+
# @param [Hash] options
|
351
|
+
# @option options [Integer,nil] :value
|
352
|
+
def initialize(options = {})
|
353
|
+
opts = { value: options[:value], endian: :little }
|
354
|
+
super(opts)
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
# native endian 4-byte unsigned integer
|
359
|
+
# @author LemonTree55
|
360
|
+
class Int32n < Int32
|
361
|
+
# @param [Integer,nil] value
|
362
|
+
undef endian=
|
363
|
+
|
364
|
+
# @param [Hash] options
|
365
|
+
# @option options [Integer,nil] :value
|
366
|
+
def initialize(options = {})
|
367
|
+
opts = { value: options[:value], endian: :native }
|
368
|
+
super(opts)
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
# 4-byte unsigned integer
|
373
|
+
# @author LemonTree55
|
374
|
+
class SInt32 < Int32
|
375
|
+
# @param [Hash] options
|
376
|
+
# @option options [Integer] :value
|
377
|
+
# @option options [:big, :little, :native] :endian
|
378
|
+
def initialize(options = {})
|
379
|
+
opts = { value: options[:value], endian: options[:endian] || :big }
|
380
|
+
super(opts)
|
381
|
+
@packstr = { big: 'l>', little: 'l<', native: 'l' }
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
# big endian 4-byte unsigned integer
|
386
|
+
# @author Sylvain Daubert
|
387
|
+
class SInt32be < SInt32
|
388
|
+
undef endian=
|
389
|
+
end
|
390
|
+
|
391
|
+
# little endian 4-byte unsigned integer
|
392
|
+
# @author LemonTree55
|
393
|
+
class SInt32le < SInt32
|
394
|
+
# @param [Integer,nil] value
|
395
|
+
undef endian=
|
396
|
+
|
397
|
+
# @param [Hash] options
|
398
|
+
# @option options [Integer] :value
|
399
|
+
def initialize(options = {})
|
400
|
+
opts = { value: options[:value], endian: :little }
|
401
|
+
super(opts)
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
# native endian 4-byte unsigned integer
|
406
|
+
# @author LemonTree55
|
407
|
+
class SInt32n < SInt32
|
408
|
+
# @param [Integer,nil] value
|
409
|
+
undef endian=
|
410
|
+
|
411
|
+
# @param [Hash] options
|
412
|
+
# @option options [Integer] :value
|
413
|
+
def initialize(options = {})
|
414
|
+
opts = { value: options[:value], endian: :native }
|
415
|
+
super(opts)
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
# 8-byte unsigned integer
|
420
|
+
# @author LemonTree55
|
421
|
+
class Int64 < Int
|
422
|
+
# @param [Hash] options
|
423
|
+
# @option options [Integer] :value
|
424
|
+
# @option options [:big, :little, :native] :endian
|
425
|
+
def initialize(options = {})
|
426
|
+
opts = options.slice(:value, :endian)
|
427
|
+
opts[:endian] ||= :big
|
428
|
+
opts[:width] = 8
|
429
|
+
super(opts)
|
430
|
+
@packstr = { big: 'Q>', little: 'Q<', native: 'Q' }
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
# big endian 8-byte unsigned integer
|
435
|
+
# @author Sylvain Daubert
|
436
|
+
class Int64be < Int64
|
437
|
+
undef endian=
|
438
|
+
end
|
439
|
+
|
440
|
+
# little endian 8-byte unsigned integer
|
441
|
+
# @author LemonTree55
|
442
|
+
class Int64le < Int64
|
443
|
+
# @param [Integer,nil] value
|
444
|
+
undef endian=
|
445
|
+
|
446
|
+
# @param [Hash] options
|
447
|
+
# @option options [Integer] :value
|
448
|
+
def initialize(options = {})
|
449
|
+
opts = { value: options[:value], endian: :little }
|
450
|
+
super(opts)
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
# native endian 8-byte unsigned integer
|
455
|
+
# @author LemonTree55
|
456
|
+
class Int64n < Int64
|
457
|
+
# @param [Integer,nil] value
|
458
|
+
undef endian=
|
459
|
+
|
460
|
+
# @param [Hash] options
|
461
|
+
# @option options [Integer] :value
|
462
|
+
def initialize(options = {})
|
463
|
+
opts = { value: options[:value], endian: :native }
|
464
|
+
super(opts)
|
465
|
+
end
|
466
|
+
end
|
467
|
+
|
468
|
+
# 8-byte unsigned integer
|
469
|
+
# @author LemonTree55
|
470
|
+
class SInt64 < Int64
|
471
|
+
# @param [Hash] options
|
472
|
+
# @option options [Integer] :value
|
473
|
+
# @option options [:big, :little, :native] :endian
|
474
|
+
def initialize(options = {})
|
475
|
+
opts = options.slice(:value, :endian)
|
476
|
+
super(opts)
|
477
|
+
@packstr = { big: 'q>', little: 'q<', native: 'q' }
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
# big endian 8-byte unsigned integer
|
482
|
+
# @author Sylvain Daubert
|
483
|
+
class SInt64be < SInt64
|
484
|
+
undef endian=
|
485
|
+
end
|
486
|
+
|
487
|
+
# little endian 8-byte unsigned integer
|
488
|
+
# @author LemonTree55
|
489
|
+
class SInt64le < SInt64
|
490
|
+
# @param [Integer,nil] value
|
491
|
+
undef endian=
|
492
|
+
|
493
|
+
# @param [Hash] options
|
494
|
+
# @option options [Integer] :value
|
495
|
+
def initialize(options = {})
|
496
|
+
opts = { value: options[:value], endian: :little }
|
497
|
+
super(opts)
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
# native endian 8-byte unsigned integer
|
502
|
+
# @author LemonTree55
|
503
|
+
class SInt64n < SInt64
|
504
|
+
# @param [Integer,nil] value
|
505
|
+
undef endian=
|
506
|
+
|
507
|
+
# @param [Hash] options
|
508
|
+
# @option options [Integer] :value
|
509
|
+
def initialize(options = {})
|
510
|
+
opts = { value: options[:value], endian: :native }
|
511
|
+
super(opts)
|
512
|
+
end
|
513
|
+
end
|
514
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This file is part of BinStruct
|
4
|
+
# see https://github.com/lemontree55/bin_struct for more informations
|
5
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
6
|
+
# Copyright (C) 2024 LemonTree55 <lenontree@proton.me>
|
7
|
+
# This program is published under MIT license.
|
8
|
+
|
9
|
+
module BinStruct
|
10
|
+
# Provides a class for creating strings preceeded by their length as a {Int}.
|
11
|
+
# By default, a null string will have one byte length (length byte set to 0).
|
12
|
+
# @author Sylvain Daubert
|
13
|
+
class IntString
|
14
|
+
include Fieldable
|
15
|
+
|
16
|
+
# internal string
|
17
|
+
# @return [String]
|
18
|
+
attr_reader :string
|
19
|
+
|
20
|
+
# @param [Hash] options
|
21
|
+
# @option options [Class] :length_type should be a {Int} subclass. Default to {Int8}.
|
22
|
+
# @option options [::String] :string String value. Default to +''+
|
23
|
+
def initialize(options = {})
|
24
|
+
@string = BinStruct::String.new.read(options[:string] || '')
|
25
|
+
@length = (options[:length_type] || Int8).new
|
26
|
+
calc_length
|
27
|
+
end
|
28
|
+
|
29
|
+
# @param [::String] str
|
30
|
+
# @return [IntString] self
|
31
|
+
def read(str)
|
32
|
+
unless str[0, @length.width].size == @length.width
|
33
|
+
raise Error,
|
34
|
+
"String too short for type #{@length.class.to_s.gsub(/.*::/, '')}"
|
35
|
+
end
|
36
|
+
@length.read str[0, @length.width]
|
37
|
+
@string.read str[@length.width, @length.to_i]
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
# @param [Integer] len
|
42
|
+
# @return [Integer]
|
43
|
+
def length=(len)
|
44
|
+
@length.from_human(len)
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [Integer]
|
48
|
+
def length
|
49
|
+
@length.to_i
|
50
|
+
end
|
51
|
+
|
52
|
+
# @param [#to_s] str
|
53
|
+
# @return [String]
|
54
|
+
def string=(str)
|
55
|
+
@length.value = str.to_s.size
|
56
|
+
@string = str.to_s
|
57
|
+
end
|
58
|
+
|
59
|
+
# Get binary string
|
60
|
+
# @return [::String]
|
61
|
+
def to_s
|
62
|
+
@length.to_s << @string.to_s
|
63
|
+
end
|
64
|
+
|
65
|
+
# Set from a human readable string
|
66
|
+
# @param [String] str
|
67
|
+
# @return [self]
|
68
|
+
def from_human(str)
|
69
|
+
@string.read str
|
70
|
+
calc_length
|
71
|
+
self
|
72
|
+
end
|
73
|
+
|
74
|
+
# Get human readable string
|
75
|
+
# @return [::String]
|
76
|
+
# @since 2.2.0
|
77
|
+
def to_human
|
78
|
+
@string
|
79
|
+
end
|
80
|
+
|
81
|
+
# Set length from internal string length
|
82
|
+
# @return [Integer]
|
83
|
+
def calc_length
|
84
|
+
@length.read @string.length
|
85
|
+
end
|
86
|
+
|
87
|
+
# Give binary string length (including +length+ field)
|
88
|
+
# @return [Integer]
|
89
|
+
def sz
|
90
|
+
to_s.size
|
91
|
+
end
|
92
|
+
|
93
|
+
# Say if IntString is empty
|
94
|
+
# @return [Boolean]
|
95
|
+
def empty?
|
96
|
+
length.zero?
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This file is part of BinStruct
|
4
|
+
# see https://github.com/lemontree55/bin_struct for more informations
|
5
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
6
|
+
# Copyright (C) 2024 LemonTree55 <lenontree@proton.me>
|
7
|
+
# This program is published under MIT license.
|
8
|
+
|
9
|
+
module BinStruct
|
10
|
+
# This module is a mixin adding +length_from+ capacity to a type.
|
11
|
+
# +length_from+ capacity is the capacity, for a type, to gets its
|
12
|
+
# length from another object.
|
13
|
+
# @author Sylvain Daubert
|
14
|
+
# @since 3.0.0
|
15
|
+
module LengthFrom
|
16
|
+
# Max value returned by {#sz_to_read}.
|
17
|
+
MAX_SZ_TO_READ = 65_535
|
18
|
+
|
19
|
+
# Initialize +length from+ capacity.
|
20
|
+
# Should be call by extensed object's initialize.
|
21
|
+
# @param [Hash] options
|
22
|
+
# @option options [Types::Int,Proc] :length_from object or proc from which
|
23
|
+
# takes length when reading
|
24
|
+
# @return [void]
|
25
|
+
def initialize_length_from(options)
|
26
|
+
@length_from = options[:length_from]
|
27
|
+
end
|
28
|
+
|
29
|
+
# Return a substring from +str+ of length given in another object.
|
30
|
+
# @param [#to_s] str
|
31
|
+
# @return [String]
|
32
|
+
def read_with_length_from(str)
|
33
|
+
s = BinStruct.force_binary(str.to_s)
|
34
|
+
s[0, sz_to_read]
|
35
|
+
end
|
36
|
+
|
37
|
+
# Size to read, from length_from
|
38
|
+
# @return [Integer]
|
39
|
+
def sz_to_read
|
40
|
+
len = case @length_from
|
41
|
+
when Int
|
42
|
+
@length_from.to_i
|
43
|
+
when Proc
|
44
|
+
@length_from.call
|
45
|
+
else
|
46
|
+
MAX_SZ_TO_READ
|
47
|
+
end
|
48
|
+
[0, len].max
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This file is part of BinStruct
|
4
|
+
# see https://github.com/lemontree55/bin_struct for more informations
|
5
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
6
|
+
# Copyright (C) 2024 LemonTree55 <lenontree@proton.me>
|
7
|
+
# This program is published under MIT license.
|
8
|
+
|
9
|
+
module BinStruct
|
10
|
+
# OUI type, defined as a set of 3 bytes
|
11
|
+
# oui = OUI.new
|
12
|
+
# oui.from_human('00:01:02')
|
13
|
+
# oui.to_human # => "00:01:02"
|
14
|
+
# @author Sylvain Daubert
|
15
|
+
class OUI < Fields
|
16
|
+
include Fieldable
|
17
|
+
|
18
|
+
# @attribute b2
|
19
|
+
# @return [Integer] left-most byte
|
20
|
+
define_field :b2, Int8
|
21
|
+
# @attribute b1
|
22
|
+
# @return [Integer] center byte
|
23
|
+
define_field :b1, Int8
|
24
|
+
# @attribute b0
|
25
|
+
# @return [Integer] right-most byte
|
26
|
+
define_field :b0, Int8
|
27
|
+
|
28
|
+
# Read a human-readable string to populate object
|
29
|
+
# @param [String] str
|
30
|
+
# @return [OUI] self
|
31
|
+
def from_human(str)
|
32
|
+
return self if str.nil?
|
33
|
+
|
34
|
+
bytes = str.split(':')
|
35
|
+
raise ArgumentError, 'not a OUI' unless bytes.size == 3
|
36
|
+
|
37
|
+
self[:b2].from_human(bytes[0].to_i(16))
|
38
|
+
self[:b1].from_human(bytes[1].to_i(16))
|
39
|
+
self[:b0].from_human(bytes[2].to_i(16))
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
# Get OUI in human readable form (colon-separated bytes)
|
44
|
+
# @return [String]
|
45
|
+
def to_human
|
46
|
+
fields.map { |m| '%02x' % self[m] }.join(':')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|