forked from Logicalis/asn1
-
Notifications
You must be signed in to change notification settings - Fork 3
/
options.go
128 lines (110 loc) · 2.85 KB
/
options.go
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package asn1
import (
"strconv"
"strings"
)
type fieldOptions struct {
universal bool
application bool
explicit bool
indefinite bool
optional bool
set bool
tag *int
defaultValue *int
choice *string
}
// validate returns an error if any option is invalid.
func (opts *fieldOptions) validate() error {
tagError := func(class string) error {
return syntaxError(
"'tag' must be specified when '%s' is used", class)
}
if opts.universal && opts.tag == nil {
return tagError("universal")
}
if opts.application && opts.tag == nil {
return tagError("application")
}
if opts.tag != nil && *opts.tag < 0 {
return syntaxError("'tag' cannot be negative: %d", *opts.tag)
}
if opts.choice != nil && *opts.choice == "" {
return syntaxError("'choice' cannot be empty")
}
return nil
}
// parseOption returns a parsed fieldOptions or an error. Returns nil for the ignore tag "-".
func parseOptions(s string) (*fieldOptions, error) {
if s == "-" {
return nil, nil
}
var opts fieldOptions
for _, token := range strings.Split(s, ",") {
args := strings.Split(strings.TrimSpace(token), ":")
err := parseOption(&opts, args)
if err != nil {
return nil, err
}
}
if err := opts.validate(); err != nil {
return nil, err
}
return &opts, nil
}
// parseOption parse a single option.
func parseOption(opts *fieldOptions, args []string) error {
var err error
switch args[0] {
case "":
// ignore
case "universal":
opts.universal, err = parseBoolOption(args)
case "application":
opts.application, err = parseBoolOption(args)
case "explicit":
opts.explicit, err = parseBoolOption(args)
case "indefinite":
opts.indefinite, err = parseBoolOption(args)
case "optional":
opts.optional, err = parseBoolOption(args)
case "set":
opts.set, err = parseBoolOption(args)
case "tag":
opts.tag, err = parseIntOption(args)
case "default":
opts.defaultValue, err = parseIntOption(args)
case "choice":
opts.choice, err = parseStringOption(args)
default:
err = syntaxError("Invalid option: %s", args[0])
}
return err
}
// parseBoolOption just checks if no arguments were given.
func parseBoolOption(args []string) (bool, error) {
if len(args) > 1 {
return false, syntaxError("option '%s' does not have arguments.",
args[0])
}
return true, nil
}
// parseIntOption parses an integer argument.
func parseIntOption(args []string) (*int, error) {
if len(args) != 2 {
return nil, syntaxError("option '%s' does not have arguments.")
}
num, err := strconv.Atoi(args[1])
if err != nil {
return nil, syntaxError("invalid value '%s' for option '%s'.",
args[1], args[0])
}
return &num, nil
}
// parseStringOption parses a string argument.
func parseStringOption(args []string) (*string, error) {
if len(args) != 2 {
return nil, syntaxError("option '%s' does not have arguments.")
}
return &args[1], nil
}