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,200 @@
|
|
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
|
+
# @abstract Base enum class to handle binary integers with limited
|
11
|
+
# authorized values
|
12
|
+
# An {Enum} type is used to handle an {Int} field with limited
|
13
|
+
# and named values.
|
14
|
+
#
|
15
|
+
# == Simple example
|
16
|
+
# enum = Int8Enum.new('low' => 0, 'medium' => 1, 'high' => 2})
|
17
|
+
# In this example, +enum+ is a 8-bit field which may take one
|
18
|
+
# among three values: +low+, +medium+ or +high+:
|
19
|
+
# enum.value = 'high'
|
20
|
+
# enum.value # => 2
|
21
|
+
# enum.value = 1
|
22
|
+
# enum.value # => 1
|
23
|
+
# enum.to_human # => "medium"
|
24
|
+
# Setting an unknown value will raise an exception:
|
25
|
+
# enum.value = 4 # => raise!
|
26
|
+
# enum.value = 'unknown' # => raise!
|
27
|
+
# But {#read} will not raise when reading an outbound value. This
|
28
|
+
# to enable decoding (or forging) of bad packets.
|
29
|
+
# @author Sylvain Daubert
|
30
|
+
class Enum < Int
|
31
|
+
# @return [Hash]
|
32
|
+
attr_reader :enum
|
33
|
+
|
34
|
+
# @param [Hash] options
|
35
|
+
# @see Int#initialize
|
36
|
+
# @option options [Hash] enum enumerated values. Default value is taken from
|
37
|
+
# first element unless given. This option is mandatory.
|
38
|
+
# @option options [Integer,String] :default
|
39
|
+
# @author LemonTree55
|
40
|
+
def initialize(options = {})
|
41
|
+
enum = options[:enum]
|
42
|
+
raise TypeError, 'enum must be defined as a Hash' unless enum.is_a?(Hash)
|
43
|
+
|
44
|
+
options[:default] ||= enum[enum.keys.first]
|
45
|
+
super
|
46
|
+
@enum = enum
|
47
|
+
end
|
48
|
+
|
49
|
+
# Setter for value attribute
|
50
|
+
# @param [#to_i, String,nil] value value as an Integer or as a String
|
51
|
+
# from enumration
|
52
|
+
# @return [Integer]
|
53
|
+
# @raise [ArgumentError] String value is unknown
|
54
|
+
def value=(value)
|
55
|
+
ival = case value
|
56
|
+
when NilClass
|
57
|
+
nil
|
58
|
+
when ::String
|
59
|
+
raise ArgumentError, "#{value.inspect} not in enumeration" unless @enum.key?(value)
|
60
|
+
|
61
|
+
@enum[value]
|
62
|
+
else
|
63
|
+
value.to_i
|
64
|
+
end
|
65
|
+
@value = ival
|
66
|
+
end
|
67
|
+
|
68
|
+
# To handle human API: set value from a String
|
69
|
+
alias from_human value=
|
70
|
+
|
71
|
+
# Get human readable value (enum name)
|
72
|
+
# @return [String]
|
73
|
+
def to_human
|
74
|
+
@enum.key(to_i) || "<unknown:#{@value}>"
|
75
|
+
end
|
76
|
+
|
77
|
+
def format_inspect
|
78
|
+
format_str % [to_human, to_i]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Enumeration on one byte. See {Enum}.
|
83
|
+
# @author LemonTree55
|
84
|
+
class Int8Enum < Enum
|
85
|
+
# @param [Hash] options
|
86
|
+
# @option options [Hash] :enum
|
87
|
+
# @option options [Integer,::String] :value
|
88
|
+
# @option options [Integer,::String] :default
|
89
|
+
def initialize(options = {})
|
90
|
+
opts = options.slice(:enum, :value, :default)
|
91
|
+
opts[:width] = 1
|
92
|
+
opts[:endian] = nil
|
93
|
+
super(opts)
|
94
|
+
@packstr = { nil => 'C' }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Enumeration on 2-byte integer. See {Enum}.
|
99
|
+
# @author LemonTree55
|
100
|
+
class Int16Enum < Enum
|
101
|
+
# @param [Hash] options
|
102
|
+
# @option options [Hash] :enum
|
103
|
+
# @option options [:big,:little] :endian
|
104
|
+
# @option options [Integer,::String] :value
|
105
|
+
# @option options [Integer,::String] :default
|
106
|
+
def initialize(options = {})
|
107
|
+
opts = options.slice(:enum, :endian, :default, :value)
|
108
|
+
opts[:endian] ||= :big
|
109
|
+
opts[:width] = 2
|
110
|
+
super(opts)
|
111
|
+
@packstr = { big: 'n', little: 'v' }
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Enumeration on big endian 2-byte integer. See {Enum}.
|
116
|
+
# @author Sylvain Daubert
|
117
|
+
class Int16beEnum < Int16Enum
|
118
|
+
undef endian=
|
119
|
+
|
120
|
+
# @param [Hash] options
|
121
|
+
# @option options [Hash] :enum
|
122
|
+
# @option options [Integer,::String] :value
|
123
|
+
# @option options [Integer,::String] :default
|
124
|
+
# @author LemonTree55
|
125
|
+
def initialize(options = {})
|
126
|
+
opts = options.slice(:enum, :default, :value)
|
127
|
+
opts[:endian] = :big
|
128
|
+
super(opts)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Enumeration on big endian 2-byte integer. See {Enum}.
|
133
|
+
# @author Sylvain Daubert
|
134
|
+
class Int16leEnum < Int16Enum
|
135
|
+
undef endian=
|
136
|
+
|
137
|
+
# @param [Hash] options
|
138
|
+
# @option options [Hash] :enum
|
139
|
+
# @option options [Integer,::String] :value
|
140
|
+
# @option options [Integer,::String] :default
|
141
|
+
# @author LemonTree55
|
142
|
+
def initialize(options = {})
|
143
|
+
opts = options.slice(:enum, :default, :value)
|
144
|
+
opts[:endian] = :little
|
145
|
+
super(opts)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# Enumeration on 4-byte integer. See {Enum}.
|
150
|
+
# @author LemonTree55
|
151
|
+
class Int32Enum < Enum
|
152
|
+
# @param [Hash] options
|
153
|
+
# @option options [Hash] :enum
|
154
|
+
# @option options [:big,:little] :endian
|
155
|
+
# @option options [Integer,::String] :value
|
156
|
+
# @option options [Integer,::String] :default
|
157
|
+
def initialize(options = {})
|
158
|
+
opts = options.slice(:enum, :endian, :default, :value)
|
159
|
+
opts[:endian] ||= :big
|
160
|
+
opts[:width] = 4
|
161
|
+
super(opts)
|
162
|
+
@packstr = { big: 'N', little: 'V' }
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# Enumeration on big endian 4-byte integer. See {Enum}.
|
167
|
+
# @author Sylvain Daubert
|
168
|
+
class Int32beEnum < Int32Enum
|
169
|
+
undef endian=
|
170
|
+
|
171
|
+
# @param [Hash] options
|
172
|
+
# @option options [Hash] :enum
|
173
|
+
# @option options [Integer,::String] :value
|
174
|
+
# @option options [Integer,::String] :default
|
175
|
+
# @author LemonTree55
|
176
|
+
def initialize(options = {})
|
177
|
+
opts = options.slice(:enum, :default, :value)
|
178
|
+
opts[:endian] = :big
|
179
|
+
super(opts)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# Enumeration on big endian 4-byte integer. See {Enum}.
|
184
|
+
# @author Sylvain Daubert
|
185
|
+
# @since 2.1.3
|
186
|
+
class Int32leEnum < Int32Enum
|
187
|
+
undef endian=
|
188
|
+
|
189
|
+
# @param [Hash] options
|
190
|
+
# @option options [Hash] :enum
|
191
|
+
# @option options [Integer,::String] :value
|
192
|
+
# @option options [Integer,::String] :default
|
193
|
+
# @author LemonTree55
|
194
|
+
def initialize(options = {})
|
195
|
+
opts = options.slice(:enum, :default, :value)
|
196
|
+
opts[:endian] = :little
|
197
|
+
super(opts)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
@@ -0,0 +1,64 @@
|
|
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
|
+
# Mixin to define minimal API for a class to be embbeded as a field in
|
11
|
+
# {Fields} type.
|
12
|
+
#
|
13
|
+
# == Optional methods
|
14
|
+
# These methods may, optionally, be defined by fieldable types:
|
15
|
+
# * +from_human+ to load data from a human-readable string.
|
16
|
+
# @author Sylvain Daubert
|
17
|
+
# @since 3.1.6
|
18
|
+
module Fieldable
|
19
|
+
# Get type name
|
20
|
+
# @return [String]
|
21
|
+
def type_name
|
22
|
+
self.class.to_s.split('::').last
|
23
|
+
end
|
24
|
+
|
25
|
+
# rubocop:disable Lint/UselessMethodDefinition
|
26
|
+
# These methods are defined for documentation.
|
27
|
+
|
28
|
+
# Populate object from a binary string
|
29
|
+
# @param [String] str
|
30
|
+
# @return [Fields] self
|
31
|
+
# @abstract subclass should overload it.
|
32
|
+
def read(str)
|
33
|
+
super
|
34
|
+
end
|
35
|
+
|
36
|
+
# Return object as a binary string
|
37
|
+
# @return [String]
|
38
|
+
# @abstract subclass should overload it.
|
39
|
+
def to_s
|
40
|
+
super
|
41
|
+
end
|
42
|
+
|
43
|
+
# Size of object as binary string
|
44
|
+
# @return [Integer]
|
45
|
+
def sz
|
46
|
+
to_s.size
|
47
|
+
end
|
48
|
+
|
49
|
+
# Return a human-readbale string
|
50
|
+
# @return [String]
|
51
|
+
# @abstract subclass should overload it.
|
52
|
+
def to_human
|
53
|
+
super
|
54
|
+
end
|
55
|
+
|
56
|
+
# rubocop:enable Lint/UselessMethodDefinition
|
57
|
+
|
58
|
+
# Format object when inspecting a {Fields} object
|
59
|
+
# @return [String]
|
60
|
+
def format_inspect
|
61
|
+
to_human
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|