rasn1 0.11.0 → 0.12.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cc6eb3e3649f88dae027153d6136d5e5969135c74a527d4abbc42a42e03e2e73
4
- data.tar.gz: a674238e2461230d7076ffb29250b3a222c229b7af484b586da25642ba87863a
3
+ metadata.gz: 884fa6f74d0b3074ef074d061301092d55df580b663714c4a962a7b8503d777d
4
+ data.tar.gz: 77cc3c5d7bf926463464ca4d37237f0cddc358e0d7b9aa3e85c15982ab3f3fc1
5
5
  SHA512:
6
- metadata.gz: dba48f620835a6ce4c9b6764d1538a2f96a94f21a7c8aa39b587783ba08b5c745c918eb885276372b3ae215f904596dfb3b5eab818c1a7416131e898c9c220eb
7
- data.tar.gz: e397c4b1b78320a3b69e24aa9bbf46d29b04653b03aed76f9c906e5e47a03b027957d2d8d6a8f60793f13255b2492f5eb43e9f05a73d3e8dd9bde676cbbcdfe9
6
+ metadata.gz: fee544874a10b10618cd596b1c30edd4ad70185a783eeadbe23a86fa2439339d7d025784be5adc76904e05856ac8791817a768c0603ece0141e38d2975e588ad
7
+ data.tar.gz: 39428eb166401712d44eb60c4413bcd919d4fca380213acbe1dc29c32425c03a8852e1f0afa8934f5a04c604b376ac3c47424754b358cae96cc685029c467da7
data/lib/rasn1/errors.rb CHANGED
@@ -18,10 +18,17 @@ module RASN1
18
18
  # Enumerated error
19
19
  class EnumeratedError < Error; end
20
20
 
21
- # CHOICE error: #chosen not set
21
+ # CHOICE error: {Types::Choice#chosen} not set
22
22
  class ChoiceError < RASN1::Error
23
+ # @param [Types::Base] object
24
+ def initialize(object)
25
+ @object = object
26
+ super()
27
+ end
28
+
29
+ # @return [String]
23
30
  def message
24
- "CHOICE #{@name}: #chosen not set"
31
+ "CHOICE #{@object.name}: #chosen not set"
25
32
  end
26
33
  end
27
34
 
@@ -37,7 +44,12 @@ module RASN1
37
44
 
38
45
  # @return [String]
39
46
  def message
40
- "Constraint not verified on #{object.inspect}"
47
+ "Constraint not verified on #{@object.inspect}"
41
48
  end
42
49
  end
50
+
51
+ # Exception raised when model validation fails
52
+ # @since 0.12.0
53
+ class ModelValidationError < Error
54
+ end
43
55
  end
data/lib/rasn1/model.rb CHANGED
@@ -57,16 +57,47 @@ module RASN1
57
57
  #
58
58
  # == Delegation
59
59
  # {Model} may delegate some methods to its root element. Thus, if root element
60
- # is, for example, a {TypeInts::Choice}, model may delegate +#chosen+ and +#chosen_value+.
60
+ # is, for example, a {Types::Choice}, model may delegate +#chosen+ and +#chosen_value+.
61
61
  #
62
62
  # All methods defined by root may be delegated by model, unless model also defines
63
63
  # this method.
64
64
  # @author Sylvain Daubert
65
- class Model
65
+ # @author adfoster-r7 ModelValidationError, track source location for dynamic class methods
66
+ class Model # rubocop:disable Metrics/ClassLength
66
67
  # @private
