rasn1 0.14.0 → 0.15.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 +4 -4
- data/README.md +13 -6
- data/lib/rasn1/model.rb +145 -138
- data/lib/rasn1/tracer.rb +4 -4
- data/lib/rasn1/types/any.rb +5 -3
- data/lib/rasn1/types/base.rb +43 -30
- data/lib/rasn1/types/bit_string.rb +12 -7
- data/lib/rasn1/types/bmp_string.rb +3 -11
- data/lib/rasn1/types/boolean.rb +15 -8
- data/lib/rasn1/types/choice.rb +43 -3
- data/lib/rasn1/types/constrained.rb +5 -2
- data/lib/rasn1/types/generalized_time.rb +32 -24
- data/lib/rasn1/types/ia5string.rb +3 -11
- data/lib/rasn1/types/integer.rb +13 -9
- data/lib/rasn1/types/null.rb +11 -6
- data/lib/rasn1/types/numeric_string.rb +13 -6
- data/lib/rasn1/types/object_id.rb +33 -21
- data/lib/rasn1/types/octet_string.rb +26 -0
- data/lib/rasn1/types/printable_string.rb +13 -6
- data/lib/rasn1/types/sequence.rb +16 -12
- data/lib/rasn1/types/sequence_of.rb +15 -11
- data/lib/rasn1/types/universal_string.rb +3 -11
- data/lib/rasn1/types/utc_time.rb +17 -7
- data/lib/rasn1/types/utf8_string.rb +3 -11
- data/lib/rasn1/types/visible_string.rb +14 -2
- data/lib/rasn1/types.rb +6 -5
- data/lib/rasn1/version.rb +2 -1
- data/lib/rasn1/wrapper.rb +72 -18
- data/lib/rasn1.rb +4 -1
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 44b823b6a8e75b419ef38d27be1a31464667f4a2729ce514702b83a34210e7cb
         | 
| 4 | 
            +
              data.tar.gz: 4e8f19d517834432999dac059bd175bc53330b224ffb554017efd6ebdca83e34
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: a44cdcea86cd6a7687cc0bb56475ee9325a5135acdd3b3408d5c1be936511279ed344d3811afa44a0eb658f01cd71a73fa49ea4c825e3d81d6c5746684e04076
         | 
