v2 / vlib / x / encoding / asn1 / numericstring.v
114 lines · 97 sloc · 2.96 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_numericstring_tag is the default tag of ASN.1 NUMERICSTRING type.
7pub const default_numericstring_tag = Tag{.universal, false, int(TagType.numericstring)}
8
9// NumericString.
10//
11// NumericString was restricted character string types
12// restricted to sequences of zero, one or more characters from some
13// specified collection of characters.
14// That was : digit : 0,1,..9 and spaces char (0x20)
15pub struct NumericString {
16pub:
17 value string
18}
19
20// new creates a new NumericString element from string s.
21pub fn NumericString.new(s string) !NumericString {
22 if !all_numeric_string(s.bytes()) {
23 return error('NumericString: contains non-numeric string')
24 }
25 return NumericString{
26 value: s
27 }
28}
29
30// tag returns the tag of NumericString element.
31pub fn (nst NumericString) tag() Tag {
32 return default_numericstring_tag
33}
34
35// payload returns the payload of NumericString element.
36pub fn (nst NumericString) payload() ![]u8 {
37 return nst.payload_with_rule(.der)!
38}
39
40fn (nst NumericString) str() string {
41 if nst.value.len == 0 {
42 return 'NumericString (<empty>)'
43 }
44 return 'NumericString (${nst.value})'
45}
46
47fn (nst NumericString) payload_with_rule(rule EncodingRule) ![]u8 {
48 bytes := nst.value.bytes()
49 if !all_numeric_string(bytes) {
50 return error('NumericString: contains non-numeric string')
51 }
52 if rule != .der && rule != .ber {
53 return error('NumericString: bad rule')
54 }
55 return bytes
56}
57
58fn NumericString.parse(mut p Parser) !NumericString {
59 tag := p.read_tag()!
60 if !tag.equal(default_numericstring_tag) {
61 return error('Bad NumericString tag')
62 }
63 length := p.read_length()!
64 bytes := p.read_bytes(length)!
65
66 res := NumericString.from_bytes(bytes)!
67
68 return res
69}
70
71fn NumericString.from_bytes(bytes []u8) !NumericString {
72 if !all_numeric_string(bytes) {
73 return error('NumericString: contains non-numeric string')
74 }
75 return NumericString{
76 value: bytes.bytestr()
77 }
78}
79
80fn NumericString.decode(bytes []u8) !(NumericString, int) {
81 ns, next := NumericString.decode_with_rule(bytes, .der)!
82 return ns, next
83}
84
85fn NumericString.decode_with_rule(bytes []u8, rule EncodingRule) !(NumericString, int) {
86 tag, length_pos := Tag.decode_with_rule(bytes, 0, rule)!
87 if !tag.equal(default_numericstring_tag) {
88 return error('Unexpected non-numericstring tag')
89 }
90 length, content_pos := Length.decode_with_rule(bytes, length_pos, rule)!
91 content := if length == 0 {
92 []u8{}
93 } else {
94 if content_pos >= bytes.len || content_pos + length > bytes.len {
95 return error('NumericString: truncated payload bytes')
96 }
97 unsafe { bytes[content_pos..content_pos + length] }
98 }
99
100 ns := NumericString.from_bytes(content)!
101 next := content_pos + length
102
103 return ns, next
104}
105
106// Utility function
107//
108fn all_numeric_string(bytes []u8) bool {
109 return bytes.all(is_numericstring(it))
110}
111
112fn is_numericstring(c u8) bool {
113 return c.is_digit() || c == u8(0x20)
114}
115