67
- Elem = Struct.new(:name, :proc_or_class, :content)
68
+ Elem = Struct.new(:name, :proc_or_class, :content) do
69
+ # @param [String,Symbol] name
70
+ # @param [Proc,Class] proc_or_class
71
+ # @param [Hash,nil] content
72
+ def initialize(name, proc_or_class, content)
73
+ if content.is_a?(Array)
74
+ duplicate_names = find_all_duplicate_names(content.map(&:name) + [name])
75
+ raise ModelValidationError, "Duplicate name #{duplicate_names.first} found" if duplicate_names.any?
76
+ end
77
+
78
+ super
79
+ end
80
+
81
+ private
82
+
83
+ # @param [Array<String>] names
84
+ # @return [Array<String>] The duplicate names found in the array
85
+ def find_all_duplicate_names(names)
86
+ names.group_by { |name| name }
87
+ .select { |_name, values| values.length > 1 }
88
+ .keys
89
+ end
90
+ end
68
91
 
69
92
  # @private
93
+ WrapElem = Struct.new(:element, :options) do
94
+ # @return [String]
95
+ def name
96
+ "#{element.name}_wrapper"
97
+ end
98
+ end
99
+
100
+ # Define helper methods to define models
70
101
  module Accel
71
102
  # @return [Hash]
72
103
  attr_reader :options
@@ -79,6 +110,15 @@ module RASN1
79
110
  @root = Elem.new(name, model_klass, nil)
80
111
  end
81
112
 
113
+ # Use a {Wrapper} around a {Types::Base} or a {Model} object
114
+ # @param [Types::Base,Model] element
115
+ # @param [Hash] options
116
+ # @return [WrapElem]
117
+ # @since 0.12
118
+ def wrapper(element, options={})
119
+ @root = WrapElem.new(element, options)
120
+ end
121
+
82
122
  # Update options of root element.
83
123
  # May be used when subclassing.
84
124
  # class Model1 < RASN1::Model
@@ -92,8 +132,13 @@ module RASN1
92
132
  # end
93
133
  # @param [Hash] options
94
134
  # @return [void]
135
+ # @since 0.12.0 may change name through +:name+
95
136
  def root_options(options)
96
137
  @options = options
138
+ return unless options.key?(:name)
139
+
140
+ @root = @root.dup
141
+ @root.name = options[:name]
97
142
  end
98
143
 
99
144
  # On inheritance, create +@root+ class variable
@@ -105,33 +150,45 @@ module RASN1
105
150
  klass.class_eval { @root = root }
106
151
  end
107
152
 
153
+ # @private
154
+ # @param [String,Symbol] accel_name
155
+ # @param [Class] klass
156
+ # @since 0.11.0
157
+ # @since 0.12.0 track source location on error (adfoster-r7)
108
158
  def define_type_accel_base(accel_name, klass)
109
- singleton_class.class_eval(
110
- "def #{accel_name}(name, options={})\n" \
111
- " options[:name] = name\n" \
112
- " proc = proc do |opts|\n" \
113
- " #{klass}.new(options.merge(opts))\n" \
114
- " end\n" \
115
- " @root = Elem.new(name, proc, options[:content])\n" \
116
- 'end'
117
- )
159
+ singleton_class.class_eval <<-EVAL, __FILE__, __LINE__ + 1
160
+ def #{accel_name}(name, options={}) # def sequence(name, type, options)
161
+ options[:name] = name
162
+ proc = proc do |opts|
163
+ #{klass}.new(options.merge(opts)) # Sequence.new(options.merge(opts))
164
+ end
165
+ @root = Elem.new(name, proc, options[:content])
166
+ end
167
+ EVAL
118
168
  end
119
169
 
170
+ # @private
171
+ # @param [String,Symbol] accel_name
172
+ # @param [Class] klass
173
+ # @since 0.11.0
174
+ # @since 0.12.0 track source location on error (adfoster-r7)
120
175
  def define_type_accel_of(accel_name, klass)
