aboutsummaryrefslogtreecommitdiffstats
path: root/lib/asn1kit/types.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/asn1kit/types.rb')
-rw-r--r--lib/asn1kit/types.rb183
1 files changed, 183 insertions, 0 deletions
diff --git a/lib/asn1kit/types.rb b/lib/asn1kit/types.rb
new file mode 100644
index 0000000..817c842
--- /dev/null
+++ b/lib/asn1kit/types.rb
@@ -0,0 +1,183 @@
+# coding: ASCII-8BIT
+using ASN1Kit::BERString
+
+module ASN1Kit
+ class Type
+ CONSTRAINT = nil
+
+ class Tag < Struct.new(:tagging, :tag_class, :tag_number)
+ def acceptable_ber_header?(str, offset = 0)
+ tc, tn, constructed, hlen, len = str.get_object(offset)
+ if tc == tag_class && tn == tag_number
+ [constructed, hlen, len]
+ else
+ nil
+ end
+ end
+ end
+ TAG = nil
+
+ class << self
+ def tagging!(tagging, tag_class, tag_number)
+ const_set(:TAG, Tag.new(tagging, tag_class, tag_number))
+ end
+
+ def asn1_tag(tagging, tag_class, tag_number)
+ const_set(:TAG, Tag.new(tagging, tag_class, tag_number))
+ end
+
+ def asn1_alias(name)
+ instance_variable_set(:@alias, name)
+ end
+
+ def tagging(tagging, tag_class, tag_number)
+ ret = Class.new(self)
+ ret.tagging!(tagging, tag_class, tag_number)
+ ret
+ end
+
+ def from_ber(str)
+ list = self::TAG.acceptable_ber_header?(str) or
+ raise EncodingError, "invalid object: %p, %p, %p, %p, %p" % str.get_object(str)
+
+ constructed, hlen, len = list
+ if self::TAG.tagging == :EXPLICIT
+ raise EncodingError, "invalid EXPLICIT tagging encoding" unless constructed
+ c = self
+ while c = c.superclass
+ raise EncodingError, "invalid EXPLICIT tagging: %p" % self unless c < ASN1Kit::Type
+ break unless c::TAG.equal?(self::TAG)
+ end
+ list_inner = c::TAG.acceptable_ber_header?(str, hlen) or
+ raise EncodingError, "invalid EXPLICIT tagging inner object"
+ end
+
+ if len == 0x80
+ from_ber_content(str, 0, nil, true)
+ else
+ from_ber_content(str, 0, len, constructed)
+ end
+ end
+
+ private def from_ber_content(str, offset, len, constructed)
+ raise NotImplementedError, "BER decoding for %p not implemented" % self
+ end
+
+ def check_ber_header(str, expect_con = false, pos: 0)
+ tc, con, tn, len, pos = str.get_object(pos)
+ if tc != self::TAG.tag_class || expect_con != con || tn != self::TAG.tag_number
+ raise "invalid object: %p, %p, %p, %p, %p" % [tc, con, tn, len, pos]
+ end
+ [len, pos]
+ end
+
+ def builtin?
+ false
+ end
+
+ def inspect_abbrev
+ defined?(@alias) ? "<#{@alias}>" : inspect
+ end
+
+ def inspect
+ name = defined?(@alias) ? "(#{@alias}) " : ""
+ type_ancestors = ancestors.drop(1).select { |x| x < Type }
+ baseclass = type_ancestors.find { |x| x.instance_variable_defined?(:@alias) }
+ baseclass ||= type_ancestors.reverse_each.find { |x| x < ASN1Kit::Type }
+ if baseclass
+ if self::TAG != baseclass::TAG
+ prefix = "["
+ if self::TAG.tag_class != :CONTEXT_SPECIFIC
+ prefix << self::TAG.tag_class.to_s << " "
+ end
+ prefix << self::TAG.tag_number.to_s << "] "
+ end
+ bname = baseclass.instance_variable_get(:@alias) || baseclass.name
+ end
+ if body = inspect_inner
+ "<#{name}#{prefix}#{bname} #{body}>"
+ else
+ "<#{name}#{prefix}#{bname}>"
+ end
+ end
+
+ private def inspect_inner() nil end
+ end
+
+ def to_der
+ raise NotImplementedError, "DER encoding for %p not implemented" % self.class
+ end
+
+ private def der_header(len, encoding = :primitive)
+ "".put_object(self.class::TAG.tag_class, self.class::TAG.tag_number, len, encoding)
+ end
+
+ def cast_to(type)
+ raise TypeError, "casting %p value into %p undefined" % [self.class, type]
+ end
+
+ def inspect_abbrev
+ defined?(@alias) ? "{#{@alias}}" : inspect
+ end
+
+ def inspect
+ name = defined?(@alias) ? "(#{@alias})" : ""
+ if body = inspect_inner
+ "{#{name}#{self.class.inspect_abbrev} #{body}}"
+ else
+ "{#{name}#{self.class.inspect_abbrev}}"
+ end
+ end
+
+ def initialize_copy(orig)
+ super
+ # UGHH; Duplicated instances should not have an alias
+ remove_instance_variable(:@alias) if defined?(@alias)
+ end
+
+ private def inspect_inner() defined?(@value) ? @value.inspect : nil end
+ end
+end
+
+module ASN1Kit::Internal
+ module CompileType
+ refine ASN1Kit::Type.singleton_class do
+ def _compile_fixup(state)
+ end
+
+ attr_reader :alias
+ def alias=(value)
+ unreachable if defined?(@alias)
+ @alias = value
+ end
+ end
+
+ refine ASN1Kit::Type do
+ def _compile_fixup(state)
+ end
+
+ attr_reader :alias
+ def alias=(value)
+ unreachable if defined?(@alias)
+ @alias = value
+ end
+ end
+ end
+end
+
+require_relative "types/boolean"
+require_relative "types/integer"
+require_relative "types/bit_string"
+require_relative "types/octet_string"
+require_relative "types/null"
+require_relative "types/object_identifier"
+require_relative "types/real"
+require_relative "types/enumerated"
+require_relative "types/relative_oid"
+require_relative "types/sequence"
+require_relative "types/sequence_of"
+require_relative "types/set"
+require_relative "types/set_of"
+require_relative "types/choice"
+require_relative "types/character_string_types"
+require_relative "types/useful_types"