v2 / vlib / x / encoding / asn1 / ia5string.v
101 lines · 85 sloc · 2.49 KB · 897ec51480ee51714f03534117f603eb28dae7fa
Raw
1// Copyright (c) 2022, 2024 blackshirt. All rights reserved.
2// Use of this source code is governed by a MIT License
3// that can be found in the LICENSE file.
4module asn1
5
6// default_ia5string_tag is the default tag of ASN.1 IA5STRING type.
7pub const default_ia5string_tag = Tag{.universal, false, int(TagType.ia5string)}
8
9// ASN.1 IA5String type handling routine.
10// IA5String is a standard ASCII characters
11pub struct IA5String {
12pub:
13 value string
14}
15
16// new creates a IA5String element from string s.
17pub fn IA5String.new(s string) !IA5String {
18 if !valid_ia5string(s) {
19 return error('IA5String: contains non-ascii chars')
20 }
21 return IA5String{
22 value: s
23 }
24}
25
26// tag returns the tag of IA5String type element.
27pub fn (v IA5String) tag() Tag {
28 return default_ia5string_tag
29}
30
31// payload returns the payload of IA5String type element.
32pub fn (v IA5String) payload() ![]u8 {
33 if !v.value.is_ascii() {
34 return error('IA5String: contains non-ascii chars')
35 }
36 return v.value.bytes()
37}
38
39fn (v IA5String) str() string {
40 if v.value.len == 0 {
41 return 'IA5String (<empty>)'
42 }
43 return 'IA5String (${v.value})'
44}
45
46fn IA5String.parse(mut p Parser) !IA5String {
47 tag := p.read_tag()!
48 if !tag.equal(default_ia5string_tag) {
49 return error('Bad Ia5String tag')
50 }
51 length := p.read_length()!
52 bytes := p.read_bytes(length)!
53
54 res := IA5String.from_bytes(bytes)!
55
56 return res
57}
58
59fn IA5String.decode(bytes []u8) !(IA5String, int) {
60 bs, next := IA5String.decode_with_rule(bytes, .der)!
61 return bs, next
62}
63
64fn IA5String.decode_with_rule(bytes []u8, rule EncodingRule) !(IA5String, int) {
65 tag, length_pos := Tag.decode_with_rule(bytes, 0, rule)!
66 if !tag.equal(default_ia5string_tag) {
67 return error('Unexpected non-ia5string tag')
68 }
69 length, content_pos := Length.decode_with_rule(bytes, length_pos, rule)!
70
71 // if the length is 0, this mean if the payload is empty
72 // otherwise, check for bound
73 content := if length == 0 {
74 []u8{}
75 } else {
76 if content_pos >= bytes.len || content_pos + length > bytes.len {
77 return error('IA5String: truncated payload bytes')
78 }
79 unsafe { bytes[content_pos..content_pos + length] }
80 }
81
82 result := IA5String.from_bytes(content)!
83 next := content_pos + length
84
85 return result, next
86}
87
88// from_bytes creates a new IA5String from bytes b
89fn IA5String.from_bytes(b []u8) !IA5String {
90 if b.any(it < u8(` `) || it > u8(`~`)) {
91 return error('IA5String: bytes contains non-ascii chars')
92 }
93 return IA5String{
94 value: b.bytestr()
95 }
96}
97
98// Utility function
99fn valid_ia5string(s string) bool {
100 return s.is_ascii()
101}
102