121
- singleton_class.class_eval(
122
- "def #{accel_name}_of(name, type, options={})\n" \
123
- " options[:name] = name\n" \
124
- " proc = proc do |opts|\n" \
125
- " #{klass}.new(type, options.merge(opts))\n" \
126
- " end\n" \
127
- " @root = Elem.new(name, proc, nil)\n" \
128
- 'end'
129
- )
176
+ singleton_class.class_eval <<-EVAL, __FILE__, __LINE__ + 1
177
+ def #{accel_name}_of(name, type, options={}) # def sequence_of(name, type, options)
178
+ options[:name] = name
179
+ proc = proc do |opts|
180
+ #{klass}.new(type, options.merge(opts)) # SequenceOf.new(type, options.merge(opts))
181
+ end
182
+ @root = Elem.new(name, proc, nil)
183
+ end
184
+ EVAL
130
185
  end
131
186
 
132
187
  # Define an accelarator to access a type in a model definition
133
188
  # @param [String] accel_name
134
- # @param [Class] klass
189
+ # @param [Class] klass class to instanciate
190
+ # @since 0.11.0
191
+ # @since 0.12.0 track source location on error (adfoster-r7)
135
192
  def define_type_accel(accel_name, klass)
136
193
  if klass < Types::SequenceOf
137
194
  define_type_accel_of(accel_name, klass)
@@ -184,17 +241,20 @@ module RASN1
184
241
 
185
242
  extend Accel
186
243
 
187
- # @method sequence(name, options)
244
+ # @!method sequence(name, options)
245
+ # @!scope class
188
246
  # @param [Symbol,String] name name of object in model
189
247
  # @param [Hash] options
190
248
  # @return [Elem]
191
249
  # @see Types::Sequence#initialize
192
- # @method set(name, options)
250
+ # @!method set(name, options)
251
+ # @!scope class
193
252
  # @param [Symbol,String] name name of object in model
194
253
  # @param [Hash] options
195
254
  # @return [Elem]
196
255
  # @see Types::Set#initialize
197
- # @method choice(name, options)
256
+ # @!method choice(name, options)
257
+ # @!scope class
198
258
  # @param [Symbol,String] name name of object in model
199
259
  # @param [Hash] options
200
260
  # @return [Elem]
@@ -203,13 +263,15 @@ module RASN1
203
263
  self.define_type_accel_base(type, Types.const_get(type.capitalize))
204
264
  end
205
265
 
206
- # @method sequence_of(name, type, options)
266
+ # @!method sequence_of(name, type, options)
267
+ # @!scope class
207
268
  # @param [Symbol,String] name name of object in model
208
269
  # @param [Model, Types::Base] type type for SEQUENCE OF
209
270
  # @param [Hash] options
210
271
  # @return [Elem]
211
272
  # @see Types::SequenceOf#initialize
212
- # @method set_of(name, type, options)
273
+ # @!method set_of(name, type, options)
274
+ # @!scope class
213
275
  # @param [Symbol,String] name name of object in model
214
276
  # @param [Model, Types::Base] type type for SET OF
215
277
  # @param [Hash] options
@@ -219,57 +281,68 @@ module RASN1
219
281
  define_type_accel_of(type, Types.const_get("#{type.capitalize}Of"))
220
282
  end
221
283
 
222
- # @method boolean(name, options)
284
+ # @!method boolean(name, options)
285
+ # @!scope class
223
286
  # @param [Symbol,String] name name of object in model
224
287
  # @param [Hash] options
225
288
  # @return [Elem]
226
289
  # @see Types::Boolean#initialize
227
- # @method integer(name, options)
290
+ # @!method integer(name, options)
291
+ # @!scope class
228
292
  # @param [Symbol,String] name name of object in model
229
293
  # @param [Hash] options
230
294
  # @return [Elem]
231
295
  # @see Types::Integer#initialize
232
- # @method bit_string(name, options)
296
+ # @!method bit_string(name, options)
297
+ # @!scope class
233
298
  # @param [Symbol,String] name name of object in model
234
299
  # @param [Hash] options
235
300
  # @return [Elem]
236
301
  # @see Types::BitString#initialize
237
- # @method octet_string(name, options)
302
+ # @!method octet_string(name, options)
303
+ # @!scope class
238
304
  # @param [Symbol,String] name name of object in model
