aboutsummaryrefslogtreecommitdiffstats
path: root/lib/asn1kit/types/sequence.rb
blob: 2fbf530dc3d47a6f8697be225c89b0ffae1ae72e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# coding: ASCII-8BIT

class ASN1Kit::Sequence < ASN1Kit::Type
  asn1_tag :IMPLICIT, :UNIVERSAL, 16
  asn1_alias "SEQUENCE"

  class ComponentType
    attr_reader :name, :type, :default

    def optional?
      @optional
    end

    def initialize(name, type, default: nil, optional: false)
      @name = name
      @type = type
      @default = default
      @optional = optional
    end

    def inspect
      str = "#{name} #{type.inspect_abbrev}"
      str << " DEFAULT #{default.inspect_abbrev}" if default
      str << " OPTIONAL" if optional?
      str
    end
  end

  class << self
    def [](*component_types)
      ret = Class.new(self)
      hash = component_types.map { |c| [c.name, c] }.to_h
      ret.const_set(:COMPONENT_TYPES, hash)
      ret
    end

    def component_types
      self::COMPONENT_TYPES.keys
    end

    def component_type(name)
      self::COMPONENT_TYPES[name]&.type
    end

    private def inspect_inner
      ctypes = self::COMPONENT_TYPES.values.map { |c| c.inspect }.join(", ")
      "{ #{ctypes} }"
    end

    # def pretty_print(q)
    #   nil
    # end

    def from_ber(str)
      ssize = str.bytesize
      , pos = check_ber_header(str, constructed: true)
      hash = {}
      last = nil
      self::COMPONENT_TYPES.each do |c|
        last ||= str.get_object(pos)
        if c.optional?
          next if a
        end
      end
    end
  end

  def initialize(value)
    unless defined?(self.class::COMPONENT_TYPES)
      raise "unable to instantiate uninitialized SEQUENCE"
    end
    @value = value
  end

  def [](name)
    unless self.class::COMPONENT_TYPES[name]
      raise ArgumentError, "invalid component type name: %p" % name
    end
    @value[name]
  end

  def to_der
    content = self.class::COMPONENT_TYPES.map { |name, type, opts|
      next nil unless @value[name]
      @value[name].to_der
    }.compact.join
    der_header(content.bytesize, :constructed) << content
  end
end

module ASN1Kit::Internal::CompileSequence
  refine ASN1Kit::Sequence::ComponentType do
    attr_writer :name, :type, :default, :optional
  end

  refine ASN1Kit::Sequence.singleton_class do
    def _compile_fixup(state)
      self::COMPONENT_TYPES.each do |name, c|
        if c.type.is_a?(ASN1Kit::Internal::TypeReference)
          c.type = c.type.unwrap(state)
        end
        state.resolve(c.type)
        if c.default
          c.default.type = c.type # opts[:default] may be still TypeReference at this time
          c.default = c.default.unwrap(state)
          state.resolve(c.default)
        end
      end
    end
  end

  refine ASN1Kit::Sequence do
    def _compile_fixup(state)
      @value.transform_values! do |value|
        value = value.unwrap(state)
        state.resolve(value)
        value
      end
    end
  end
end