packetgen 3.3.3 → 4.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.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +38 -22
  3. data/lib/packetgen/capture.rb +2 -2
  4. data/lib/packetgen/config.rb +0 -1
  5. data/lib/packetgen/deprecation.rb +14 -8
  6. data/lib/packetgen/header/arp.rb +17 -18
  7. data/lib/packetgen/header/asn1_base.rb +2 -1
  8. data/lib/packetgen/header/base.rb +42 -40
  9. data/lib/packetgen/header/bootp.rb +35 -37
  10. data/lib/packetgen/header/dhcp/option.rb +21 -21
  11. data/lib/packetgen/header/dhcp/options.rb +3 -3
  12. data/lib/packetgen/header/dhcp.rb +8 -9
  13. data/lib/packetgen/header/dhcpv6/duid.rb +16 -16
  14. data/lib/packetgen/header/dhcpv6/option.rb +83 -61
  15. data/lib/packetgen/header/dhcpv6/options.rb +4 -4
  16. data/lib/packetgen/header/dhcpv6/relay.rb +6 -5
  17. data/lib/packetgen/header/dhcpv6.rb +17 -18
  18. data/lib/packetgen/header/dns/name.rb +21 -16
  19. data/lib/packetgen/header/dns/opt.rb +5 -2
  20. data/lib/packetgen/header/dns/option.rb +14 -14
  21. data/lib/packetgen/header/dns/qdsection.rb +3 -3
  22. data/lib/packetgen/header/dns/question.rb +7 -8
  23. data/lib/packetgen/header/dns/rr.rb +56 -43
  24. data/lib/packetgen/header/dns/rrsection.rb +6 -6
  25. data/lib/packetgen/header/dns.rb +103 -90
  26. data/lib/packetgen/header/dot11/control.rb +12 -12
  27. data/lib/packetgen/header/dot11/data.rb +25 -24
  28. data/lib/packetgen/header/dot11/element.rb +4 -4
  29. data/lib/packetgen/header/dot11/management.rb +21 -18
  30. data/lib/packetgen/header/dot11/sub_mngt.rb +40 -53
  31. data/lib/packetgen/header/dot11.rb +117 -122
  32. data/lib/packetgen/header/dot1q.rb +12 -13
  33. data/lib/packetgen/header/dot1x.rb +13 -13
  34. data/lib/packetgen/header/eap/fast.rb +4 -4
  35. data/lib/packetgen/header/eap/md5.rb +16 -8
  36. data/lib/packetgen/header/eap/tls.rb +18 -19
  37. data/lib/packetgen/header/eap/ttls.rb +22 -21
  38. data/lib/packetgen/header/eap.rb +73 -48
  39. data/lib/packetgen/header/eth.rb +41 -27
  40. data/lib/packetgen/header/gre.rb +33 -11
  41. data/lib/packetgen/header/http/headers.rb +7 -6
  42. data/lib/packetgen/header/http/request.rb +38 -29
  43. data/lib/packetgen/header/http/response.rb +35 -27
  44. data/lib/packetgen/header/http/verbs.rb +1 -3
  45. data/lib/packetgen/header/icmp.rb +14 -14
  46. data/lib/packetgen/header/icmpv6.rb +10 -9
  47. data/lib/packetgen/header/igmp.rb +26 -15
  48. data/lib/packetgen/header/igmpv3/group_record.rb +18 -13
  49. data/lib/packetgen/header/igmpv3/mq.rb +16 -18
  50. data/lib/packetgen/header/igmpv3/mr.rb +5 -5
  51. data/lib/packetgen/header/igmpv3.rb +12 -11
  52. data/lib/packetgen/header/ip/addr.rb +19 -15
  53. data/lib/packetgen/header/ip/option.rb +47 -36
  54. data/lib/packetgen/header/ip/options.rb +1 -1
  55. data/lib/packetgen/header/ip.rb +77 -95
  56. data/lib/packetgen/header/ipv6/addr.rb +28 -27
  57. data/lib/packetgen/header/ipv6/extension.rb +13 -11
  58. data/lib/packetgen/header/ipv6/hop_by_hop.rb +32 -13
  59. data/lib/packetgen/header/ipv6.rb +42 -35
  60. data/lib/packetgen/header/llc.rb +28 -21
  61. data/lib/packetgen/header/mdns.rb +10 -3
  62. data/lib/packetgen/header/mld.rb +15 -13
  63. data/lib/packetgen/header/mldv2/mcast_address_record.rb +17 -12
  64. data/lib/packetgen/header/mldv2/mlq.rb +22 -24
  65. data/lib/packetgen/header/mldv2/mlr.rb +8 -8
  66. data/lib/packetgen/header/mldv2.rb +1 -1
  67. data/lib/packetgen/header/ospfv2/db_description.rb +17 -18
  68. data/lib/packetgen/header/ospfv2/hello.rb +18 -17
  69. data/lib/packetgen/header/ospfv2/ls_ack.rb +6 -7
  70. data/lib/packetgen/header/ospfv2/ls_request.rb +14 -13
  71. data/lib/packetgen/header/ospfv2/ls_update.rb +9 -9
  72. data/lib/packetgen/header/ospfv2/lsa.rb +79 -60
  73. data/lib/packetgen/header/ospfv2/lsa_header.rb +12 -11
  74. data/lib/packetgen/header/ospfv2.rb +49 -46
  75. data/lib/packetgen/header/ospfv3/db_description.rb +20 -22
  76. data/lib/packetgen/header/ospfv3/hello.rb +17 -16
  77. data/lib/packetgen/header/ospfv3/ipv6_prefix.rb +22 -20
  78. data/lib/packetgen/header/ospfv3/ls_ack.rb +7 -8
  79. data/lib/packetgen/header/ospfv3/ls_request.rb +18 -18
  80. data/lib/packetgen/header/ospfv3/ls_update.rb +10 -10
  81. data/lib/packetgen/header/ospfv3/lsa.rb +62 -51
  82. data/lib/packetgen/header/ospfv3/lsa_header.rb +12 -11
  83. data/lib/packetgen/header/ospfv3.rb +54 -52
  84. data/lib/packetgen/header/sctp/chunk.rb +80 -56
  85. data/lib/packetgen/header/sctp/error.rb +174 -202
  86. data/lib/packetgen/header/sctp/padded32.rb +3 -3
  87. data/lib/packetgen/header/sctp/parameter.rb +89 -136
  88. data/lib/packetgen/header/sctp.rb +19 -8
  89. data/lib/packetgen/header/snmp.rb +108 -7
  90. data/lib/packetgen/header/tcp/option.rb +52 -39
  91. data/lib/packetgen/header/tcp/options.rb +13 -5
  92. data/lib/packetgen/header/tcp.rb +83 -65
  93. data/lib/packetgen/header/tftp.rb +31 -25
  94. data/lib/packetgen/header/udp.rb +21 -19
  95. data/lib/packetgen/header.rb +23 -18
  96. data/lib/packetgen/headerable.rb +21 -5
  97. data/lib/packetgen/inspect.rb +3 -8
  98. data/lib/packetgen/packet.rb +146 -71
  99. data/lib/packetgen/pcap.rb +15 -4
  100. data/lib/packetgen/pcapng/block.rb +20 -18
  101. data/lib/packetgen/pcapng/epb.rb +13 -15
  102. data/lib/packetgen/pcapng/file.rb +44 -111
  103. data/lib/packetgen/pcapng/idb.rb +11 -12
  104. data/lib/packetgen/pcapng/shb.rb +15 -16
  105. data/lib/packetgen/pcapng/spb.rb +9 -11
  106. data/lib/packetgen/pcapng/unknown_block.rb +6 -17
  107. data/lib/packetgen/pcapng.rb +6 -4
  108. data/lib/packetgen/pcaprub_wrapper.rb +17 -1
  109. data/lib/packetgen/proto.rb +5 -1
  110. data/lib/packetgen/unknown_packet.rb +5 -5
  111. data/lib/packetgen/utils/arp_spoofer.rb +18 -19
  112. data/lib/packetgen/utils.rb +4 -3
  113. data/lib/packetgen/version.rb +1 -1
  114. data/lib/packetgen.rb +12 -5
  115. metadata +29 -38
  116. data/lib/packetgen/types/abstract_tlv.rb +0 -278
  117. data/lib/packetgen/types/array.rb +0 -287
  118. data/lib/packetgen/types/cstring.rb +0 -109
  119. data/lib/packetgen/types/enum.rb +0 -171
  120. data/lib/packetgen/types/fieldable.rb +0 -66
  121. data/lib/packetgen/types/fields.rb +0 -622
  122. data/lib/packetgen/types/int.rb +0 -473
  123. data/lib/packetgen/types/int_string.rb +0 -102
  124. data/lib/packetgen/types/length_from.rb +0 -54
  125. data/lib/packetgen/types/oui.rb +0 -52
  126. data/lib/packetgen/types/string.rb +0 -97
  127. data/lib/packetgen/types/tlv.rb +0 -161
  128. data/lib/packetgen/types.rb +0 -26