239
305
  # @param [Hash] options
240
306
  # @return [Elem]
241
307
  # @see Types::OctetString#initialize
242
- # @method null(name, options)
308
+ # @!method null(name, options)
309
+ # @!scope class
243
310
  # @param [Symbol,String] name name of object in model
244
311
  # @param [Hash] options
245
312
  # @return [Elem]
246
313
  # @see Types::Null#initialize
247
- # @method enumerated(name, options)
314
+ # @!method enumerated(name, options)
315
+ # @!scope class
248
316
  # @param [Symbol,String] name name of object in model
249
317
  # @param [Hash] options
250
318
  # @return [Elem]
251
319
  # @see Types::Enumerated#initialize
252
- # @method utf8_string(name, options)
320
+ # @!method utf8_string(name, options)
321
+ # @!scope class
253
322
  # @param [Symbol,String] name name of object in model
254
323
  # @param [Hash] options
255
324
  # @return [Elem]
256
325
  # @see Types::Utf8String#initialize
257
- # @method numeric_string(name, options)
326
+ # @!method numeric_string(name, options)
327
+ # @!scope class
258
328
  # @param [Symbol,String] name name of object in model
259
329
  # @param [Hash] options
260
330
  # @return [Elem]
261
331
  # @see Types::NumericString#initialize
262
- # @method printable_string(name, options)
332
+ # @!method printable_string(name, options)
333
+ # @!scope class
263
334
  # @param [Symbol,String] name name of object in model
264
335
  # @param [Hash] options
265
336
  # @return [Elem]
266
337
  # @see Types::PrintableString#initialize
267
- # @method visible_string(name, options)
338
+ # @!method visible_string(name, options)
339
+ # @!scope class
268
340
  # @param [Symbol,String] name name of object in model
269
341
  # @param [Hash] options
270
342
  # @return [Elem]
271
343
  # @see Types::VisibleString#initialize
272
- # @method ia5_string(name, options)
344
+ # @!method ia5_string(name, options)
345
+ # @!scope class
273
346
  # @param [Symbol,String] name name of object in model
274
347
  # @param [Hash] options
275
348
  # @return [Elem]
@@ -285,7 +358,7 @@ module RASN1
285
358
  # @param [Hash] args
286
359
  def initialize(args={})
287
360
  root = generate_root
288
- set_elements(root)
361
+ generate_elements(root)
289
362
  initialize_elements(self, args)
290
363
  end
291
364
 
@@ -296,7 +369,7 @@ module RASN1
296
369
  @elements[name]
297
370
  end
298
371
 
299
- # Set value of element +name+. Element should be a {Base}.
372
+ # Set value of element +name+. Element should be a {Types::Base}.
300
373
  # @param [String,Symbol] name
301
374
  # @param [Object] value
302
375
  # @return [Object] value
@@ -460,14 +533,33 @@ module RASN1
460
533
  class_element
461
534
  end
462
535
 
463
- def set_elements(element) # rubocop:disable Naming/AccessorMethodName
536
+ def generate_elements(element)
537
+ if element.is_a?(WrapElem)
538
+ generate_wrapper(element)
539
+ return
540
+ end
464
541
  return unless element.content.is_a? Array
465
542
 
466
543
  @elements[name].value = element.content.map do |another_element|
467
- subel = get_type(another_element.proc_or_class)
468
- @elements[another_element.name] = subel
469
- set_elements(another_element) if composed?(subel) && another_element.content.is_a?(Array)
544
+ add_subelement(another_element)
545
+ end
546
+ end
547
+
548
+ def generate_wrapper(wrap_elem)
549
+ inner_elem = wrap_elem.element
550
+ subel = add_subelement(inner_elem)
551
+ Wrapper.new(subel, wrap_elem.options)
552
+ end
553
+
554
+ def add_subelement(subelement)
555
+ case subelement
556
+ when Elem
557
+ subel = get_type(subelement.proc_or_class)
558
+ @elements[subelement.name] = subel
559
+ generate_elements(subelement) if composed?(subel) && subelement.content.is_a?(Array)
470
560
  subel
