Mercurial > yakumo_izuru > aya
comparison vendor/gopkg.in/yaml.v2/resolve.go @ 66:787b5ee0289d draft
Use vendored modules
Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>
author | yakumo.izuru |
---|---|
date | Sun, 23 Jul 2023 13:18:53 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
65:6d985efa0f7a | 66:787b5ee0289d |
---|---|
1 package yaml | |
2 | |
3 import ( | |
4 "encoding/base64" | |
5 "math" | |
6 "regexp" | |
7 "strconv" | |
8 "strings" | |
9 "time" | |
10 ) | |
11 | |
12 type resolveMapItem struct { | |
13 value interface{} | |
14 tag string | |
15 } | |
16 | |
17 var resolveTable = make([]byte, 256) | |
18 var resolveMap = make(map[string]resolveMapItem) | |
19 | |
20 func init() { | |
21 t := resolveTable | |
22 t[int('+')] = 'S' // Sign | |
23 t[int('-')] = 'S' | |
24 for _, c := range "0123456789" { | |
25 t[int(c)] = 'D' // Digit | |
26 } | |
27 for _, c := range "yYnNtTfFoO~" { | |
28 t[int(c)] = 'M' // In map | |
29 } | |
30 t[int('.')] = '.' // Float (potentially in map) | |
31 | |
32 var resolveMapList = []struct { | |
33 v interface{} | |
34 tag string | |
35 l []string | |
36 }{ | |
37 {true, yaml_BOOL_TAG, []string{"y", "Y", "yes", "Yes", "YES"}}, | |
38 {true, yaml_BOOL_TAG, []string{"true", "True", "TRUE"}}, | |
39 {true, yaml_BOOL_TAG, []string{"on", "On", "ON"}}, | |
40 {false, yaml_BOOL_TAG, []string{"n", "N", "no", "No", "NO"}}, | |
41 {false, yaml_BOOL_TAG, []string{"false", "False", "FALSE"}}, | |
42 {false, yaml_BOOL_TAG, []string{"off", "Off", "OFF"}}, | |
43 {nil, yaml_NULL_TAG, []string{"", "~", "null", "Null", "NULL"}}, | |
44 {math.NaN(), yaml_FLOAT_TAG, []string{".nan", ".NaN", ".NAN"}}, | |
45 {math.Inf(+1), yaml_FLOAT_TAG, []string{".inf", ".Inf", ".INF"}}, | |
46 {math.Inf(+1), yaml_FLOAT_TAG, []string{"+.inf", "+.Inf", "+.INF"}}, | |
47 {math.Inf(-1), yaml_FLOAT_TAG, []string{"-.inf", "-.Inf", "-.INF"}}, | |
48 {"<<", yaml_MERGE_TAG, []string{"<<"}}, | |
49 } | |
50 | |
51 m := resolveMap | |
52 for _, item := range resolveMapList { | |
53 for _, s := range item.l { | |
54 m[s] = resolveMapItem{item.v, item.tag} | |
55 } | |
56 } | |
57 } | |
58 | |
59 const longTagPrefix = "tag:yaml.org,2002:" | |
60 | |
61 func shortTag(tag string) string { | |
62 // TODO This can easily be made faster and produce less garbage. | |
63 if strings.HasPrefix(tag, longTagPrefix) { | |
64 return "!!" + tag[len(longTagPrefix):] | |
65 } | |
66 return tag | |
67 } | |
68 | |
69 func longTag(tag string) string { | |
70 if strings.HasPrefix(tag, "!!") { | |
71 return longTagPrefix + tag[2:] | |
72 } | |
73 return tag | |
74 } | |
75 | |
76 func resolvableTag(tag string) bool { | |
77 switch tag { | |
78 case "", yaml_STR_TAG, yaml_BOOL_TAG, yaml_INT_TAG, yaml_FLOAT_TAG, yaml_NULL_TAG, yaml_TIMESTAMP_TAG: | |
79 return true | |
80 } | |
81 return false | |
82 } | |
83 | |
84 var yamlStyleFloat = regexp.MustCompile(`^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$`) | |
85 | |
86 func resolve(tag string, in string) (rtag string, out interface{}) { | |
87 if !resolvableTag(tag) { | |
88 return tag, in | |
89 } | |
90 | |
91 defer func() { | |
92 switch tag { | |
93 case "", rtag, yaml_STR_TAG, yaml_BINARY_TAG: | |
94 return | |
95 case yaml_FLOAT_TAG: | |
96 if rtag == yaml_INT_TAG { | |
97 switch v := out.(type) { | |
98 case int64: | |
99 rtag = yaml_FLOAT_TAG | |
100 out = float64(v) | |
101 return | |
102 case int: | |
103 rtag = yaml_FLOAT_TAG | |
104 out = float64(v) | |
105 return | |
106 } | |
107 } | |
108 } | |
109 failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag)) | |
110 }() | |
111 | |
112 // Any data is accepted as a !!str or !!binary. | |
113 // Otherwise, the prefix is enough of a hint about what it might be. | |
114 hint := byte('N') | |
115 if in != "" { | |
116 hint = resolveTable[in[0]] | |
117 } | |
118 if hint != 0 && tag != yaml_STR_TAG && tag != yaml_BINARY_TAG { | |
119 // Handle things we can lookup in a map. | |
120 if item, ok := resolveMap[in]; ok { | |
121 return item.tag, item.value | |
122 } | |
123 | |
124 // Base 60 floats are a bad idea, were dropped in YAML 1.2, and | |
125 // are purposefully unsupported here. They're still quoted on | |
126 // the way out for compatibility with other parser, though. | |
127 | |
128 switch hint { | |
129 case 'M': | |
130 // We've already checked the map above. | |
131 | |
132 case '.': | |
133 // Not in the map, so maybe a normal float. | |
134 floatv, err := strconv.ParseFloat(in, 64) | |
135 if err == nil { | |
136 return yaml_FLOAT_TAG, floatv | |
137 } | |
138 | |
139 case 'D', 'S': | |
140 // Int, float, or timestamp. | |
141 // Only try values as a timestamp if the value is unquoted or there's an explicit | |
142 // !!timestamp tag. | |
143 if tag == "" || tag == yaml_TIMESTAMP_TAG { | |
144 t, ok := parseTimestamp(in) | |
145 if ok { | |
146 return yaml_TIMESTAMP_TAG, t | |
147 } | |
148 } | |
149 | |
150 plain := strings.Replace(in, "_", "", -1) | |
151 intv, err := strconv.ParseInt(plain, 0, 64) | |
152 if err == nil { | |
153 if intv == int64(int(intv)) { | |
154 return yaml_INT_TAG, int(intv) | |
155 } else { | |
156 return yaml_INT_TAG, intv | |
157 } | |
158 } | |
159 uintv, err := strconv.ParseUint(plain, 0, 64) | |
160 if err == nil { | |
161 return yaml_INT_TAG, uintv | |
162 } | |
163 if yamlStyleFloat.MatchString(plain) { | |
164 floatv, err := strconv.ParseFloat(plain, 64) | |
165 if err == nil { | |
166 return yaml_FLOAT_TAG, floatv | |
167 } | |
168 } | |
169 if strings.HasPrefix(plain, "0b") { | |
170 intv, err := strconv.ParseInt(plain[2:], 2, 64) | |
171 if err == nil { | |
172 if intv == int64(int(intv)) { | |
173 return yaml_INT_TAG, int(intv) | |
174 } else { | |
175 return yaml_INT_TAG, intv | |
176 } | |
177 } | |
178 uintv, err := strconv.ParseUint(plain[2:], 2, 64) | |
179 if err == nil { | |
180 return yaml_INT_TAG, uintv | |
181 } | |
182 } else if strings.HasPrefix(plain, "-0b") { | |
183 intv, err := strconv.ParseInt("-" + plain[3:], 2, 64) | |
184 if err == nil { | |
185 if true || intv == int64(int(intv)) { | |
186 return yaml_INT_TAG, int(intv) | |
187 } else { | |
188 return yaml_INT_TAG, intv | |
189 } | |
190 } | |
191 } | |
192 default: | |
193 panic("resolveTable item not yet handled: " + string(rune(hint)) + " (with " + in + ")") | |
194 } | |
195 } | |
196 return yaml_STR_TAG, in | |
197 } | |
198 | |
199 // encodeBase64 encodes s as base64 that is broken up into multiple lines | |
200 // as appropriate for the resulting length. | |
201 func encodeBase64(s string) string { | |
202 const lineLen = 70 | |
203 encLen := base64.StdEncoding.EncodedLen(len(s)) | |
204 lines := encLen/lineLen + 1 | |
205 buf := make([]byte, encLen*2+lines) | |
206 in := buf[0:encLen] | |
207 out := buf[encLen:] | |
208 base64.StdEncoding.Encode(in, []byte(s)) | |
209 k := 0 | |
210 for i := 0; i < len(in); i += lineLen { | |
211 j := i + lineLen | |
212 if j > len(in) { | |
213 j = len(in) | |
214 } | |
215 k += copy(out[k:], in[i:j]) | |
216 if lines > 1 { | |
217 out[k] = '\n' | |
218 k++ | |
219 } | |
220 } | |
221 return string(out[:k]) | |
222 } | |
223 | |
224 // This is a subset of the formats allowed by the regular expression | |
225 // defined at http://yaml.org/type/timestamp.html. | |
226 var allowedTimestampFormats = []string{ | |
227 "2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields. | |
228 "2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t". | |
229 "2006-1-2 15:4:5.999999999", // space separated with no time zone | |
230 "2006-1-2", // date only | |
231 // Notable exception: time.Parse cannot handle: "2001-12-14 21:59:43.10 -5" | |
232 // from the set of examples. | |
233 } | |
234 | |
235 // parseTimestamp parses s as a timestamp string and | |
236 // returns the timestamp and reports whether it succeeded. | |
237 // Timestamp formats are defined at http://yaml.org/type/timestamp.html | |
238 func parseTimestamp(s string) (time.Time, bool) { | |
239 // TODO write code to check all the formats supported by | |
240 // http://yaml.org/type/timestamp.html instead of using time.Parse. | |
241 | |
242 // Quick check: all date formats start with YYYY-. | |
243 i := 0 | |
244 for ; i < len(s); i++ { | |
245 if c := s[i]; c < '0' || c > '9' { | |
246 break | |
247 } | |
248 } | |
249 if i != 4 || i == len(s) || s[i] != '-' { | |
250 return time.Time{}, false | |
251 } | |
252 for _, format := range allowedTimestampFormats { | |
253 if t, err := time.Parse(format, s); err == nil { | |
254 return t, true | |
255 } | |
256 } | |
257 return time.Time{}, false | |
258 } |