x.encoding.asn1: cleanup code, improve performance (#22968)

This commit is contained in:
blackshirt 2024-11-25 16:08:54 +07:00 committed by GitHub
parent 904bccb564
commit 94905820e6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 54 additions and 148 deletions

View File

@ -67,8 +67,7 @@ pub fn (el Element) into_object[T]() !T {
// length tells the payload length of this element.
pub fn (el Element) length() !int {
payload := el.payload()!
return payload.len
return el.payload()!.len
}
// UTILITY HELPER FOR ELEMENT
@ -225,8 +224,7 @@ fn (el Element) equal_payload(other Element) bool {
}
fn Element.decode(src []u8) !(Element, int) {
el, pos := Element.decode_with_rule(src, 0, .der)!
return el, pos
return Element.decode_with_rule(src, 0, .der)!
}
// decode deserializes back bytes in src from offet `loc` into Element.

View File

@ -99,8 +99,7 @@ pub fn decode_with_field_options(bytes []u8, fo FieldOptions) !Element {
return error('Get different tag number')
}
// TODO: default
el := tlv.unwrap_with_field_options(fo)!
return el
return tlv.unwrap_with_field_options(fo)!
}
fn decode_optional(bytes []u8, expected_tag Tag) !Element {

View File

@ -39,25 +39,16 @@ pub fn encode(el Element) ![]u8 {
// assert explicit_out == [u8(0xA5), 0x04, 0x0C, 0x02, 0x68, 0x69]
// ```
pub fn encode_with_options(el Element, opt string) ![]u8 {
return el.encode_with_options(opt)!
}
// `encode_with_field_options` serializes this element into bytes array with options defined in fo.
pub fn encode_with_field_options(el Element, fo FieldOptions) ![]u8 {
return el.encode_with_field_options(fo)!
}
fn (el Element) encode_with_options(opt string) ![]u8 {
// treated as without option when nil
// treated as without option when empty
if opt.len == 0 {
return encode_with_rule(el, .der)!
}
fo := FieldOptions.from_string(opt)!
return el.encode_with_field_options(fo)!
return encode_with_field_options(el, fo)!
}
// encode_with_field_options serializes element into bytes arrays with supplied FieldOptions.
fn (el Element) encode_with_field_options(fo FieldOptions) ![]u8 {
// `encode_with_field_options` serializes this element into bytes array with options defined in fo.
pub fn encode_with_field_options(el Element, fo FieldOptions) ![]u8 {
// validates options again this element.
el.validate_options(fo)!
@ -81,33 +72,7 @@ fn (el Element) encode_with_field_options(fo FieldOptions) ![]u8 {
return new_el.encode()!
}
// otherwise, just serializing it
out := encode_with_rule(new_el, .der)!
return out
}
// encode_with_rule encodes element into bytes array with rule.
fn encode_with_rule(el Element, rule EncodingRule) ![]u8 {
if rule != .der && rule != .ber {
return error('Element: unsupported rule')
}
mut dst := []u8{}
// when this element is Optional without presence flag, by default would
// serialize this element into empty bytes otherwise, would serialize underlying element.
if el is Optional {
return el.encode()!
}
// otherwise, just serializes as normal
el.tag().encode_with_rule(mut dst, rule)!
// calculates the length of element, and serialize this length
payload := el.payload()!
length := Length.new(payload.len)!
length.encode_with_rule(mut dst, rule)!
// append the element payload to destination
dst << payload
return dst
return encode_with_rule(new_el, .der)!
}
// Helper for wrapping element
@ -201,3 +166,27 @@ fn wrap(el Element, cls TagClass, number int, mode TaggedMode) !Element {
}
}
}
// encode_with_rule encodes element into bytes array with rule.
fn encode_with_rule(el Element, rule EncodingRule) ![]u8 {
if rule != .der && rule != .ber {
return error('Element: unsupported rule')
}
mut dst := []u8{}
// when this element is Optional without presence flag, by default would
// serialize this element into empty bytes otherwise, would serialize underlying element.
if el is Optional {
return el.encode()!
}
// otherwise, just serializes as normal
el.tag().encode_with_rule(mut dst, rule)!
// calculates the length of element, and serialize this length
payload := el.payload()!
length := Length.new(payload.len)!
length.encode_with_rule(mut dst, rule)!
// append the element payload to destination
dst << payload
return dst
}

View File

@ -115,10 +115,6 @@ pub fn FieldOptions.from_attrs(attrs []string) !FieldOptions {
// The item has space-trimmed
for item in filtered {
if !is_tag_marker(item) && !is_optional_marker(item) && !is_default_marker(item)
&& !is_mode_marker(item) && !is_inner_tag_marker(item) {
return error('unsupported keyword')
}
if is_tag_marker(item) {
cls, num := parse_tag_marker(item)!
tag_ctr += 1

View File

@ -46,19 +46,6 @@ pub fn RawElement.new(tag Tag, content []u8) !RawElement {
return RawElement{
tag: tag
content: content
// Issues: without set this to `none`, when compiled with `-cstrict` options, its would bring
// into failed compiles error:
// ================= C compilation error (from clang): ==============
// error: incompatible pointer types passing '_option_x__encoding__asn1__Tag *'
// (aka 'struct _option_x__encoding__asn1__Tag *') to parameter of type '_option *'
// (aka 'struct _option *') [-Werror,-Wincompatible-pointer-types]
// cc: _option_none(&(x__encoding__asn1__Tag[])
// { ((x__encoding__asn1__Tag){.__v_class =
// x__encoding__asn1__TagClass__universal,.constructed = 0,.number = 0,})},
// &_t6, sizeof(x__encoding__asn1__Tag)); ```
inner_tag: none
mode: none
default_value: none
}
}
@ -93,19 +80,9 @@ pub fn (r RawElement) payload() ![]u8 {
return r.content
}
// force_set_mode forces to change tagged mode of RawElement into mode.
// It will change how the element was interpreted.
pub fn (mut r RawElement) force_set_mode(mode TaggedMode) ! {
r.set_mode_with_flag(mode, true)!
}
// set_mode sets the tagged mode of the RawElement into mode.
// If you want force it to use the mode, use `force_set_mode`.
pub fn (mut r RawElement) set_mode(mode TaggedMode) ! {
r.set_mode_with_flag(mode, false)!
}
fn (mut r RawElement) set_mode_with_flag(mode TaggedMode, force bool) ! {
// set_mode sets the RawElement tagged mode, in explicit or implicit mode. If the mode has been set,
// it would drop into error until you forces it by setting force flag into true value, ie, replaces the old one.
pub fn (mut r RawElement) set_mode(mode TaggedMode, force bool) ! {
if r.tag.class == .universal {
return error('No need it on universal class')
}
@ -120,28 +97,15 @@ fn (mut r RawElement) set_mode_with_flag(mode TaggedMode, force bool) ! {
r.mode = mode
}
// set_inner_tag sets the inner tag of the RawElement into inner_tag.
// If its already set, it would return error.
// Use `force_set_inner_tag` instead to force it.
pub fn (mut r RawElement) set_inner_tag(inner_tag Tag) ! {
r.set_inner_tag_with_flag(inner_tag, false)!
}
// force_set_inner_tag forces to set the inner tag of the RawElement into inner_tag
// even its has been set previously.
pub fn (mut r RawElement) force_set_inner_tag(inner_tag Tag) ! {
r.set_inner_tag_with_flag(inner_tag, true)!
}
fn (mut r RawElement) set_inner_tag_with_flag(inner_tag Tag, force bool) ! {
// set_inner_tag sets the inner tag of the RawElement into inner_tag value. If it has been already set,
// it would be an error until you setting force flag into true value to replace the old one.
pub fn (mut r RawElement) set_inner_tag(inner_tag Tag, force bool) ! {
// not needed in universal class
if r.tag.class == .universal {
return error('No need it on universal class')
}
// we need mode first
mode := r.mode or { return error('unmeet_requirement, set the mode first') }
// when its explicit, compares the provided tag with tag from the inner element.
mode := r.mode or { return error('You dont set any mode') }
// when its in explicit mode, compares the provided tag with tag from the inner element.
if mode == .explicit {
if !r.tag.constructed {
return error('unmeet_requirement, explicit should be constructed')
@ -164,17 +128,8 @@ fn (mut r RawElement) set_inner_tag_with_flag(inner_tag Tag, force bool) ! {
}
// force_set_default_value forces set default value of this RawElement into value.
pub fn (mut r RawElement) force_set_default_value(value Element) ! {
r.set_default_value_with_flag(value, true)!
}
// set_default_value sets the default value of this RawElement to some value.
pub fn (mut r RawElement) set_default_value(value Element) ! {
r.set_default_value_with_flag(value, false)!
}
fn (mut r RawElement) set_default_value_with_flag(value Element, force bool) ! {
// default value of this element should have equal tag.
fn (mut r RawElement) set_default_value(value Element, force bool) ! {
// default value of this element should have an equal tag.
if !value.tag().equal(r.tag) {
return error('You provides unequal tag for default value')
}
@ -189,10 +144,8 @@ fn (mut r RawElement) set_default_value_with_flag(value Element, force bool) ! {
}
// inner_tag returns the inner tag of the RawElement if it exists, or error on fails.
pub fn (r RawElement) inner_tag() !Tag {
inner_tag := r.inner_tag or { return error(' r.inner_tag is not set') }
return inner_tag
pub fn (r RawElement) inner_tag() ?Tag {
return r.inner_tag
}
// inner_element returns the inner element of the RawElement if its exists.
@ -200,9 +153,8 @@ pub fn (r RawElement) inner_element() !Element {
if r.tag.class == .universal {
return error('inner element from universal class is not availables')
}
mode := r.mode or { return err }
inner_tag := r.inner_tag or { return err }
mode := r.mode or { return error('You dont set any mode') }
if mode == .explicit {
if !r.tag.constructed {
return error('tag should be constructed when in explicit')
@ -302,11 +254,8 @@ fn ContextElement.decode_raw(bytes []u8) !(ContextElement, int) {
next := content_pos + length
// Raw ContextElement, you should provide mode and inner tag.
ctx := ContextElement{
tag: tag
content: content
inner_tag: none
mode: none
default_value: none
tag: tag
content: content
}
return ctx, next
}

View File

@ -32,13 +32,6 @@ mut:
fields []Element
}
fn (s Sequence) str() string {
if s.fields.len == 0 {
return 'SEQUENCE: <empty>'
}
return 'SEQUENCE: ${s.fields.len} elements.'
}
// new creates new Sequence with default size.
pub fn Sequence.new() !Sequence {
return Sequence.new_with_size(default_sequence_size)!
@ -240,13 +233,6 @@ mut:
fields []T
}
fn (s SequenceOf[T]) str() string {
if s.fields.len == 0 {
return 'SEQUENCE OF (<empty>)'
}
return 'SEQUENCE OF (${s.fields.len} ${typeof(s).name})'
}
// SequenceOf.new creates a new SequenceOf[T]
pub fn SequenceOf.new[T]() SequenceOf[T] {
return SequenceOf[T]{}

View File

@ -23,13 +23,6 @@ mut:
fields []Element
}
fn (s Set) str() string {
if s.fields.len == 0 {
return 'SET (<empty>)'
}
return 'SET (${s.fields.len} Elements)'
}
// creates a new Set with default size.
pub fn Set.new() !Set {
return Set.new_with_size(default_set_size)!
@ -247,13 +240,6 @@ pub fn SetOf.new[T]() !SetOf[T] {
return SetOf[T]{}
}
fn (s SetOf[T]) str() string {
if s.fields.len == 0 {
return 'SET OF (<empty>)'
}
return 'SET OF (${s.fields.len} ${typeof(s).name})'
}
// from_list creates new SetOf type T from arrays of T.
pub fn SetOf.from_list[T](els []T) !SetOf[T] {
$if T !is Element {

View File

@ -59,8 +59,8 @@ Example ::= SEQUENCE {
assert els[1] is Integer
mut els2 := els[2] as ContextElement
els2.set_mode(.explicit)!
els2.set_inner_tag(default_oid_tag)!
els2.set_mode(.explicit, true)!
els2.set_inner_tag(default_oid_tag, true)!
out.clear()
out = encode(els2)!

View File

@ -50,7 +50,8 @@ pub fn UtcTime.new(s string) !UtcTime {
}
}
fn UtcTime.from_time(t time.Time) !UtcTime {
// from_time creates a new UtcTime element from standard `time.Time` in UTC time format.
pub fn UtcTime.from_time(t time.Time) !UtcTime {
// changes into utc time
utime := t.local_to_utc()
s := utime.custom_format(default_utctime_format) // 20241113060446+0
@ -226,7 +227,7 @@ pub fn GeneralizedTime.new(s string) !GeneralizedTime {
}
}
// from_time creates GeneralizedTime element from tine.Time (as an UTC time).
// from_time creates GeneralizedTime element from standard `time.Time` (as an UTC time).
pub fn GeneralizedTime.from_time(t time.Time) !GeneralizedTime {
u := t.local_to_utc()
s := u.custom_format(default_genztime_format)

View File

@ -116,6 +116,8 @@ fn test_create_generalizedtime_from_std_time() ! {
gtc := GeneralizedTime.from_time(now)!
assert gtb.value == gtc.value
assert gtb.value == '20241113174550Z'
assert gtc.value == '20241113174550Z'
tt := gtc.into_utctime()!
assert now == tt