561
+ when WrapElem
562
+ generate_wrapper(subelement)
471
563
  end
472
564
  end
473
565
 
@@ -477,7 +569,7 @@ module RASN1
477
569
 
478
570
  case value
479
571
  when Hash
480
- raise ArgumentError, "element #{name}: may only pass a Hash for Model elements" unless obj[name].is_a? Model
572
+ raise ArgumentError, "element #{name}: may only pass a Hash for Model elements" unless obj[name].is_a?(Model)
481
573
 
482
574
  initialize_elements obj[name], value
483
575
  when Array
@@ -499,7 +591,7 @@ module RASN1
499
591
  end
500
592
  end
501
593
 
502
- def private_to_h(element=nil)
594
+ def private_to_h(element=nil) # rubocop:disable Metrics/CyclomaticComplexity
503
595
  my_element = element || root
504
596
  my_element = my_element.root if my_element.is_a?(Model)
505
597
  value = case my_element
@@ -507,6 +599,13 @@ module RASN1
507
599
  sequence_of_to_h(my_element)
508
600
  when Types::Sequence
509
601
  sequence_to_h(my_element)
602
+ # @author adfoster-r7
603
+ when Types::Choice
604
+ raise ChoiceError.new(my_element) if my_element.chosen.nil?
605
+
606
+ private_to_h(my_element.value[my_element.chosen])
607
+ when Wrapper
608
+ wrapper_to_h(my_element)
510
609
  else
511
610
  my_element.value
512
611
  end
@@ -529,11 +628,29 @@ module RASN1
529
628
  ary = seq.value.map do |el|
530
629
  next if el.optional? && el.value.nil?
531
630
 
532
- name = el.is_a?(Model) ? @elements.key(el) : el.name
533
- [name, private_to_h(el)]
631
+ case el
632
+ when Model
633
+ hsh = el.to_h
634
+ hsh = hsh[hsh.keys.first]
635
+ [@elements.key(el), hsh]
636
+ when Wrapper
637
+ [@elements.key(el.element), wrapper_to_h(el)]
638
+ else
639
+ [el.name, private_to_h(el)]
640
+ end
534
641
  end
535
642
  ary.compact!
536
643
  ary.to_h
537
644
  end
645
+
646
+ def wrapper_to_h(wrap)
647
+ case wrap.element
648
+ when Model
649
+ hsh = wrap.element.to_h
650
+ hsh[hsh.keys.first]
651
+ else
652
+ private_to_h(wrap.element)
653
+ end
654
+ end
538
655
  end
539
656
  end