@@ -1,278 +0,0 @@
1
- # coding: utf-8
2
- # frozen_string_literal: true
3
-
4
- # This file is part of PacketGen
5
- # See https://github.com/lemontree55/packetgen for more informations
6
- # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
7
- # Copyright (C) 2024 LemonTree55 <lenontree@proton.me>
8
- # This program is published under MIT license.
9
-
10
- module PacketGen
11
- module Types
12
- # This class is an abstract class to define type-length-value data.
13
- #
14
- # This class supersedes {TLV} class, which is not well defined on some corner
15
- # cases.
16
- #
17
- # ===Usage
18
- # To simply define a new TLV class, do:
19
- # MyTLV = PacketGen::Types::AbstractTLV.create
20
- # MyTLV.define_type_enum 'one' => 1, 'two' => 2
21
- # This will define a new +MyTLV+ class, subclass of {Fields}. This class will
22
- # define 3 fields:
23
- # * +#type+, as a {Int8Enum} by default,
24
- # * +#length+, as a {Int8} by default,
25
- # * and +#value+, as a {String} by default.
26
- # +.define_type_enum+ is, here, necessary to define enum hash to be used
27
- # for +#type+ accessor, as this one is defined as an {Enum}.
28
- #
29
- # This class may then be used as older {TLV} class:
30
- # tlv = MyTLV.new(type: 1, value: 'abcd') # automagically set #length from value
31
- # tlv.type #=> 1
32
- # tlv.human_type #=> 'one'
33
- # tlv.length #=> 4
34
- # tlv.value #=> "abcd"
35
- #
36
- # ===Advanced usage
37
- # Each field's type may be changed at generating TLV class:
38
- # MyTLV = PacketGen::Types::AbstractTLV.create(type_class: PacketGen::Types::Int16,
39
- # length_class: PacketGen::Types::Int16,
40
- # value_class: PacketGen::Header::IP::Addr)
41
- # tlv = MyTLV.new(type: 1, value: '1.2.3.4')
42
- # tlv.type #=> 1
43
- # tlv.length #=> 4
44
- # tlv.value #=> '1.2.3.4'
45
- # tlv.to_s #=> "\x00\x01\x00\x04\x01\x02\x03\x04"
46
- #
47
- # Some aliases may also be defined. For example, to create a TLV type
48
- # whose +type+ field should be named +code+:
49
- # MyTLV = PacketGen::Types::AbstractTLV.create(type_class: PacketGen::Types::Int16,
50
- # length_class: PacketGen::Types::Int16,
51
- # aliases: { code: :type })
52
- # tlv = MyTLV.new(code: 1, value: 'abcd')
53
- # tlv.code #=> 1
54
- # tlv.type #=> 1
55
- # tlv.length #=> 4
56
- # tlv.value #=> 'abcd'
57
- #
58
- # @author Sylvain Daubert
59
- # @since 3.1.0
60
- # @since 3.1.1 add +:aliases+ keyword to {#initialize}
61
- class AbstractTLV < Types::Fields
62
- include Fieldable
63
-
64
- # @private
65
- FIELD_TYPES = { 'T' => :type, 'L' => :length, 'V' => :value }.freeze
66
-
67
- class << self
68
- # @return [Hash]
69
- attr_accessor :aliases
70
- # @deprecated
71
- attr_accessor :header_in_length
72
- # @private
73
- attr_accessor :field_in_length
74
-
75
- # rubocop:disable Metrics/ParameterLists
76
-
77
- # Generate a TLV class
78
- # @param [Class] type_class Class to use for +type+
79
- # @param [Class] length_class Class to use for +length+
80
- # @param [Class] value_class Class to use for +value+
81
- # @param [Boolean] header_in_length if +true +, +type+ and +length+ fields are
82
- # included in length. Deprecated, use +field_in_length+ instead.
83
- # @param [String] field_order give field order. Each character in [T,L,V] MUST be present once, in the desired order.
84
- # @param [String] field_in_length give fields to compute length on.
85
- # @return [Class]
86
- # @since 3.1.4 Add +header_in_length+ parameter
87
- # @since 3.3.1 Add +field_order+ and +field_in_length' parameters. Deprecate +header_in_length+ parameter.
88
- def create(type_class: Int8Enum, length_class: Int8, value_class: String,
89
- aliases: {}, header_in_length: false, field_order: 'TLV', field_in_length: 'V')
90
- Deprecation.deprecated_option(self, 'create', 'header_in_length', klass_method: true) if header_in_length
91
- raise Error, '.create cannot be called on a subclass of PacketGen::Types::AbstractTLV' unless self.equal?(AbstractTLV)
92
-
93
- klass = Class.new(self)
94
- klass.aliases = aliases
95
- klass.header_in_length = header_in_length
96
- klass.field_in_length = field_in_length
97
-
98
- check_field_in_length(field_in_length)
99
- check_field_order(field_order)
100
- generate_fields(klass, field_order, type_class, length_class, value_class)
101
-
102
- aliases.each do |al, orig|
103
- klass.instance_eval do
104
- alias_method al, orig if klass.method_defined?(orig)
105
- alias_method :"#{al}=", :"#{orig}=" if klass.method_defined?(:"#{orig}=")
106
- end
107
- end
108
-
109
- klass
110
- end
111
- # rubocop:enable Metrics/ParameterLists
112
-
113
- # @!attribute type
114
- # @abstract Type attribute for real TLV class
115
- # @return [Integer]
116
- # @!attribute length
117
- # @abstract Length attribute for real TLV class
118
- # @return [Integer]
119
- # @!attribute value
120
- # @abstract Value attribute for real TLV class
121
- # @return [Object]
122
-
123
- # @abstract Should only be called on real TLV classes, created by {.create}.
124
- # Set enum hash for {#type} field.
125
- # @param [Hash{String, Symbol => Integer}] hsh enum hash
126
- # @return [void]
127
- def define_type_enum(hsh)
128
- field_defs[:type][:enum].clear
129
- field_defs[:type][:enum].merge!(hsh)
130
- end
131
-
132
- # @abstract Should only be called on real TLV classes, created by {.create}.
133
- # Set default value for {#type} field.
134
- # @param [Integer,String,Symbol,nil] default default value from +hsh+ for type
135
- # @return [void]
136
- # @since 3.4.0
137
- def define_type_default(default)
138
- field_defs[:type][:default] = default
139
- end
140
-
141
- private
142
-
143
- def check_field_in_length(field_in_length)
144
- return if /^[TLV]{1,3}$/.match?(field_in_length)
145
-
146
- raise 'field_in_length must only contain T, L and/or V characters'
147
- end
148
-
149
- def check_field_order(field_order)
150
- return if field_order.match(/^[TLV]{3,3}$/) && (field_order[0] != field_order[1]) && (field_order[0] != field_order[2]) && (field_order[1] != field_order[2])
151
-
152
- raise 'field_order must contain all three letters TLV, each once'
153
- end
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
158
- when 'T'
159
- if type_class < Enum
160
- klass.define_field(:type, type_class, enum: {})
161
- else
162
- klass.define_field(:type, type_class)
163
- end
164
- when 'L'
165
- klass.define_field(:length, length_class)
166
- when 'V'
167
- klass.define_field(:value, value_class)
168
- end
169
- end
170
- end
171
- end
172
-
173
- # @!attribute type
174
- # @abstract Type attribute
175
- # @return [Integer]
176
- # @!attribute length
177
- # @abstract Length
178
- # @return [Integer]
179
- # @!attribute value
180
- # @abstract Value attribute
181
- # @return [Object]
182
-
183
- # @abstract Should only be called on real TLV classes, created by {.create}.
184
- # @param [Hash] options
185
- # @option options [Integer] :type
186
- # @option options [Integer] :length
187
- # @option options [Object] :value
188
- def initialize(options={})
189
- @header_in_length = self.class.header_in_length
190
- @field_in_length = self.class.field_in_length
191
- self.class.aliases.each do |al, orig|
192
- options[orig] = options[al] if options.key?(al)
193
- end
194
-
195
- super
196
- # used #value= defined below, which set length if needed
197
- self.value = options[:value] if options[:value]
198
- calc_length unless options.key?(:length)
199
- end
200
-
201
- # @abstract Should only be called on real TLV class instances.
202
- # Populate object from a binary string
203
- # @param [String,nil] str
204
- # @return [Fields] self
205
- def read(str)
206
- return self if str.nil?
207
-
208
- idx = 0
209
- fields.each do |field_name|
210
- field = self[field_name]
211
- length = field_name == :value ? real_length : field.sz
212
- field.read(str[idx, length])
213
- idx += field.sz
214
- end
215
-
216
- self
217
- end
218
-
219
- # @abstract Should only be called on real TLV class instances.
220
- # Set +value+. May set +length+ if value is a {Types::String}.
221
- # @param [Object] val
222
- # @return [Object]
223
- # @since 3.4.0 Base on field's +#from_human+ method
224
- def value=(val)
225
- if val.is_a?(self[:value].class)
226
- self[:value] = val
227
- elsif self[:value].respond_to?(:from_human)
228
- self[:value].from_human(val)
229
- else
230
- self[:value].read(val)
231
- end
232
- calc_length
233
- val
234
- end
235
-
236
- # @abstract Should only be called on real TLV class instances.
237
- # Get human-readable type
238
- # @return [String]
239
- def human_type
240
- self[:type].to_human.to_s
241
- end
242
-
243
- # @abstract Should only be called on real TLV class instances.
244
- # @return [String]
245
- def to_human
246
- my_value = self[:value].is_a?(String) ? self[:value].inspect : self[:value].to_human
247
- 'type:%s,length:%u,value:%s' % [human_type, length, my_value]
248
- end
249
-
250
- # Calculate length
251
- # @return [void]
252
- # @since 3.4.0
253
- def calc_length
254
- fil = @field_in_length
255
- fil = 'TLV' if @header_in_length
256
-
257
- length = 0
258
- fil.each_char do |field_type|
259
- length += self[FIELD_TYPES[field_type]].sz
260
- end
261
- self.length = length
262
- end
263
-
264
- private
265
-
266
- def real_length
267
- if @header_in_length
268
- self.length - self[:type].sz - self[:length].sz
269
- else
270
- length = self.length
271
- length -= self[:type].sz if @field_in_length.include?('T')
272
- length -= self[:length].sz if @field_in_length.include?('L')
273
- length
274
- end
275
- end
276
- end
277
- end
278
- end
@@ -1,287 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # This file is part of PacketGen
4
- # See https://github.com/lemontree55/packetgen 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
- require 'forwardable'
10
-
11
- module PacketGen
12
- module Types
13
- # @abstract Base class to define set of {Fields} subclasses.
14
- # == #record_from_hash
15
- # Subclasses should define private method +#record_from_hash+. This method
16
- # is called by {#push} to add an object to the set.
17
- #
18
- # A default method is defined by {Array}: it calls constructor of class defined
19
- # by {.set_of}.
20
- #
21
- # == #real_type
22
- # Subclasses should define private method +#real_type+ if {.set_of} type
23
- # may be subclassed. This method should return real class to use. It
24
- # takes an only argument, which is of type given by {.set_of}.
25
- #
26
- # Default behaviour of this method is to return argument's class.
27
- #
28
- # @author Sylvain Daubert
29
- class Array
30
- extend Forwardable
31
- include Enumerable
32
- include Fieldable
33
- include LengthFrom
34
-
35
- # @!method [](index)
36
- # Return the element at +index+.
37
- # @param [integer] index
38
- # @return [Object]
39
- # @!method clear
40
- # Clear array.
41
- # @return [void]
42
- # @!method each
43
- # Calls the given block once for each element in self, passing that
44
- # element as a parameter. Returns the array itself.
45
- # @return [Array]
46
- # @method empty?
47
- # Return +true+ if contains no element.
48
- # @return [Booelan]
49
- # @!method first
50
- # Return first element
51
- # @return [Object]
52
- # @!method last
53
- # Return last element.
54
- # @return [Object]
55
- # @!method size
56
- # Get number of element in array
57
- # @return [Integer]
58
- def_delegators :@array, :[], :clear, :each, :empty?, :first, :last, :size
59
- alias length size
60
-
61
- # Separator used in {#to_human}.
62
- # May be ovverriden by subclasses
63
- HUMAN_SEPARATOR = ','
64
-
65
- # rubocop:disable Naming/AccessorMethodName
66
- class << self
67
- # Get class set with {.set_of}.
68
- # @return [Class]
69
- # @since 3.0.0
70
- def set_of_klass
71
- @klass
72
- end
73
-
74
- # Define type of objects in set. Used by {#read} and {#push}.
75
- # @param [Class] klass
76
- # @return [void]
77
- def set_of(klass)
78
- @klass = klass
79
- end
80
- end
81
- # rubocop:enable Naming/AccessorMethodName
82
-
83
- # @param [Hash] options
84
- # @option options [Int] counter Int object used as a counter for this set
85
- def initialize(options={})
86
- @counter = options[:counter]
87
- @array = []
88
- initialize_length_from(options)
89
- end
90
-
91
- # Initialize array for copy:
92
- # * duplicate internal array.
93
- def initialize_copy(_other)
94
- @array = @array.dup
95
- end
96
-
97
- def ==(other)
98
- @array == case other
99
- when Array
100
- other.to_a
101
- else
102
- other
103
- end
104
- end
105
-
106
- # Clear array. Reset associated counter, if any.
107
- # @return [void]
108
- def clear!
109
- @array.clear
110
- @counter&.read(0)
111
- end
112
-
113
- # Delete an object from this array. Update associated counter if any
114
- # @param [Object] obj
115
- # @return [Object] deleted object
116
- def delete(obj)
117
- deleted = @array.delete(obj)
118
- @counter.read(@counter.to_i - 1) if @counter && deleted
119
- deleted
120
- end
121
-
122
- # Delete element at +index+.
123
- # @param [Integer] index
124
- # @return [Object,nil] deleted object
125
- def delete_at(index)
126
- deleted = @array.delete_at(index)
127
- @counter.read(@counter.to_i - 1) if @counter && deleted
128
- deleted
129
- end
130
-
131
- # @abstract depend on private method +#record_from_hash+ which should be
132
- # declared by subclasses.
133
- # Add an object to this array
134
- # @param [Object] obj type depends on subclass
135
- # @return [Array] self
136
- def push(obj)
137
- obj = case obj
138
- when Hash
139
- record_from_hash obj
140
- else
141
- obj
142
- end
143
- @array << obj
144
- self
145
- end
146
-
147
- # @abstract depend on private method +#record_from_hash+ which should be
148
- # declared by subclasses.
149
- # Add an object to this array, and increment associated counter, if any
150
- # @param [Object] obj type depends on subclass
151
- # @return [Array] self
152
- def <<(obj)
153
- push obj
154
- @counter&.read(@counter.to_i + 1)
155
- self
156
- end
157
-
158
- # Populate object from a string or from an array of hashes
159
- # @param [String, Array<Hash>] data
160
- # @return [self]
161
- def read(data)
162
- clear
163
- case data
164
- when ::Array
165
- read_from_array(data)
166
- else
167
- read_from_string(data)
168
- end
169
- self
170
- end
171
-
172
- # Get size in bytes
173
- # @return [Integer]
174
- def sz
175
- to_s.size
176
- end
177
-
178
- # Return an Array
179
- # @return [::Array]
180
- def to_a
181
- @array
182
- end
183
-
184
- # Get binary string
185
- # @return [String]
186
- def to_s
187
- @array.map(&:to_s).join
188
- end
189
-
190
- # Get a human readable string
191
- # @return [String]
192
- def to_human
193
- @array.map(&:to_human).join(self.class::HUMAN_SEPARATOR)
194
- end
195
-
196
- private
197
-
198
- # rubocop:disable Metrics/CyclomaticComplexity
199
-
200
- def read_from_string(str)
201
- return self if str.nil? || @counter&.to_i&.zero?
202
-
203
- str = read_with_length_from(str)
204
- until str.empty? || (@counter && self.size == @counter.to_i)
205
- obj = create_object_from_str(str)
206
- @array << obj
207
- str.slice!(0, obj.sz)
208
- end
209
- end
210
- # rubocop:enable Metrics/CyclomaticComplexity
211
-
212
- def read_from_array(ary)
213
- return self if ary.empty?
214
-
215
- ary.each do |hsh|
216
- self << hsh
217
- end
218
- end
219
-
220
- def record_from_hash(hsh)
221
- obj_klass = self.class.set_of_klass
222
- raise NotImplementedError, 'class should define #record_from_hash or declare type of elements in set with .set_of' unless obj_klass
223
-
224
- obj = obj_klass.new(hsh) if obj_klass
225
- klass = real_type(obj)
226
- klass == obj_klass ? obj : klass.new(hsh)
227
- end
228
-
229
- def real_type(_obj)
230
- self.class.set_of_klass
231
- end
232
-
233
- def create_object_from_str(str)
234
- klass = self.class.set_of_klass
235
- obj = klass.new.read(str)
236
- real_klass = real_type(obj)
237
-
238
- if real_klass == klass
239
- obj
240
- else
241
- real_klass.new.read(str)
242
- end
243
- end
244
- end
245
-
246
- # @private
247
- module ArrayOfIntMixin
248
- def read_from_array(ary)
249
- return self if ary.empty?
250
-
251
- ary.each do |i|
252
- self << self.class.set_of_klass.new(i)
253
- end
254
- end
255
- end
256
-
257
- # Specialized array to handle serie of {Int8}.
258
- class ArrayOfInt8 < Array
259
- include ArrayOfIntMixin
260
- set_of Int8
261
- end
262
-
263
- # Specialized array to handle serie of {Int16}.
264
- class ArrayOfInt16 < Array
265
- include ArrayOfIntMixin
266
- set_of Int16
267
- end
268
-
269
- # Specialized array to handle serie of {Int16le}.
270
- class ArrayOfInt16le < Array
271
- include ArrayOfIntMixin
272
- set_of Int16le
273
- end
274
-
275
- # Specialized array to handle serie of {Int32}.
276
- class ArrayOfInt32 < Types::Array
277
- include ArrayOfIntMixin
278
- set_of Types::Int32
279
- end
280
-
281
- # Specialized array to handle serie of {Int32le}.
282
- class ArrayOfInt32le < Types::Array
283
- include ArrayOfIntMixin
284
- set_of Types::Int32le
285
- end
286
- end
287
- end
@@ -1,109 +0,0 @@
1
- # coding: utf-8
2
- # frozen_string_literal: true
3
-
4
- # This file is part of PacketGen
5
- # See https://github.com/lemontree55/packetgen for more informations
6
- # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
7
- # Copyright (C) 2024 LemonTree55 <lenontree@proton.me>
8
- # This program is published under MIT license.
9
-
10
- require 'forwardable'
11
-
12
- module PacketGen
13
- module Types
14
- # This class handles null-terminated strings (aka C strings).
15
- # @author Sylvain Daubert
16
- # @since 3.1.6 no more a subclass or regular String
17
- class CString
18
- extend Forwardable
19
- include Fieldable
20
-
21
- def_delegators :@string, :[], :length, :size, :inspect, :==,
22
- :unpack, :force_encoding, :encoding, :index, :empty?,
23
- :encode, :slice, :slice!
24
-
25
- # @return [::String]
26
- attr_reader :string
27
- # @return [Integer]
28
- attr_reader :static_length
29
-
30
- # @param [Hash] options
31
- # @option options [Integer] :static_length set a static length for this string
32
- def initialize(options={})
33
- register_internal_string(+'')
34
- @static_length = options[:static_length]
35
- end
36
-
37
- # @param [::String] str
38
- # @return [String] self
39
- def read(str)
40
- s = str.to_s
41
- s = s[0, static_length] if static_length?
42
- register_internal_string s
43
- remove_null_character
44
- self
45
- end
46
-
47
- # get null-terminated string
48
- # @return [String]
49
- def to_s
50
- if static_length?
51
- s = string[0, static_length - 1]
52
- s << "\x00" * (static_length - s.length)
53
- else
54
- s = "#{string}\x00"
55
- end
56
- PacketGen.force_binary(s)
57
- end
58
-
59
- # Append the given string to CString
60
- # @param [#to_s] str
61
- # @return [self]
62
- def <<(str)
63
- @string << str.to_s
64
- remove_null_character
65
- self
66
- end
67
-
68
- # @return [Integer]
69
- def sz
70
- if static_length?
71
- static_length
72
- else
73
- to_s.size
74
- end
75
- end
76
-
77
- # Say if a static length is defined
78
- # @return [Boolean]
79
- # @since 3.1.6
80
- def static_length?
81
- !static_length.nil?
82
- end
83
-
84
- # Populate CString from a human readable string
85
- # @param [String] str
86
- # @return [self]
87
- def from_human(str)
88
- read str
89
- end
90
-
91
- # @return [String]
92
- def to_human
93
- string
94
- end
95
-
96
- private
97
-
98
- def register_internal_string(str)
99
- @string = str
100
- PacketGen.force_binary(@string)
101
- end
102
-
103
- def remove_null_character
104
- idx = string.index(0.chr)
105
- register_internal_string(string[0, idx]) unless idx.nil?
106
- end
107
- end
108
- end
109
- end