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
|
# coding: ASCII-8BIT
class ASN1Kit::BitString < ASN1Kit::Type
asn1_tag :IMPLICIT, :UNIVERSAL, 3
asn1_alias "BIT STRING"
NAMED_BITS = {}
NAMED_BITS_INVERTED = {}
class << self
def [](*named_bits)
return self if named_bits.empty?
ret = Class.new(self)
hash = named_bits.to_h
hash_inverted = hash.invert
raise "duplicate name(s) in named bit list" if named_bits.size != hash.size
raise "duplicate value(s) in named bit list" if hash.size != hash_inverted.size
ret.const_set(:NAMED_BITS, hash)
ret.const_set(:NAMED_BITS_INVERTED, hash.invert)
ret
end
def named_bit(name)
self::NAMED_BITS[name]
end
def named_bits
self::NAMED_BITS.keys
end
private def inspect_inner
return nil if self::NAMED_BITS.empty?
nns = self::NAMED_BITS.map { |name, value|
"#{name}(#{value})"
}.join(", ")
"{ #{nns} }"
end
def new_with_names(*list)
if self::NAMED_BITS.empty?
raise TypeError, "BIT STRING without NamedBits defined cannot be " \
"instantiated by #from_names"
end
return new(String.new, 0) if list.empty?
bits = list.map { |name|
named_bit(name) or
raise ArgumentError, "invalid name: %p" % name
}
bit_length = bits.max + 1
str = "0".b * bit_length
bits.each { |pos| str[pos] = "1" }
new([str].pack("B*"), bit_length)
end
end
attr_reader :string, :bit_length
def initialize(str, bit_length)
if bit_length <= (str.bytesize - 1) * 8 || bit_length > str.bytesize * 8
raise ArgumentError, "invalid bit_length"
end
@string = str
@bit_length = bit_length
end
def set?(name_or_pos)
if name_or_pos.is_a?(String)
name_or_pos = self.class.named_bit(name_or_pos)
end
unless name_or_pos.is_a?(::Integer)
raise TypeError, "invalid argument type: %p" % name_or_pos
end
byte = @string.getbyte(name_or_pos / 8)
byte[7 - name_or_pos % 8] == 1
end
def to_der
byte_length = (bit_length / 8r).ceil
unused_bits = byte_length * 8 - bit_length
content = [unused_bits].pack("C") << @string
der_header(byte_length + 1) << content
end
def ==(other)
return false unless other.is_a?(ASN1Kit::BitString)
return false unless self.class::NAMED_BITS.equal?(other.class::NAMED_BITS)
value == other.value && bit_length == other.bit_length
end
end
module ASN1Kit::Internal::CompileBitString
refine ASN1Kit::BitString.singleton_class do
def _compile_fixup(state)
self::NAMED_BITS.transform_values! do |value|
if value.is_a?(ASN1Kit::Internal::UnresolvedValue)
vname = value.value.name
value = state.value_symbols[vname] ||
raise("unresolved value: %s" % vname)
if !value.is_a?(ASN1Kit::Integer)
raise ASN1Kit::ParseError, "DefinedValue in NamedBit resolved to non-integer: %s" % vname
end
if value.value < 0
raise ASN1Kit::ParseError, "DefinedValue in NamedBit resolved to negative integer: %s" % vname
end
value = value.value
end
value
end
end
end
end
|