@@ -0,0 +1,174 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RASN1
4
+ # @private
5
+ class Tracer
6
+ # @return [IO]
7
+ attr_reader :io
8
+ # @return [Integer]
9
+ attr_accessor :tracing_level
10
+
11
+ TRACED_CLASSES = [Types::Any, Types::Choice, Types::Sequence, Types::SequenceOf, Types::Base].freeze
12
+
13
+ # @param [IO] io
14
+ def initialize(io)
15
+ @io = io
16
+ @tracing_level = 0
17
+ end
18
+
19
+ # Puts +msg+ onto {#io}.
20
+ # @param [String] msg
21
+ # @return [void]
22
+ def trace(msg)
23
+ @io.puts(indent << msg)
24
+ end
25
+
26
+ # Return identation for given +level+. If +nil+, use {#tracing_level}.
27
+ # @param [Integer,nil] level
28
+ # @return [String]
29
+ def indent(level=nil)
30
+ level ||= @tracing_level
31
+ ' ' * level
32
+ end
33
+ end
34
+
35
+ # Trace RASN1 parsing to +io+.
36
+ # All parsing methods called in block are traced to +io+. Each ASN.1 element is
37
+ # traced in a line showing element's id, its length and its data.
38
+ # @param [IO] io
39
+ # @example
40
+ # RASN1.trace do
41
+ # RASN1.parse("\x02\x01\x01") # puts "INTEGER id: 2 (0x02), len: 1 (0x01), data: 0x01"
42
+ # end
43
+ # RASN1.parse("\x01\x01\xff") # puts nothing onto STDOUT
44
+ # @return [void]
45
+ def self.trace(io=$stdout)
46
+ @tracer = Tracer.new(io)
47
+ Tracer::TRACED_CLASSES.each(&:start_tracing)
48
+
49
+ begin
50
+ yield @tracer
51
+ ensure
52
+ Tracer::TRACED_CLASSES.reverse.each(&:stop_tracing)
53
+ @tracer.io.flush
54
+ @tracer = nil
55
+ end
56
+ end
57
+
58
+ # @private
59
+ def self.tracer
60
+ @tracer
61
+ end
62
+
63
+ module Types
64
+ class Base
65
+ class << self
66
+ # @private
67
+ # Patch {#do_parse} to add tracing ability
68
+ def start_tracing
69
+ alias_method :do_parse_without_tracing, :do_parse
70
+ alias_method :do_parse, :do_parse_with_tracing
71
+ alias_method :do_parse_explicit_without_tracing, :do_parse_explicit
72
+ alias_method :do_parse_explicit, :do_parse_explicit_with_tracing
73
+ end
74
+
75
+ # @private
76
+ # Unpatch {#do_parse} to remove tracing ability
77
+ def stop_tracing
78
+ alias_method :do_parse, :do_parse_without_tracing # rubocop:disable Lint/DuplicateMethods
79
+ alias_method :do_parse_explicit, :do_parse_explicit_without_tracing # rubocop:disable Lint/DuplicateMethods
80
+ end
81
+ end
82
+
83
+ # @private
84
+ # Parse +der+ with tracing abillity
85
+ # @see #parse!
86
+ def do_parse_with_tracing(der, ber)
87
+ ret = do_parse_without_tracing(der, ber)
88
+ RASN1.tracer.trace(self.trace)
89
+ ret
90
+ end
91
+
92
+ def do_parse_explicit_with_tracing(data)
93
+ RASN1.tracer.tracing_level += 1
94
+ do_parse_explicit_without_tracing(data)
95
+ RASN1.tracer.tracing_level -= 1
96
+ end
97
+ end
98
+
99
+ class Choice
100
+ class << self
101
+ # @private
102
+ # Patch {#parse!} to add tracing ability
103
+ def start_tracing
104
+ alias_method :parse_without_tracing, :parse!
105
+ alias_method :parse!, :parse_with_tracing
106
+ end
107
+
108
+ # @private
109
+ # Unpatch {#parse!} to remove tracing ability
110
+ def stop_tracing
111
+ alias_method :parse!, :parse_without_tracing # rubocop:disable Lint/DuplicateMethods
112
+ end
113
+ end
114
+
115
+ # @private
116
+ # Parse +der+ with tracing abillity
117
+ # @see #parse!
118
+ def parse_with_tracing(der, ber: false)
119
+ RASN1.tracer.trace(self.trace)
120
+ parse_without_tracing(der, ber: ber)
121
+ end
122
+ end
123
+
124
+ class Sequence
125
+ class << self
126
+ # @private
127
+ # Patch {#der_to_value} to add tracing ability
128
+ def start_tracing
129
+ alias_method :der_to_value_without_tracing, :der_to_value
130
+ alias_method :der_to_value, :der_to_value_with_tracing
131
+ end
132
+
133
+ # @private
134
+ # Unpatch {#der_to_value!} to remove tracing ability
135
+ def stop_tracing
136
+ alias_method :der_to_value, :der_to_value_without_tracing # rubocop:disable Lint/DuplicateMethods
137
+ end
138
+ end
139
+
140
+ # @private
141
+ # der_to_value +der+ with tracing abillity
142
+ def der_to_value_with_tracing(der, ber: false)
143
+ RASN1.tracer.tracing_level += 1
144
+ der_to_value_without_tracing(der, ber: ber)
145
+ RASN1.tracer.tracing_level -= 1
146
+ end
147
+ end
148
+
149
+ class SequenceOf
150
+ class << self
151
+ # @private
152
+ # Patch {#der_to_value} to add tracing ability
153
+ def start_tracing
154
+ alias_method :der_to_value_without_tracing, :der_to_value
155
+ alias_method :der_to_value, :der_to_value_with_tracing
156
+ end
157
+
158
+ # @private
159
+ # Unpatch {#der_to_value!} to remove tracing ability
160
+ def stop_tracing
161
+ alias_method :der_to_value, :der_to_value_without_tracing # rubocop:disable Lint/DuplicateMethods
162
+ end
163
+ end
164
+
165
+ # @private
166
+ # der_to_value +der+ with tracing abillity
167
+ def der_to_value_with_tracing(der, ber: false)
168
+ RASN1.tracer.tracing_level += 1
169
+ der_to_value_without_tracing(der, ber: ber)
170
+ RASN1.tracer.tracing_level -= 1
171
+ end
172
+ end
173
+ end
174
+ end
@@ -21,28 +21,22 @@ module RASN1
21
21
  end
