rasn1 0.11.0 → 0.12.1

Sign up to get free protection for your applications and to get access to all the features.
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