v2 / vlib / x / encoding / asn1 / field_options.v
568 lines · 515 sloc · 16.49 KB · 94905820e6da47fbb60eb4f30a3c553ba6d73a95
Raw
1module asn1
2
3// This file is for supporting configure through string options.
4// so, you can tag your struct field with supported attributes defined here.
5
6// Limit of string option length
7const max_string_option_length = 255
8const max_attributes_length = 5
9
10// Configuration format for field tagging.
11//
12// Currently, this configurations option support following string config, ie.
13//
14// - `class:number`, for wrapping the element with other non-universal class, for examole: `private:100`.
15// - `explicit` or `implicit` mode.
16// - `inner:5` for universal class form or `inner:class,constructed,number` for extended form.
17// - `optional` or `optional:present' tagging for element with OPTIONAL behaviour.
18// - `has_default` tagging for element with DEFAULT behaviour.
19//
20// Field options attributes handling.
21//
22// FieldOptions is a structure to accomodate and allowing configures your complex structures
23// through string or arrays of string stored in FieldOptions fields.
24// For example, you can tagging your fields of some element with tagging
25// like `@[context_specific:10; explicit; inner:5; optional]`.
26// Its will be parsed and can be used to drive encoding or decoding of Element.
27pub struct FieldOptions {
28mut:
29 // The fields `cls`, `tagnum`, `mode` and `inner` was used
30 // for wrapping (and unwrapping) purposes. turn some element
31 // into another element configured with this options.
32 // In the encoding (decoding) phase, it would be checked
33 // if this options meet required criteria.
34 // Limitation applied on the wrapper fields:
35 // 1. Wrap into UNIVERSAL is not allowed (cls != universal)
36 // 2. You should provide mode for wrapping, explicit or implicit.
37 // 3. If cls == '', no wrapping is performed, discarding all wrapper options
38 cls string // should cls != 'universal'
39 tagnum int = -1 // Provides with wrapper tag number, as n outer tag number.
40 mode string // explicit or implicit, depends on definition schema.
41
42 // inner should valid inner tag format, ie, universal form in single value 'number'
43 // or extended form in triplet value of 'class,form,number' format.
44 inner string
45
46 // optional field applied to element with OPTIONAL behaviour, with or without DEFAULT value.
47 // Set `optional` to true when this element has OPTIONAL keyword in the definition of element.
48 // Usually element with OPTIONAL keyword is not presents in the encoding (decoding) data.
49 optional bool
50 present bool
51
52 // This field applied to element with DEFAULT keyword behaviour.
53 // Its applied into wrapping of element or optionality of the element.
54 // If some element has DEFAULT keyword, set this field to true and gives default element
55 // into `default_value` field.
56 has_default bool
57 default_value ?Element
58}
59
60// `from_string` parses string as an attribute of field options.
61// Its allows string similar to `application:4; optional; has_default`
62// to be treated as an field options.
63// See FieldOptions in `field_options.v` for more detail.
64pub fn FieldOptions.from_string(s string) !FieldOptions {
65 if s.len == 0 {
66 return FieldOptions{}
67 }
68 if s.len > max_string_option_length {
69 return error('string option exceed limit')
70 }
71
72 trimmed := s.trim_space()
73 // check whether this string is a valid one.
74 if !is_asn1_options_marker(trimmed) {
75 return error('You have not provides correct options marker')
76 }
77 attrs := trimmed.split(';')
78 opt := FieldOptions.from_attrs(attrs)!
79 // no need to check, from_attrs already called it internally.
80 // opt.check_wrapper()!
81
82 return opt
83}
84
85// filtered_attrs filters and takes only supported asn1 marker from arrays of string.
86fn filtered_attrs(attrs []string) []string {
87 mut filtered := []string{}
88 for attr in attrs {
89 item := attr.trim_space()
90 if is_asn1_options_marker(item) {
91 filtered << item
92 }
93 }
94 return filtered
95}
96
97// `from_attrs` parses and validates []string into FieldOptions.
98pub fn FieldOptions.from_attrs(attrs []string) !FieldOptions {
99 mut fo := FieldOptions{}
100 if attrs.len == 0 {
101 return fo
102 }
103
104 mut tag_ctr := 0 // tag marker counter
105 mut opt_ctr := 0 // optional marker counter
106 mut def_ctr := 0 // has_default marker counter
107 mut mod_ctr := 0 // mode marker counter
108 mut inn_ctr := 0 // inner counter
109
110 // take only valid supported asn1 marker
111 filtered := filtered_attrs(attrs)
112 if filtered.len > max_attributes_length {
113 return error('max allowed filtered.len')
114 }
115
116 // The item has space-trimmed
117 for item in filtered {
118 if is_tag_marker(item) {
119 cls, num := parse_tag_marker(item)!
120 tag_ctr += 1
121 if tag_ctr > 1 {
122 return error('multiples tag format defined')
123 }
124 tnum := num.int()
125 if tnum < 0 {
126 return error('bad tag number')
127 }
128 fo.cls = cls
129 fo.tagnum = tnum
130 }
131 if is_mode_marker(item) {
132 value := parse_mode_marker(item)!
133 mod_ctr += 1
134 if mod_ctr > 1 {
135 return error('multiples mode key defined')
136 }
137 if !valid_mode_value(value) {
138 return error('Bad mode values')
139 }
140 fo.mode = value
141 }
142 if is_inner_tag_marker(item) {
143 _, value := parse_inner_tag_marker(item)!
144 inn_ctr += 1
145 if inn_ctr > 1 {
146 return error('multiples inner tag format defined')
147 }
148
149 fo.inner = value
150 }
151 if is_optional_marker(item) {
152 _, value := parse_optional_marker(item)!
153 opt_ctr += 1
154 if opt_ctr > 1 {
155 return error('multiples optional tag')
156 }
157 // when this present, its an optional
158 fo.optional = true
159
160 present := if valid_optional_present_bit_marker(value) { true } else { false }
161 fo.present = present
162 }
163 if is_default_marker(item) {
164 default_marker := parse_default_marker(item)!
165 def_ctr += 1
166 if def_ctr > 1 {
167 return error('multiples has_default flag')
168 }
169 has_default := if valid_default_marker(default_marker) { true } else { false }
170 fo.has_default = has_default
171 }
172 }
173
174 // check
175 fo.check_wrapper()!
176
177 return fo
178}
179
180// wrapper_tag makes a wrapper Tag from FieldOptions for current element.
181// The form of wrapper tag depends on tagged mode being supplied,
182// if implicit, its follows the inner tag being wrapped (primitive or constructed one)
183// If explicit, the wrapper tag would in non-primitive form.
184fn (fo FieldOptions) wrapper_tag() !Tag {
185 if fo.cls == '' {
186 return error('You cant build wrapper tag from empty string')
187 }
188 fo.check_wrapper()!
189 cls := TagClass.from_string(fo.cls)!
190 if !valid_mode_value(fo.mode) {
191 return error('Invalid mode')
192 }
193 inner_tag := fo.inner_tag()!
194 form := inner_tag.constructed
195 if fo.mode == 'implicit' {
196 // implicit tagging allows to be applied on non-constructed element, inherited from inner.
197 return Tag.new(cls, form, fo.tagnum)!
198 }
199 return Tag.new(cls, true, fo.tagnum)!
200}
201
202// inner_tag gets inner Tag from FieldOptions.
203fn (fo FieldOptions) inner_tag() !Tag {
204 // universal or extended form of inner value
205 st := fo.inner.trim_space()
206 if st == '' {
207 return error('invalid empty inner value')
208 }
209 if valid_inner_universal_form(st) {
210 val := st.int()
211 if val < 0 || val > max_universal_tagnumber {
212 return error('You cant create universal tag from invalid inner value')
213 }
214 utag := universal_tag_from_int(val)!
215 return utag
216 }
217 if !valid_extended_inner_form(st) {
218 return error('invalid extended inner value')
219 }
220 c, form, n := parse_inner_extended_form(st)!
221
222 cls := TagClass.from_string(c)!
223 constructed := if form == 'true' { true } else { false }
224 number := n.int()
225
226 inn_tag := Tag.new(cls, constructed, number)!
227 return inn_tag
228}
229
230// install_default tries to install and sets element el as a default value when has_default flag of FieldOptions
231// has been set into true, or error if has_default is false.
232// When default_value has been set with some value before this, its would return error until you force it
233// by setingt force flag into true.
234pub fn (mut fo FieldOptions) install_default(el Element, force bool) ! {
235 if fo.has_default {
236 if fo.default_value == none {
237 fo.default_value = el
238 return
239 }
240 // not nil
241 if !force {
242 return error('set force to overide')
243 }
244 // replace the old one, or should we check its matching tag ?
245 fo.default_value = el
246 }
247 return error('you can not install default value when has_default being not set')
248}
249
250// check_wrapper validates wrapper's part of fields options.
251fn (fo FieldOptions) check_wrapper() ! {
252 // Validates wrapper part
253 // Its discard all check when fo.cls is empty string, its marked as non-wrapped element.
254 if fo.cls != '' {
255 if !valid_tagclass_name(fo.cls) {
256 return error('Get unexpected fo.cls value')
257 }
258 // provides the tag number
259 if fo.tagnum < 0 {
260 return error('Get unexpected fo.tagnum}')
261 }
262 // wraps into UNIVERSAL type is not allowed
263 if fo.cls == 'universal' {
264 return error('wraps into universal class is not allowed')
265 }
266 if !valid_mode_value(fo.mode) {
267 return error('Invalid zonk or uncorerct mode value')
268 }
269 // when wrapped, you should provide inner tag number value.
270 if fo.inner == '' {
271 return error('You provides incorrect inner number')
272 }
273 // inner := fo.inner.trim_space()
274 if !valid_inner_universal_form(fo.inner) && !valid_extended_inner_form(fo.inner) {
275 return error('invalid inner value format')
276 }
277 if valid_inner_universal_form(fo.inner) {
278 // val := fo.inner.trim_space()
279 num := fo.inner.int()
280 if num > max_universal_tagnumber {
281 return error('Inner number exceed universal limit')
282 }
283 }
284 }
285}
286
287// WRAPPING (UNWRAPPING) OPTIONS.
288//
289// parse 'application=number' format
290// format: `class=number` without constructed keyword.
291fn parse_tag_marker(attr string) !(string, string) {
292 src := attr.trim_space()
293 if is_tag_marker(src) {
294 field := src.split(':')
295 if field.len != 2 {
296 return error('bad tag marker length')
297 }
298 first := field[0].trim_space()
299 if !valid_tagclass_name(first) {
300 return error('bad tag name')
301 }
302 second := field[1].trim_space()
303 if !valid_string_tag_number(second) {
304 return error('bad tag number')
305 }
306 return first, second
307 }
308 return error('not a tag marker')
309}
310
311fn is_tag_marker(attr string) bool {
312 return attr.starts_with('application') || attr.starts_with('private')
313 || attr.starts_with('context_specific')
314}
315
316fn valid_tagclass_name(tag string) bool {
317 return tag == 'application' || tag == 'private' || tag == 'context_specific'
318}
319
320// it should be represented in int or hex number
321fn valid_string_tag_number(s string) bool {
322 return s.is_int() || s.is_hex()
323}
324
325// EXPLICIT OR IMPLICIT OPTIONS.
326//
327// parse 'explicit [or implicit]' format.
328fn parse_mode_marker(s string) !string {
329 item := s.trim_space()
330 if is_mode_marker(item) {
331 if !valid_mode_value(item) {
332 return error('bad mode value')
333 }
334
335 return item
336 }
337 return error('not mode marker')
338}
339
340fn is_mode_marker(attr string) bool {
341 return attr.starts_with('explicit') || attr.starts_with('implicit')
342}
343
344fn valid_mode_value(s string) bool {
345 return s == 'explicit' || s == 'implicit'
346}
347
348// INNER TAG OPTIONS.
349//
350// parse inner value to be used by decoder.
351// support two format:
352// - unviersal inner format in the form `inner:number`, where number is universal class number.
353// - extended inner format in the form 'inner:class,form,number' for more broad support of the inner class.
354fn parse_inner_tag_marker(src string) !(string, string) {
355 if is_inner_tag_marker(src) {
356 item := src.split(':')
357 if item.len != 2 {
358 return error('bad inner tag marker length')
359 }
360 // check for inner part
361 key := item[0].trim_space()
362 if !valid_inner_tag_key(key) {
363 return error('bad inner key')
364 }
365 // check for universal or extended form.
366 // item is comma separated value.
367 value := item[1].trim_space()
368 items := value.split(',')
369 if items.len == 0 {
370 return error('no inner value')
371 }
372 // length should 1 (universal) or 3 (extended)
373 if items.len != 1 && items.len != 3 {
374 return error('Invalid items.len')
375 }
376 // if its in universal form, should be a number
377 if items.len == 1 {
378 if !valid_inner_universal_form(value) {
379 return error('Get invalid universal inner value')
380 }
381 }
382 // extended form
383 if items.len == 3 {
384 if !is_extended_inner_cls_marker(items[0].trim_space()) {
385 return error('Your first ext inner is not extended cls')
386 }
387 if !valid_extended_inner_cls_marker(items[0].trim_space()) {
388 return error('Your first ext inner is not valid ext cls')
389 }
390 // second form should be 'true' or 'false'
391 if !valid_extended_inner_form_marker(items[1].trim_space()) {
392 return error('Your ext inner form is invalid')
393 }
394 // third item should be a number
395 if !valid_extended_inner_number_marker(items[2].trim_space()) {
396 return error('invalid ext inner number part')
397 }
398 }
399 return key, value
400 }
401 return error('not inner tag marker')
402}
403
404fn is_inner_tag_marker(s string) bool {
405 return s.starts_with('inner')
406}
407
408fn valid_inner_tag_key(s string) bool {
409 return s == 'inner'
410}
411
412fn valid_inner_universal_form(value string) bool {
413 // 'inner: number' part
414 return valid_string_tag_number(value)
415}
416
417fn valid_extended_inner_form(value string) bool {
418 // 'inner:class,form,number' part in comma separated value.
419 items := value.split(',')
420 if items.len != 3 {
421 return false
422 }
423 if !is_extended_inner_cls_marker(items[0].trim_space()) {
424 return false
425 }
426 if !valid_extended_inner_cls_marker(items[0].trim_space()) {
427 return false
428 }
429 // second form should be 'true' or 'false'
430 if !valid_extended_inner_form_marker(items[1].trim_space()) {
431 return false
432 }
433 // third item should be a number
434 if !valid_extended_inner_number_marker(items[2].trim_space()) {
435 return false
436 }
437 return true
438}
439
440fn parse_inner_extended_form(s string) !(string, string, string) {
441 // 'inner:class,form,number' part in comma separated value.
442 items := s.split(',')
443 if items.len != 3 {
444 return error('invalid extended form length')
445 }
446 cls := items[0].trim_space()
447 if !is_extended_inner_cls_marker(cls) {
448 return error('Your first ext inner is not extended cls')
449 }
450 if !valid_extended_inner_cls_marker(cls) {
451 return error('Your first ext inner is not valid ext cls')
452 }
453 // second form should be 'true' or 'false'
454 form := items[1].trim_space()
455 if !valid_extended_inner_form_marker(form) {
456 return error('Your ext inner form is invalid')
457 }
458 // third item should be a number
459 third := items[2].trim_space()
460 if !valid_extended_inner_number_marker(third) {
461 return error('invalid ext inner number part')
462 }
463 return cls, form, third
464}
465
466// allows universal class as an inner.
467fn is_extended_inner_cls_marker(attr string) bool {
468 return is_tag_marker(attr) || attr.starts_with('universal')
469}
470
471fn valid_extended_inner_cls_marker(attr string) bool {
472 return valid_tagclass_name(attr) || attr == 'universal'
473}
474
475fn valid_extended_inner_form_marker(s string) bool {
476 return s == 'true' || s == 'false'
477}
478
479fn valid_extended_inner_number_marker(s string) bool {
480 return valid_string_tag_number(s)
481}
482
483// OPTIONAL.
484//
485// support two form of optional marker.
486// - the only optional key 'optional' marker, and
487// - extended bit of presence of optional, 'optional:present'
488fn parse_optional_marker(attr string) !(string, string) {
489 values := attr.split(':')
490 if values.len != 1 && values.len != 2 {
491 return error('Bad optional length')
492 }
493 if values.len == 1 {
494 key := values[0].trim_space()
495 if is_optional_marker(key) {
496 if !valid_optional_key(key) {
497 return error('bad optional key')
498 }
499 return key, ''
500 }
501 }
502 if values.len == 2 {
503 first := values[0].trim_space()
504 if !valid_optional_key(first) {
505 return error('bad optional key')
506 }
507 second := values[1].trim_space()
508 if !is_optional_present_bit_marker(second) {
509 return error('Non optional presence bit marker')
510 }
511 if !valid_optional_present_bit_marker(second) {
512 return error('Not valid optional presence bit marker')
513 }
514 return first, second
515 }
516
517 return error('not optional marker')
518}
519
520fn is_optional_marker(attr string) bool {
521 return attr.starts_with('optional')
522}
523
524fn valid_optional_key(attr string) bool {
525 return attr == 'optional'
526}
527
528fn is_optional_present_bit_marker(attr string) bool {
529 return attr.starts_with('present')
530}
531
532fn valid_optional_present_bit_marker(attr string) bool {
533 return attr == 'present'
534}
535
536// DEFAULT OPTIONS.
537//
538// parse 'has_default' marker
539fn parse_default_marker(attr string) !string {
540 item := attr.trim_space()
541 if is_default_marker(item) {
542 if !valid_default_marker(item) {
543 return error('bad has_default marker')
544 }
545 return item
546 }
547 return error('not has_default marker')
548}
549
550fn is_default_marker(attr string) bool {
551 return attr.starts_with('has_default')
552}
553
554fn valid_default_marker(attr string) bool {
555 return attr == 'has_default'
556}
557
558// UTILTIY
559//
560// is_asn1_options_marker checks if provided string is valid supported field options string.
561fn is_asn1_options_marker(item string) bool {
562 // item := s.trim_space()
563 // belowng to one of five supported marker.
564 valid := is_tag_marker(item) || is_mode_marker(item) || is_inner_tag_marker(item)
565 || is_optional_marker(item) || is_default_marker(item)
566
567 return valid
568}
569