v/vlib/x/encoding/asn1/parser.v

140 lines
3.7 KiB
V

module asn1
import io
// Parser is ongoing ASN.1 parser.
// Its capables parsing ASN.1 element through availables methods.
pub struct Parser {
mut:
data []u8
}
// new creates a new Parser from bytes array in data.
pub fn Parser.new(data []u8) &Parser {
return &Parser{
data: data
}
}
// reset resets internal data of parser to empty buffer.
pub fn (mut p Parser) reset() {
p.data = unsafe { p.data[..0] }
}
// peek_tag lookups the tag from the parser without updates internal parser data.
pub fn (mut p Parser) peek_tag() !Tag {
tag, _ := Tag.from_bytes(p.data)!
return tag
}
// read_tag lookups the tag from the current parser and updates internal parser data.
pub fn (mut p Parser) read_tag() !Tag {
tag, rest := Tag.from_bytes(p.data)!
p.data = rest
return tag
}
// read_length read the Length from the current parser data.
pub fn (mut p Parser) read_length() !Length {
length, rest := Length.from_bytes(p.data)!
p.data = rest
return length
}
// read_bytes read length bytes from the current parser data.
pub fn (mut p Parser) read_bytes(length int) ![]u8 {
if length > p.data.len {
return error('Parser: too short data to read ${length} bytes')
}
result := p.data[0..length]
rest := if length == p.data.len { []u8{} } else { unsafe { p.data[length..] } }
p.data = rest
return result
}
// BUG: This is not supported with error:
// ```bash
// error: unknown function: asn1.Boolean__static__parse
// 57 | // Note: somes builtin have not this method.
// 58 | fn (mut p Parser) read_element[T]() !T {
// 59 | result := T.parse(mut p)!
// | ~~~~~~~~~~~~~~
// 60 | return result
// 61 | }
// vlib/x/encoding/asn1/parser.v:59:26: error: unexpected `!`,
// the function `T__static__parse` does not return a Result
// 57 | // Note: somes builtin have not this method.
// 58 | fn (mut p Parser) read_element[T]() !T {
// 59 | result := T.parse(mut p)!
// | ^
// 60 | return result
// 61 | }
// vlib/x/encoding/asn1/parser.v:59:9: error: assignment mismatch: 1 variable
// but `T.parse()` returns 0 values
// 57 | // Note: somes builtin have not this method.
// 58 | fn (mut p Parser) read_element[T]() !T {
// 59 | result := T.parse(mut p)!
// | ~~
// 60 | return result
// 61 | }
// ```
// read_element read an element T from the current parser.
// Note: somes builtin have not this method.
// fn (mut p Parser) read_element[T]() !T {
// result := T.parse(mut p)!
// return result
// }
// read_tlv read an Element from the parser data.
// Its return an Element, you should cast it to underlying data if you need.
pub fn (mut p Parser) read_tlv() !Element {
tag := p.read_tag()!
length := p.read_length()!
content := p.read_bytes(length)!
elem := parse_element(tag, content)!
return elem
}
// finish end this parser or error if not empty.
pub fn (mut p Parser) finish() ! {
if !p.is_empty() {
return error('not empty on finish')
}
}
// is_empty checks whether the parser has empty buffer data.
pub fn (mut p Parser) is_empty() bool {
return p.data.len == 0
}
// read_from read up to buf.len bytes from reader r, places them into buf and then appends
// to current Parser data.
fn (mut p Parser) read_from(mut r io.Reader, mut buf []u8) !int {
n := r.read(mut buf)!
p.data << buf
return n
}
fn parse_single[T](data []u8) !T {
mut p := Parser.new(data)!
out := p.read_element[T]()!
return out
}
fn parse[T](data []u8, callback fn (mut p Parser) !T) !T {
mut p := Parser.new(data)
result := callback(mut p)!
p.finish()!
return result
}
/*
fn strip_tlv(data []u8) !(Element, []u8) {
mut p := Parser.new(data)
tlv := p.read_element[Asn1Element]()!
return tlv, p.data
}
*/