v2 / vlib / x / encoding / asn1 / parser.v
139 lines · 121 sloc · 3.66 KB · fdc49dc51a0d7e83abd5b383afaaab3f2793f2cf
Raw
1module asn1
2
3import io
4
5// Parser is ongoing ASN.1 parser.
6// Its capables parsing ASN.1 element through availables methods.
7pub struct Parser {
8mut:
9 data []u8
10}
11
12// new creates a new Parser from bytes array in data.
13pub fn Parser.new(data []u8) &Parser {
14 return &Parser{
15 data: data
16 }
17}
18
19// reset resets internal data of parser to empty buffer.
20pub fn (mut p Parser) reset() {
21 p.data = unsafe { p.data[..0] }
22}
23
24// peek_tag lookups the tag from the parser without updates internal parser data.
25pub fn (mut p Parser) peek_tag() !Tag {
26 tag, _ := Tag.from_bytes(p.data)!
27 return tag
28}
29
30// read_tag lookups the tag from the current parser and updates internal parser data.
31pub fn (mut p Parser) read_tag() !Tag {
32 tag, rest := Tag.from_bytes(p.data)!
33 p.data = rest
34 return tag
35}
36
37// read_length read the Length from the current parser data.
38pub fn (mut p Parser) read_length() !Length {
39 length, rest := Length.from_bytes(p.data)!
40 p.data = rest
41 return length
42}
43
44// read_bytes read length bytes from the current parser data.
45pub fn (mut p Parser) read_bytes(length int) ![]u8 {
46 if length > p.data.len {
47 return error('Parser: too short data to read ${length} bytes')
48 }
49 result := p.data[0..length]
50 rest := if length == p.data.len { []u8{} } else { unsafe { p.data[length..] } }
51 p.data = rest
52 return result
53}
54
55// BUG: This is not supported with error:
56// ```bash
57// error: unknown function: asn1.Boolean__static__parse
58// 57 | // Note: somes builtin have not this method.
59// 58 | fn (mut p Parser) read_element[T]() !T {
60// 59 | result := T.parse(mut p)!
61// | ~~~~~~~~~~~~~~
62// 60 | return result
63// 61 | }
64// vlib/x/encoding/asn1/parser.v:59:26: error: unexpected `!`,
65// the function `T__static__parse` does not return a Result
66// 57 | // Note: somes builtin have not this method.
67// 58 | fn (mut p Parser) read_element[T]() !T {
68// 59 | result := T.parse(mut p)!
69// | ^
70// 60 | return result
71// 61 | }
72// vlib/x/encoding/asn1/parser.v:59:9: error: assignment mismatch: 1 variable
73// but `T.parse()` returns 0 values
74// 57 | // Note: somes builtin have not this method.
75// 58 | fn (mut p Parser) read_element[T]() !T {
76// 59 | result := T.parse(mut p)!
77// | ~~
78// 60 | return result
79// 61 | }
80// ```
81// read_element read an element T from the current parser.
82// Note: somes builtin have not this method.
83// fn (mut p Parser) read_element[T]() !T {
84// result := T.parse(mut p)!
85// return result
86// }
87
88// read_tlv read an Element from the parser data.
89// Its return an Element, you should cast it to underlying data if you need.
90pub fn (mut p Parser) read_tlv() !Element {
91 tag := p.read_tag()!
92 length := p.read_length()!
93 content := p.read_bytes(length)!
94
95 elem := parse_element(tag, content)!
96 return elem
97}
98
99// finish end this parser or error if not empty.
100pub fn (mut p Parser) finish() ! {
101 if !p.is_empty() {
102 return error('not empty on finish')
103 }
104}
105
106// is_empty checks whether the parser has empty buffer data.
107pub fn (mut p Parser) is_empty() bool {
108 return p.data.len == 0
109}
110
111// read_from read up to buf.len bytes from reader r, places them into buf and then appends
112// to current Parser data.
113fn (mut p Parser) read_from(mut r io.Reader, mut buf []u8) !int {
114 n := r.read(mut buf)!
115 p.data << buf
116
117 return n
118}
119
120fn parse_single[T](data []u8) !T {
121 mut p := Parser.new(data)!
122 out := p.read_element[T]()!
123 return out
124}
125
126fn parse[T](data []u8, callback fn (mut p Parser) !T) !T {
127 mut p := Parser.new(data)
128 result := callback(mut p)!
129 p.finish()!
130 return result
131}
132
133/*
134fn strip_tlv(data []u8) !(Element, []u8) {
135 mut p := Parser.new(data)
136 tlv := p.read_element[Asn1Element]()!
137 return tlv, p.data
138}
139*/
140