diff options
Diffstat (limited to 'lib/asn1kit/types.rb')
-rw-r--r-- | lib/asn1kit/types.rb | 183 |
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" |