From bc98bd8adb81c9b98ddb81fc2b7e96ceb83343ad Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Tue, 28 Feb 2017 02:16:33 +0900 Subject: wip --- lib/asn1kit/types/integer.rb | 87 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 lib/asn1kit/types/integer.rb (limited to 'lib/asn1kit/types/integer.rb') diff --git a/lib/asn1kit/types/integer.rb b/lib/asn1kit/types/integer.rb new file mode 100644 index 0000000..9104a5d --- /dev/null +++ b/lib/asn1kit/types/integer.rb @@ -0,0 +1,87 @@ +# coding: ASCII-8BIT + +class ASN1Kit::Integer < ASN1Kit::Type + asn1_tag :IMPLICIT, :UNIVERSAL, 2 + asn1_alias "INTEGER" + + NAMED_NUMBERS = {} + NAMED_NUMBERS_INVERTED = {} + + class << self + def [](*named_numbers) + return self if named_numbers.empty? + ret = Class.new(self) + hash = named_numbers.to_h + hash_inverted = hash.invert + raise "duplicate name(s) in named number list" if named_numbers.size != hash.size + raise "duplicate value(s) in named number list" if hash.size != hash_inverted.size + ret.const_set(:NAMED_NUMBERS, hash) + ret.const_set(:NAMED_NUMBERS_INVERTED, hash.invert) + ret + end + + def named_number(name) + self::NAMED_NUMBERS[name] + end + + def named_numbers + self::NAMED_NUMBERS.keys + end + + private def inspect_inner + return nil if self::NAMED_NUMBERS.empty? + nns = self::NAMED_NUMBERS.map { |name, value| "#{name}(#{value})" }.join(", ") + "{ #{nns} }" + end + end + + attr_reader :value + + def initialize(value) + case value + when Integer + @value = value + when String + @value = self.class::NAMED_NUMBERS[value] or + raise ArgumentError, "invalid name %p" % value + else + raise TypeError, "invalid value: %p (expected an Integer or a NamedValue label)" % value + end + end + + def name + self.class::NAMED_NUMBERS_INVERTED[@value] + end + + def to_der + v = @value + if v >= 0 + dig = v.digits(256) + dig << 0x00 if dig[-1] >= 0x80 + s = dig.pack("C*").reverse + else + v = ~v + dig = v.digits(256) + dig << 0x00 if dig[-1] >= 0x80 + s = dig.map!(&:~).pack("C*").reverse + end + der_header(s.bytesize) << s + end + + def ==(other) + other.class <= ASN1Kit::Integer && value == other.value + end + + def cast_to(type) + return type.new(@value) if type <= ASN1Kit::Integer + super + end + + private def inspect_inner + if n = name + "#{@value}(#{n})" + else + "#{@value}" + end + end +end -- cgit v1.2.3