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.
@@ -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