22
22
  end
23
23
 
24
+ def can_build?
25
+ value? || !optional?
26
+ end
27
+
24
28
  # Parse a DER string. This method updates object: {#value} will be a DER
25
29
  # string.
26
30
  # @param [String] der DER string
27
31
  # @param [Boolean] ber if +true+, accept BER encoding
28
32
  # @return [Integer] total number of parsed bytes
29
33
  def parse!(der, ber: false)
30
- if der.empty?
31
- return 0 if optional?
32
-
33
- raise ASN1Error, 'Expected ANY but get nothing'
34
- end
35
-
36
- id_size = Types.decode_identifier_octets(der).last
37
- total_length, = get_data(der[id_size..-1], ber)
38
- total_length += id_size
39
-
40
- @no_value = false
41
- @value = der[0, total_length]
42
-
34
+ total_length, _data = do_parse(der, ber)
43
35
  total_length
44
36
  end
45
37
 
38
+ # @param [::Integer] level
39
+ # @return [String]
46
40
  def inspect(level=0)
47
41
  str = common_inspect(level)
48
42
  str << if !value?
@@ -56,6 +50,16 @@ module RASN1
56
50
  end
57
51
  end
58
52
 
53
+ # @private Tracer private API
54
+ # @return [String]
55
+ def trace
56
+ return trace_any if value?
57
+
58
+ msg_type(no_id: true) << ' NONE'
59
+ end
60
+
61
+ private
62
+
59
63
  def common_inspect(level)
60
64
  lvl = level >= 0 ? level : 0
61
65
  str = ' ' * lvl
@@ -65,6 +69,27 @@ module RASN1
65
69
  str << "[#{id}] IMPLICIT " if implicit?
66
70
  str << '(ANY) '
67
71
  end
72
+
73
+ def do_parse(der, ber)
74
+ if der.empty?
75
+ return [0, ''] if optional?
76
+
77
+ raise ASN1Error, 'Expected ANY but get nothing'
78
+ end
79
+
80
+ id_size = Types.decode_identifier_octets(der).last
81
+ total_length, = get_data(der[id_size..-1], ber)
82
+ total_length += id_size
83
+
84
+ @no_value = false
85
+ @value = der[0, total_length]
86
+
87
+ [total_length, @value]
88
+ end
89
+
90
+ def trace_any
91
+ msg_type(no_id: true) << trace_data(value)
92
+ end
68
93
  end
69
94
  end
70
95
  end