aboutsummaryrefslogtreecommitdiffstats
path: root/lib/asn1kit/types/sequence.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/asn1kit/types/sequence.rb')
-rw-r--r--lib/asn1kit/types/sequence.rb121
1 files changed, 121 insertions, 0 deletions
diff --git a/lib/asn1kit/types/sequence.rb b/lib/asn1kit/types/sequence.rb
new file mode 100644
index 0000000..2fbf530
--- /dev/null
+++ b/lib/asn1kit/types/sequence.rb
@@ -0,0 +1,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