| 7 | 
            +
              data.tar.gz: fadc12bb059a416ae8716857ef91a402969ef78d80ca767bfefe09237794e7accffc4a6876ab90400047efb63442b065508ef3ff5768d4df1f18f8d6890f0334
         | 
    
        data/README.md
    CHANGED
    
    | @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            [](https://badge.fury.io/rb/rasn1)
         | 
| 2 | 
            -
            [](https://github.com/lemontree55/rasn1/actions/workflows/ci.yml)
         | 
| 3 3 |  | 
| 4 4 | 
             
            # Rasn1
         | 
| 5 5 |  | 
| @@ -15,11 +15,15 @@ gem 'rasn1' | |
| 15 15 |  | 
| 16 16 | 
             
            And then execute:
         | 
| 17 17 |  | 
| 18 | 
            -
             | 
| 18 | 
            +
            ```bash
         | 
| 19 | 
            +
            bundle install
         | 
| 20 | 
            +
            ```
         | 
| 19 21 |  | 
| 20 22 | 
             
            Or install it yourself as:
         | 
| 21 23 |  | 
| 22 | 
            -
             | 
| 24 | 
            +
            ```bash
         | 
| 25 | 
            +
            gem install rasn1
         | 
| 26 | 
            +
            ```
         | 
| 23 27 |  | 
| 24 28 | 
             
            ## Simple usage
         | 
| 25 29 |  | 
| @@ -31,9 +35,10 @@ decoded_ber = RASN1.parse(ber_string, ber: true) | |
| 31 35 | 
             
            ```
         | 
| 32 36 |  | 
| 33 37 | 
             
            ## Advanced usage
         | 
| 38 | 
            +
             | 
| 34 39 | 
             
            All examples below will be based on:
         | 
| 35 40 |  | 
| 36 | 
            -
            ```
         | 
| 41 | 
            +
            ```text
         | 
| 37 42 | 
             
            Record ::= SEQUENCE {
         | 
| 38 43 | 
             
              id        INTEGER,
         | 
| 39 44 | 
             
              room  [0] INTEGER OPTIONAL,
         | 
| @@ -70,6 +75,7 @@ end | |
| 70 75 | 
             
            ```
         | 
| 71 76 |  | 
| 72 77 | 
             
            ### Parse a DER-encoded string
         | 
| 78 | 
            +
             | 
| 73 79 | 
             
            ```ruby
         | 
| 74 80 | 
             
            record = Record.parse(der_string)
         | 
| 75 81 | 
             
            record[:id]             # => RASN1::Types::Integer
         | 
| @@ -92,6 +98,7 @@ cplx_record[:a_record]        # => Record | |
| 92 98 | 
             
            ```
         | 
| 93 99 |  | 
| 94 100 | 
             
            ### Generate a DER-encoded string
         | 
| 101 | 
            +
             | 
| 95 102 | 
             
            ```ruby
         | 
| 96 103 | 
             
            record = Record.new(id: 12)
         | 
| 97 104 | 
             
            record[:id].to_i      # => 12
         | 
| @@ -110,8 +117,8 @@ record.to_der         # => String | |
| 110 117 |  | 
| 111 118 | 
             
            ### More information
         | 
| 112 119 |  | 
| 113 | 
            -
            see https://github.com/sdaubert/rasn1/wiki
         | 
| 120 | 
            +
            see <https://github.com/sdaubert/rasn1/wiki>
         | 
| 114 121 |  | 
| 115 122 | 
             
            ## Contributing
         | 
| 116 123 |  | 
| 117 | 
            -
            Bug reports and pull requests are welcome on GitHub at https://github.com/sdaubert/rasn1 | 
| 124 | 
            +
            Bug reports and pull requests are welcome on GitHub at <https://github.com/sdaubert/rasn1>.
         | 
    
        data/lib/rasn1/model.rb
    CHANGED
    
    | @@ -1,7 +1,5 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require_relative 'types/constrained'
         | 
| 4 | 
            -
             | 
| 5 3 | 
             
            module RASN1
         | 
| 6 4 | 
             
              # @abstract
         | 
| 7 5 | 
             
              # {Model} class is a base class to define ASN.1 models.
         | 
| @@ -64,39 +62,45 @@ module RASN1 | |
| 64 62 | 
             
              # @author Sylvain Daubert
         | 
| 65 63 | 
             
              # @author adfoster-r7 ModelValidationError, track source location for dynamic class methods
         | 
| 66 64 | 
             
              class Model # rubocop:disable Metrics/ClassLength
         | 
| 67 | 
            -
                # @private
         | 
| 68 | 
            -
                 | 
| 65 | 
            +
                # @private Base Element
         | 
| 66 | 
            +
                BaseElem = Struct.new(:name, :proc, :content) do
         | 
| 69 67 | 
             
                  # @param [String,Symbol] name
         | 
| 70 | 
            -
                  # @param [Proc | 
| 68 | 
            +
                  # @param [Proc] proc
         | 
| 71 69 | 
             
                  # @param [Array,nil] content
         | 
| 72 | 
            -
                  def initialize(name,  | 
| 73 | 
            -
                     | 
| 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 | 
            -
             | 
| 70 | 
            +
                  def initialize(name, proc, content)
         | 
| 71 | 
            +
                    check_duplicates(content.map(&:name) + [name]) unless content.nil?
         | 
| 78 72 | 
             
                    super
         | 
| 79 73 | 
             
                  end
         | 
| 80 74 |  | 
| 81 75 | 
             
                  private
         | 
| 82 76 |  | 
| 83 | 
            -
                  # @param [Array<String>] names
         | 
| 84 77 | 
             
                  # @return [Array<String>] The duplicate names found in the array
         | 
| 85 78 | 
             
                  def find_all_duplicate_names(names)
         | 
| 86 79 | 
             
                    names.group_by { |name| name }
         | 
| 87 80 | 
             
                         .select { |_name, values| values.length > 1 }
         | 
| 88 81 | 
             
                         .keys
         | 
| 89 82 | 
             
                  end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                  def check_duplicates(names)
         | 
| 85 | 
            +
                    duplicates = find_all_duplicate_names(names)
         | 
| 86 | 
            +
                    raise ModelValidationError, "Duplicate name #{duplicates.first} found" if duplicates.any?
         | 
| 87 | 
            +
                  end
         | 
| 90 88 | 
             
                end
         | 
| 91 89 |  | 
| 92 | 
            -
                # @private
         | 
| 90 | 
            +
                # @private Model Element
         | 
| 91 | 
            +
                ModelElem = Struct.new(:name, :klass)
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                # @private Wrapper Element
         | 
| 93 94 | 
             
                WrapElem = Struct.new(:element, :options) do
         | 
| 94 | 
            -
                  # @return [ | 
| 95 | 
            +
                  # @return [Symbol]
         | 
| 95 96 | 
             
                  def name
         | 
| 96 | 
            -
                    "#{element.name}_wrapper"
         | 
| 97 | 
            +
                    :"#{element.name}_wrapper"
         | 
| 97 98 | 
             
                  end
         | 
| 98 99 | 
             
                end
         | 
| 99 100 |  | 
| 101 | 
            +
                # @private Sequence types
         | 
| 102 | 
            +
                SEQUENCE_TYPES = [Types::Sequence, Types::SequenceOf, Types::Set, Types::SetOf].freeze
         | 
| 103 | 
            +
             | 
| 100 104 | 
             
                # Define helper methods to define models
         | 
| 101 105 | 
             
                module Accel
         | 
| 102 106 | 
             
                  # @return [Hash]
         | 
| @@ -107,7 +111,7 @@ module RASN1 | |
| 107 111 | 
             
                  # @param [Class] model_klass
         | 
| 108 112 | 
             
                  # @return [Elem]
         | 
| 109 113 | 
             
                  def model(name, model_klass)
         | 
| 110 | 
            -
                    @root =  | 
| 114 | 
            +
                    @root = ModelElem.new(name, model_klass)
         | 
| 111 115 | 
             
                  end
         | 
| 112 116 |  | 
| 113 117 | 
             
                  # Use a {Wrapper} around a {Types::Base} or a {Model} object
         | 
| @@ -162,7 +166,7 @@ module RASN1 | |
| 162 166 | 
             
                        proc = proc do |opts|
         | 
| 163 167 | 
             
                          #{klass}.new(options.merge(opts)) # Sequence.new(options.merge(opts))
         | 
| 164 168 | 
             
                        end
         | 
| 165 | 
            -
                        @root =  | 
| 169 | 
            +
                        @root = BaseElem.new(name, proc, options[:content])
         | 
| 166 170 | 
             
                      end
         | 
| 167 171 | 
             
                    EVAL
         | 
| 168 172 | 
             
                  end
         | 
| @@ -179,7 +183,7 @@ module RASN1 | |
| 179 183 | 
             
                        proc = proc do |opts|
         | 
| 180 184 | 
             
                          #{klass}.new(type, options.merge(opts)) # SequenceOf.new(type, options.merge(opts))
         | 
| 181 185 | 
             
                        end
         | 
| 182 | 
            -
                        @root =  | 
| 186 | 
            +
                        @root = BaseElem.new(name, proc, nil)
         | 
| 183 187 | 
             
                      end
         | 
| 184 188 | 
             
                    EVAL
         | 
| 185 189 | 
             
                  end
         | 
| @@ -206,7 +210,7 @@ module RASN1 | |
| 206 210 | 
             
                  def objectid(name, options={})
         | 
| 207 211 | 
             
                    options[:name] = name
         | 
| 208 212 | 
             
                    proc = proc { |opts| Types::ObjectId.new(options.merge(opts)) }
         | 
| 209 | 
            -
                    @root =  | 
| 213 | 
            +
                    @root = BaseElem.new(name, proc, nil)
         | 
| 210 214 | 
             
                  end
         | 
| 211 215 |  | 
| 212 216 | 
             
                  # @param [Symbol,String] name name of object in model
         | 
| @@ -216,7 +220,7 @@ module RASN1 | |
| 216 220 | 
             
                  def any(name, options={})
         | 
| 217 221 | 
             
                    options[:name] = name
         | 
| 218 222 | 
             
                    proc = proc { |opts| Types::Any.new(options.merge(opts)) }
         | 
| 219 | 
            -
                    @root =  | 
| 223 | 
            +
                    @root = BaseElem.new(name, proc, nil)
         | 
| 220 224 | 
             
                  end
         | 
| 221 225 |  | 
| 222 226 | 
             
                  # Give type name (aka class name)
         | 
| @@ -366,19 +370,26 @@ module RASN1 | |
| 366 370 | 
             
                  self.define_type_accel_base(method_name, prim)
         | 
| 367 371 | 
             
                end
         | 
| 368 372 |  | 
| 373 | 
            +
                # @return [Model, Wrapper, Types::Base]
         | 
| 374 | 
            +
                attr_reader :root
         | 
| 375 | 
            +
             | 
| 369 376 | 
             
                # Create a new instance of a {Model}
         | 
| 370 377 | 
             
                # @param [Hash] args
         | 
| 371 378 | 
             
                def initialize(args={})
         | 
| 372 | 
            -
                   | 
| 373 | 
            -
                   | 
| 374 | 
            -
                   | 
| 379 | 
            +
                  @elements = {}
         | 
| 380 | 
            +
                  generate_root(args)
         | 
| 381 | 
            +
                  lazy_initialize(args) unless args.empty?
         | 
| 375 382 | 
             
                end
         | 
| 376 383 |  | 
| 377 | 
            -
                #  | 
| 378 | 
            -
                # @param [ | 
| 379 | 
            -
                # @return [Types::Base]
         | 
| 384 | 
            +
                # Access an element of the model by its name
         | 
| 385 | 
            +
                # @param [Symbol] name
         | 
| 386 | 
            +
                # @return [Model, Types::Base, Wrapper]
         | 
| 380 387 | 
             
                def [](name)
         | 
| 381 | 
            -
                  @elements[name]
         | 
| 388 | 
            +
                  elt = @elements[name]
         | 
| 389 | 
            +
                  return elt unless elt.is_a?(Proc)
         | 
| 390 | 
            +
             | 
| 391 | 
            +
                  # Lazy element -> generate it
         | 
| 392 | 
            +
                  @elements[name] = elt.call
         | 
| 382 393 | 
             
                end
         | 
| 383 394 |  | 
| 384 395 | 
             
                # Set value of element +name+. Element should be a {Types::Base}.
         | 
| @@ -386,13 +397,20 @@ module RASN1 | |
| 386 397 | 
             
                # @param [Object] value
         | 
| 387 398 | 
             
                # @return [Object] value
         | 
| 388 399 | 
             
                def []=(name, value)
         | 
| 389 | 
            -
                   | 
| 400 | 
            +
                  # Here, use #[] to force generation for lazy elements
         | 
| 401 | 
            +
                  raise Error, 'cannot set value for a Model' if self[name].is_a?(Model)
         | 
| 402 | 
            +
             | 
| 403 | 
            +
                  self[name].value = value
         | 
| 404 | 
            +
                end
         | 
| 390 405 |  | 
| 391 | 
            -
             | 
| 406 | 
            +
                # clone @elements and initialize @root from this new @element.
         | 
| 407 | 
            +
                def initialize_copy(_other)
         | 
| 408 | 
            +
                  @elements = @elements.clone
         | 
| 409 | 
            +
                  @root = @elements[@root_name]
         | 
| 392 410 | 
             
                end
         | 
| 393 411 |  | 
| 394 | 
            -
                #  | 
| 395 | 
            -
                # @return [String | 
| 412 | 
            +
                # Give model name (a.k.a root name)
         | 
| 413 | 
            +
                # @return [String]
         | 
| 396 414 | 
             
                def name
         | 
| 397 415 | 
             
                  @root_name
         | 
| 398 416 | 
             
                end
         | 
| @@ -409,12 +427,6 @@ module RASN1 | |
| 409 427 | 
             
                  private_to_h
         | 
| 410 428 | 
             
                end
         | 
| 411 429 |  | 
| 412 | 
            -
                # Get root element from model
         | 
| 413 | 
            -
                # @return [Types::Base,Model]
         | 
| 414 | 
            -
                def root
         | 
| 415 | 
            -
                  @elements[@root_name]
         | 
| 416 | 
            -
                end
         | 
| 417 | 
            -
             | 
| 418 430 | 
             
                # @return [String]
         | 
| 419 431 | 
             
                def to_der
         | 
| 420 432 | 
             
                  root.to_der
         | 
| @@ -427,12 +439,18 @@ module RASN1 | |
| 427 439 | 
             
                end
         | 
| 428 440 |  | 
| 429 441 | 
             
                # Parse a DER/BER encoded string, and modify object in-place.
         | 
| 430 | 
            -
                # @param [String]  | 
| 442 | 
            +
                # @param [String] der
         | 
| 431 443 | 
             
                # @param [Boolean] ber accept BER encoding or not
         | 
| 432 444 | 
             
                # @return [Integer] number of parsed bytes
         | 
| 433 445 | 
             
                # @raise [ASN1Error] error on parsing
         | 
| 434 | 
            -
                def parse!( | 
| 435 | 
            -
                  root.parse!( | 
| 446 | 
            +
                def parse!(der, ber: false)
         | 
| 447 | 
            +
                  root.parse!(der, ber: ber)
         | 
| 448 | 
            +
                end
         | 
| 449 | 
            +
             | 
| 450 | 
            +
                # @private
         | 
| 451 | 
            +
                # @see Types::Base#do_parse
         | 
| 452 | 
            +
                def do_parse(der, ber: false)
         | 
| 453 | 
            +
                  root.do_parse(der, ber: ber)
         | 
| 436 454 | 
             
                end
         | 
| 437 455 |  | 
| 438 456 | 
             
                # @overload value
         | 
| @@ -474,11 +492,13 @@ module RASN1 | |
| 474 492 | 
             
                  end
         | 
| 475 493 | 
             
                end
         | 
| 476 494 |  | 
| 495 | 
            +
                # Return a hash image of model
         | 
| 496 | 
            +
                # @return [Hash]
         | 
| 477 497 | 
             
                # Delegate some methods to root element
         | 
| 478 498 | 
             
                # @param [Symbol] meth
         | 
| 479 | 
            -
                def method_missing(meth, *args)
         | 
| 480 | 
            -
                  if root.respond_to? | 
| 481 | 
            -
                    root.send | 
| 499 | 
            +
                def method_missing(meth, *args, **kwargs)
         | 
| 500 | 
            +
                  if root.respond_to?(meth)
         | 
| 501 | 
            +
                    root.send(meth, *args, **kwargs)
         | 
| 482 502 | 
             
                  else
         | 
| 483 503 | 
             
                    super
         | 
| 484 504 | 
             
                  end
         | 
| @@ -491,7 +511,7 @@ module RASN1 | |
| 491 511 |  | 
| 492 512 | 
             
                # @return [String]
         | 
| 493 513 | 
             
                def inspect(level=0)
         | 
| 494 | 
            -
                  '  ' * level | 
| 514 | 
            +
                  "#{'  ' * level}(#{type}) #{root.inspect(-level)}"
         | 
| 495 515 | 
             
                end
         | 
| 496 516 |  | 
| 497 517 | 
             
                # Objects are equal if they have same class AND same DER
         | 
| @@ -503,112 +523,97 @@ module RASN1 | |
| 503 523 |  | 
| 504 524 | 
             
                protected
         | 
| 505 525 |  | 
| 506 | 
            -
                #  | 
| 507 | 
            -
                # @param [ | 
| 508 | 
            -
                # @return [ | 
| 509 | 
            -
                def  | 
| 510 | 
            -
                   | 
| 511 | 
            -
                   | 
| 526 | 
            +
                # Initialize model elements from +args+
         | 
| 527 | 
            +
                # @param [Hash,Array] args
         | 
| 528 | 
            +
                # @return [void]
         | 
| 529 | 
            +
                def lazy_initialize(args)
         | 
| 530 | 
            +
                  case args
         | 
| 531 | 
            +
                  when Hash
         | 
| 532 | 
            +
                    lazy_initialize_hash(args)
         | 
| 533 | 
            +
                  when Array
         | 
| 534 | 
            +
                    lazy_initialize_array(args)
         | 
| 535 | 
            +
                  end
         | 
| 536 | 
            +
                end
         | 
| 512 537 |  | 
| 513 | 
            -
             | 
| 514 | 
            -
             | 
| 515 | 
            -
             | 
| 516 | 
            -
             | 
| 517 | 
            -
             | 
| 538 | 
            +
                # Initialize an element from a hash
         | 
| 539 | 
            +
                # @param [Hash] args
         | 
| 540 | 
            +
                # @return [void]
         | 
| 541 | 
            +
                def lazy_initialize_hash(args)
         | 
| 542 | 
            +
                  args.each do |name, value|
         | 
| 543 | 
            +
                    element = self[name]
         | 
| 544 | 
            +
                    case element
         | 
| 545 | 
            +
                    when Model
         | 
| 546 | 
            +
                      element.lazy_initialize(value)
         | 
| 547 | 
            +
                    when nil
         | 
| 548 | 
            +
                    else
         | 
| 549 | 
            +
                      element.value = value
         | 
| 518 550 | 
             
                    end
         | 
| 519 551 | 
             
                  end
         | 
| 520 | 
            -
             | 
| 521 | 
            -
                  nil
         | 
| 522 552 | 
             
                end
         | 
| 523 553 |  | 
| 524 | 
            -
                 | 
| 525 | 
            -
             | 
| 526 | 
            -
                 | 
| 527 | 
            -
             | 
| 528 | 
            -
             | 
| 554 | 
            +
                # Initialize an sequence element from an array
         | 
| 555 | 
            +
                # @param [Array] args
         | 
| 556 | 
            +
                # @return [void]
         | 
| 557 | 
            +
                def lazy_initialize_array(ary)
         | 
| 558 | 
            +
                  raise Error, 'Only sequence types may be initialized with an array' unless SEQUENCE_TYPES.any? { |klass| root.is_a?(klass) }
         | 
| 529 559 |  | 
| 530 | 
            -
             | 
| 531 | 
            -
             | 
| 532 | 
            -
                # * class: a model
         | 
| 533 | 
            -
                def get_type(proc_or_class, options={})
         | 
| 534 | 
            -
                  case proc_or_class
         | 
| 535 | 
            -
                  when Proc
         | 
| 536 | 
            -
                    proc_or_class.call(options)
         | 
| 537 | 
            -
                  when Class
         | 
| 538 | 
            -
                    proc_or_class.new(options)
         | 
| 560 | 
            +
                  ary.each do |initializer|
         | 
| 561 | 
            +
                    root << initializer
         | 
| 539 562 | 
             
                  end
         | 
| 540 563 | 
             
                end
         | 
| 541 564 |  | 
| 542 | 
            -
                 | 
| 543 | 
            -
             | 
| 544 | 
            -
             | 
| 545 | 
            -
             | 
| 546 | 
            -
                   | 
| 547 | 
            -
             | 
| 548 | 
            -
                                            generate_wrapper(class_element)
         | 
| 549 | 
            -
                                          else
         | 
| 550 | 
            -
                                            get_type(class_element.proc_or_class, self.class.options || {})
         | 
| 551 | 
            -
                                          end
         | 
| 552 | 
            -
                  class_element
         | 
| 553 | 
            -
                end
         | 
| 554 | 
            -
             | 
| 555 | 
            -
                def generate_elements(element)
         | 
| 556 | 
            -
                  if element.is_a?(WrapElem)
         | 
| 557 | 
            -
                    generate_wrapper(element)
         | 
| 558 | 
            -
                    return
         | 
| 559 | 
            -
                  end
         | 
| 560 | 
            -
                  return unless element.content.is_a? Array
         | 
| 565 | 
            +
                # Give a (nested) element from its name
         | 
| 566 | 
            +
                # @param [String, Symbol] name
         | 
| 567 | 
            +
                # @return [Model, Types::Base, nil]
         | 
| 568 | 
            +
                def by_name(name)
         | 
| 569 | 
            +
                  elt = self[name]
         | 
| 570 | 
            +
                  return elt unless elt.nil?
         | 
| 561 571 |  | 
| 562 | 
            -
                  @elements | 
| 563 | 
            -
                     | 
| 572 | 
            +
                  @elements.each_value do |subelt|
         | 
| 573 | 
            +
                    next unless subelt.is_a?(Model)
         | 
| 574 | 
            +
             | 
| 575 | 
            +
                    value = subelt.by_name(name)
         | 
| 576 | 
            +
                    return value unless value.nil?
         | 
| 564 577 | 
             
                  end
         | 
| 565 | 
            -
                end
         | 
| 566 578 |  | 
| 567 | 
            -
             | 
| 568 | 
            -
                  inner_elem = wrap_elem.element
         | 
| 569 | 
            -
                  subel = add_subelement(inner_elem)
         | 
| 570 | 
            -
                  Wrapper.new(subel, wrap_elem.options)
         | 
| 579 | 
            +
                  nil
         | 
| 571 580 | 
             
                end
         | 
| 572 581 |  | 
| 573 | 
            -
                 | 
| 574 | 
            -
             | 
| 575 | 
            -
             | 
| 576 | 
            -
             | 
| 577 | 
            -
             | 
| 578 | 
            -
             | 
| 579 | 
            -
             | 
| 582 | 
            +
                private
         | 
| 583 | 
            +
             | 
| 584 | 
            +
                def generate_root(args)
         | 
| 585 | 
            +
                  opts = args.slice(:explicit, :implicit, :optional, :class, :default, :constructed, :tag_value)
         | 
| 586 | 
            +
                  root = self.class.class_eval { @root }
         | 
| 587 | 
            +
                  root_options = self.class.options || {}
         | 
| 588 | 
            +
                  root_options.merge!(opts)
         | 
| 589 | 
            +
                  @root = generate_element(root, root_options)
         | 
| 590 | 
            +
                  @root_name = root.name
         | 
| 591 | 
            +
                  @elements[root.name] = @root
         | 
| 592 | 
            +
                end
         | 
| 593 | 
            +
             | 
| 594 | 
            +
                def generate_element(elt, opts={})
         | 
| 595 | 
            +
                  case elt
         | 
| 596 | 
            +
                  when BaseElem
         | 
| 597 | 
            +
                    generate_base_element(elt, opts)
         | 
| 598 | 
            +
                  when ModelElem
         | 
| 599 | 
            +
                    elt.klass.new(opts)
         | 
| 580 600 | 
             
                  when WrapElem
         | 
| 581 | 
            -
                     | 
| 601 | 
            +
                    wrapped = elt.element.is_a?(ModelElem) ? elt.element.klass : generate_element(elt.element)
         | 
| 602 | 
            +
                    wrapper = Wrapper.new(wrapped, elt.options.merge(opts))
         | 
| 603 | 
            +
                    @elements[elt.element.name] = proc { wrapper.element }
         | 
| 604 | 
            +
                    wrapper
         | 
| 582 605 | 
             
                  end
         | 
| 583 606 | 
             
                end
         | 
| 584 607 |  | 
| 585 | 
            -
                def  | 
| 586 | 
            -
                   | 
| 587 | 
            -
             | 
| 588 | 
            -
                    next unless subobj
         | 
| 589 | 
            -
             | 
| 590 | 
            -
                    case value
         | 
| 591 | 
            -
                    when Hash
         | 
| 592 | 
            -
                      raise ArgumentError, "element #{name}: may only pass a Hash for Model elements" unless subobj.is_a?(Model)
         | 
| 593 | 
            -
             | 
| 594 | 
            -
                      initialize_elements(subobj, value)
         | 
| 595 | 
            -
                    when Array
         | 
| 596 | 
            -
                      initialize_element_from_array(subobj, value)
         | 
| 597 | 
            -
                    else
         | 
| 598 | 
            -
                      subobj.value = value
         | 
| 599 | 
            -
                    end
         | 
| 600 | 
            -
                  end
         | 
| 601 | 
            -
                end
         | 
| 608 | 
            +
                def generate_base_element(elt, opts)
         | 
| 609 | 
            +
                  element = elt.proc.call(opts)
         | 
| 610 | 
            +
                  return element if elt.content.nil?
         | 
| 602 611 |  | 
| 603 | 
            -
             | 
| 604 | 
            -
             | 
| 605 | 
            -
             | 
| 606 | 
            -
                    value.each do |el|
         | 
| 607 | 
            -
                      composed << initialize_elements(composed.of_type.class.new, el)
         | 
| 608 | 
            -
                    end
         | 
| 609 | 
            -
                  else
         | 
| 610 | 
            -
                    value.each { |el| composed << el }
         | 
| 612 | 
            +
                  element.value = elt.content.map do |subel|
         | 
| 613 | 
            +
                    generated = generate_element(subel)
         | 
| 614 | 
            +
                    @elements[subel.name] = generated
         | 
| 611 615 | 
             
                  end
         | 
| 616 | 
            +
                  element
         | 
| 612 617 | 
             
                end
         | 
| 613 618 |  | 
| 614 619 | 
             
                def private_to_h(element=nil) # rubocop:disable Metrics/CyclomaticComplexity
         | 
| @@ -638,29 +643,31 @@ module RASN1 | |
| 638 643 |  | 
| 639 644 | 
             
                def sequence_of_to_h(elt)
         | 
| 640 645 | 
             
                  if elt.of_type < Model
         | 
| 641 | 
            -
                    elt.value | 
| 646 | 
            +
                    elt.value&.map { |el| el.to_h.values.first }
         | 
| 642 647 | 
             
                  else
         | 
| 643 | 
            -
                    elt.value | 
| 648 | 
            +
                    elt.value&.map { |el| private_to_h(el) }
         | 
| 644 649 | 
             
                  end
         | 
| 645 650 | 
             
                end
         | 
| 646 651 |  | 
| 647 652 | 
             
                def sequence_to_h(seq)
         | 
| 648 | 
            -
                  ary = seq.value | 
| 653 | 
            +
                  ary = seq.value&.map do |el|
         | 
| 649 654 | 
             
                    next if el.optional? && el.value.nil?
         | 
| 650 655 |  | 
| 651 656 | 
             
                    case el
         | 
| 652 657 | 
             
                    when Model
         | 
| 653 658 | 
             
                      hsh = el.to_h
         | 
| 654 | 
            -
                       | 
| 655 | 
            -
                      [@elements.key(el), hsh]
         | 
| 659 | 
            +
                      [@elements.key(el), hsh[hsh.keys.first]]
         | 
| 656 660 | 
             
                    when Wrapper
         | 
| 657 | 
            -
                      [@elements.key(el | 
| 661 | 
            +
                      [unwrap_keyname(@elements.key(el)), wrapper_to_h(el)]
         | 
| 658 662 | 
             
                    else
         | 
| 659 663 | 
             
                      [el.name, private_to_h(el)]
         | 
| 660 664 | 
             
                    end
         | 
| 661 665 | 
             
                  end
         | 
| 662 | 
            -
                  ary.compact | 
| 663 | 
            -
             | 
| 666 | 
            +
                  ary.compact.to_h
         | 
| 667 | 
            +
                end
         | 
| 668 | 
            +
             | 
| 669 | 
            +
                def unwrap_keyname(key)
         | 
| 670 | 
            +
                  key.to_s.delete_suffix('_wrapper').to_sym
         | 
| 664 671 | 
             
                end
         | 
| 665 672 |  | 
| 666 673 | 
             
                def wrapper_to_h(wrap)
         | 
    
        data/lib/rasn1/tracer.rb
    CHANGED
    
    | @@ -83,8 +83,8 @@ module RASN1 | |
| 83 83 | 
             
                  # @private
         | 
| 84 84 | 
             
                  # Parse +der+ with tracing abillity
         | 
| 85 85 | 
             
                  # @see #parse!
         | 
| 86 | 
            -
                  def do_parse_with_tracing(der, ber)
         | 
| 87 | 
            -
                    ret = do_parse_without_tracing(der, ber)
         | 
| 86 | 
            +
                  def do_parse_with_tracing(der, ber:)
         | 
| 87 | 
            +
                    ret = do_parse_without_tracing(der, ber: ber)
         | 
| 88 88 | 
             
                    RASN1.tracer.trace(self.trace)
         | 
| 89 89 | 
             
                    ret
         | 
| 90 90 | 
             
                  end
         | 
| @@ -131,7 +131,7 @@ module RASN1 | |
| 131 131 | 
             
                    end
         | 
| 132 132 |  | 
| 133 133 | 
             
                    # @private
         | 
| 134 | 
            -
                    # Unpatch {#der_to_value | 
| 134 | 
            +
                    # Unpatch {#der_to_value} to remove tracing ability
         | 
| 135 135 | 
             
                    def stop_tracing
         | 
| 136 136 | 
             
                      alias_method :der_to_value, :der_to_value_without_tracing
         | 
| 137 137 | 
             
                    end
         | 
| @@ -156,7 +156,7 @@ module RASN1 | |
| 156 156 | 
             
                    end
         | 
| 157 157 |  | 
| 158 158 | 
             
                    # @private
         | 
| 159 | 
            -
                    # Unpatch {#der_to_value | 
| 159 | 
            +
                    # Unpatch {#der_to_value} to remove tracing ability
         | 
| 160 160 | 
             
                    def stop_tracing
         | 
| 161 161 | 
             
                      alias_method :der_to_value, :der_to_value_without_tracing
         | 
| 162 162 | 
             
                    end
         | 
    
        data/lib/rasn1/types/any.rb
    CHANGED
    
    | @@ -31,7 +31,7 @@ module RASN1 | |
| 31 31 | 
             
                  # @param [Boolean] ber if +true+, accept BER encoding
         | 
| 32 32 | 
             
                  # @return [Integer] total number of parsed bytes
         | 
| 33 33 | 
             
                  def parse!(der, ber: false)
         | 
| 34 | 
            -
                    total_length, _data = do_parse(der, ber)
         | 
| 34 | 
            +
                    total_length, _data = do_parse(der, ber: ber)
         | 
| 35 35 | 
             
                    total_length
         | 
| 36 36 | 
             
                  end
         | 
| 37 37 |  | 
| @@ -70,7 +70,9 @@ module RASN1 | |
| 70 70 | 
             
                    str << '(ANY) '
         | 
| 71 71 | 
             
                  end
         | 
| 72 72 |  | 
| 73 | 
            -
                   | 
| 73 | 
            +
                  # @private
         | 
| 74 | 
            +
                  # @see Types::Base#do_parse
         | 
| 75 | 
            +
                  def do_parse(der, ber: false)
         | 
| 74 76 | 
             
                    if der.empty?
         | 
| 75 77 | 
             
                      return [0, ''] if optional?
         | 
| 76 78 |  | 
| @@ -78,7 +80,7 @@ module RASN1 | |
| 78 80 | 
             
                    end
         | 
| 79 81 |  | 
| 80 82 | 
             
                    id_size = Types.decode_identifier_octets(der).last
         | 
| 81 | 
            -
                    total_length, = get_data(der[id_size | 
| 83 | 
            +
                    total_length, = get_data(der[id_size..], ber)
         | 
| 82 84 | 
             
                    total_length += id_size
         | 
| 83 85 |  | 
| 84 86 | 
             
                    @no_value = false
         |