-
Notifications
You must be signed in to change notification settings - Fork 0
/
reader.pony
89 lines (71 loc) · 2.07 KB
/
reader.pony
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
use "buffered"
class BeginStruct
let tagclass: U8
let tagnumber: U64
new create(c: U8 = 0, n: U64) => tagclass = c; tagnumber = n
primitive EndStruct
class BerReader
embed _rd: Reader ref = Reader
var count: USize = 0
var stack: Array[USize] = Array[USize]()
fun ref next_octet(): U8? =>
let o = _rd.u8()?
count = count + 1
o
fun ref block(len: USize val): Array[U8 val] iso^ ? =>
let r = _rd.block(len)?
count = count + len
r
fun ref append(data: (String val | Array[U8 val] val)): None val =>
_rd.append(data)
fun ref read_length(): USize? =>
let first_octet = next_octet()?
if first_octet < 0x80 then
first_octet.usize()
elseif first_octet == 0x80 then
error // unimplemented
else
var c = first_octet and 0x7f
var a = USize(0)
while c > 0 do
c = c - 1
a = (a << 8) + next_octet()?.usize()
end
a
end
fun ref read_vlq(): U64? =>
var o: U8
var u = U64(0)
repeat
o = next_octet()?
u = (u << 7) + (o and 0x7f).u64()
until (o and 0x80) == 0 end
u
fun ref read_id(): (Bool, U8, U64)? =>
let first_id_octet = next_octet()?
var constructed: Bool = (first_id_octet and 0x20) == 0x20
var tag_class: U8 = (first_id_octet and 0xc) >> 6
var tag_number: U64 = (first_id_octet and 0x1F).u64()
if tag_number == 0x1F then
tag_number = read_vlq()?
end
(constructed, tag_class, tag_number)
fun ref read_value(): (Asn1ObjectIdentifier | Asn1OctetString | Asn1Integer | BeginStruct | EndStruct)? =>
if (stack.size() > 0) and (count == stack(stack.size()-1)?) then
stack.pop()?
return EndStruct
end
(let constructed, let tag_class, let tag_number) = read_id()?
var c = read_length()?
if constructed then
stack.push(count + c)
BeginStruct(tag_class,tag_number)
else
match tag_number
| 2 => Asn1Integer.from_ber(block(c)?)
| 4 => Asn1OctetString.from_ber(block(c)?)
| 6 => Asn1ObjectIdentifier.from_ber(block(c)?)
else
error
end
end