-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WIP: Bring up to date with -09 draft
Signed-off-by: Ionut Mihalcea <[email protected]>
- Loading branch information
Showing
8 changed files
with
1,005 additions
and
833 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,223 +1,71 @@ | ||
// Copyright 2023 Contributors to the Veraison project. | ||
// Copyright 2024 Contributors to the Veraison project. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package cmw | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/fxamacker/cbor/v2" | ||
) | ||
|
||
type Serialization uint | ||
|
||
const ( | ||
UnknownSerialization = Serialization(iota) | ||
JSONArray | ||
CBORArray | ||
CBORTag | ||
JSON | ||
CBOR | ||
) | ||
|
||
// a CMW object holds the internal representation of a RATS conceptual message | ||
// wrapper | ||
type CMW struct { | ||
typ Type | ||
val Value | ||
ind Indicator | ||
serialization Serialization | ||
} | ||
|
||
func (o *CMW) SetMediaType(v string) { _ = o.typ.Set(v) } | ||
func (o *CMW) SetContentFormat(v uint16) { _ = o.typ.Set(v) } | ||
func (o *CMW) SetTagNumber(v uint64) { _ = o.typ.Set(v) } | ||
func (o *CMW) SetValue(v []byte) { _ = o.val.Set(v) } | ||
func (o *CMW) SetIndicators(indicators ...Indicator) { | ||
var v Indicator | ||
|
||
for _, ind := range indicators { | ||
v.Set(ind) | ||
} | ||
|
||
o.ind = v | ||
val any | ||
} | ||
func (o *CMW) SetSerialization(s Serialization) { o.serialization = s } | ||
|
||
func (o CMW) GetValue() []byte { return o.val } | ||
func (o CMW) GetType() string { return o.typ.String() } | ||
func (o CMW) GetIndicator() Indicator { return o.ind } | ||
func (o CMW) GetSerialization() Serialization { return o.serialization } | ||
|
||
// Deserialize a CMW | ||
func (o *CMW) Deserialize(b []byte) error { | ||
s := sniff(b) | ||
|
||
o.serialization = s | ||
|
||
switch s { | ||
case JSONArray: | ||
return o.UnmarshalJSON(b) | ||
case CBORArray, CBORTag: | ||
return o.UnmarshalCBOR(b) | ||
} | ||
|
||
return errors.New("unknown CMW format") | ||
} | ||
|
||
// Serialize a CMW according to its provided Serialization | ||
func (o CMW) Serialize() ([]byte, error) { | ||
s := o.serialization | ||
switch s { | ||
case JSONArray: | ||
return o.MarshalJSON() | ||
case CBORArray, CBORTag: | ||
return o.MarshalCBOR() | ||
} | ||
return nil, fmt.Errorf("invalid serialization format %d", s) | ||
} | ||
typ := sniff(b) | ||
|
||
func (o CMW) MarshalJSON() ([]byte, error) { return arrayEncode(json.Marshal, &o) } | ||
|
||
func (o CMW) MarshalCBOR() ([]byte, error) { | ||
s := o.serialization | ||
switch s { | ||
case CBORArray: | ||
return arrayEncode(cbor.Marshal, &o) | ||
case CBORTag: | ||
return o.encodeCBORTag() | ||
} | ||
return nil, fmt.Errorf("invalid serialization format: want CBORArray or CBORTag, got %d", s) | ||
} | ||
|
||
func (o CMW) encodeCBORTag() ([]byte, error) { | ||
var ( | ||
tag cbor.RawTag | ||
err error | ||
) | ||
|
||
if !o.typ.IsSet() || !o.val.IsSet() { | ||
return nil, fmt.Errorf("type and value MUST be set in CMW") | ||
} | ||
|
||
tag.Number, err = o.typ.TagNumber() | ||
if err != nil { | ||
return nil, fmt.Errorf("getting a suitable tag value: %w", err) | ||
switch typ { | ||
case collection: | ||
var coll CollectionCMW | ||
coll.Deserialize(b) | ||
o.val = coll | ||
case leaf: | ||
var lf LeafCMW | ||
lf.Deserialize(b) | ||
o.val = lf | ||
} | ||
|
||
tag.Content, err = cbor.Marshal(o.val) | ||
if err != nil { | ||
return nil, fmt.Errorf("marshaling tag value: %w", err) | ||
} | ||
|
||
return tag.MarshalCBOR() | ||
return errors.New("unknown CMW type") | ||
} | ||
|
||
func (o *CMW) UnmarshalCBOR(b []byte) error { | ||
if arrayDecode[cbor.RawMessage](cbor.Unmarshal, b, o) == nil { | ||
o.serialization = CBORArray | ||
return nil | ||
} | ||
|
||
if o.decodeCBORTag(b) == nil { | ||
// the serialization attribute is set by decodeCBORTag | ||
return nil | ||
func (o CMW) Serialize(s Serialization) ([]byte, error) { | ||
switch v := o.val.(type) { | ||
case LeafCMW: | ||
return v.Serialize(s) | ||
case CollectionCMW: | ||
return v.Serialize(s) | ||
default: | ||
return nil, fmt.Errorf("unsupported type %T", v) | ||
} | ||
|
||
return errors.New("invalid CBOR-encoded CMW") | ||
} | ||
|
||
func (o *CMW) UnmarshalJSON(b []byte) error { | ||
err := arrayDecode[json.RawMessage](json.Unmarshal, b, o) | ||
o.serialization = JSONArray | ||
return err | ||
} | ||
|
||
func (o *CMW) decodeCBORTag(b []byte) error { | ||
var ( | ||
v cbor.RawTag | ||
m []byte | ||
err error | ||
) | ||
type cmwNodeType uint | ||
|
||
if err = v.UnmarshalCBOR(b); err != nil { | ||
return fmt.Errorf("unmarshal CMW CBOR Tag: %w", err) | ||
} | ||
|
||
if err = cbor.Unmarshal(v.Content, &m); err != nil { | ||
return fmt.Errorf("unmarshal CMW CBOR Tag bstr-wrapped value: %w", err) | ||
} | ||
|
||
_ = o.typ.Set(v.Number) | ||
_ = o.val.Set(m) | ||
o.serialization = CBORTag | ||
|
||
return nil | ||
} | ||
|
||
func sniff(b []byte) Serialization { | ||
if len(b) == 0 { | ||
return UnknownSerialization | ||
} | ||
|
||
if b[0] == 0x82 || b[0] == 0x83 { | ||
return CBORArray | ||
} else if b[0] >= 0xc0 && b[0] <= 0xdb { | ||
return CBORTag | ||
} else if b[0] == 0x5b { | ||
return JSONArray | ||
} | ||
|
||
return UnknownSerialization | ||
} | ||
|
||
type ( | ||
arrayDecoder func([]byte, any) error | ||
arrayEncoder func(any) ([]byte, error) | ||
const ( | ||
unknownType = cmwNodeType(iota) | ||
leaf | ||
collection | ||
) | ||
|
||
func arrayDecode[V json.RawMessage | cbor.RawMessage]( | ||
dec arrayDecoder, b []byte, o *CMW, | ||
) error { | ||
var a []V | ||
|
||
if err := dec(b, &a); err != nil { | ||
return err | ||
} | ||
func sniff(b []byte) cmwNodeType { | ||
s := sniff_leaf(b) | ||
|
||
alen := len(a) | ||
|
||
if alen < 2 || alen > 3 { | ||
return fmt.Errorf("wrong number of entries (%d) in the CMW array", alen) | ||
} | ||
|
||
if err := dec(a[0], &o.typ); err != nil { | ||
return fmt.Errorf("unmarshaling type: %w", err) | ||
} | ||
|
||
if err := dec(a[1], &o.val); err != nil { | ||
return fmt.Errorf("unmarshaling value: %w", err) | ||
} | ||
|
||
if alen == 3 { | ||
if err := dec(a[2], &o.ind); err != nil { | ||
return fmt.Errorf("unmarshaling indicator: %w", err) | ||
if s == UnknownForm { | ||
if sniff_collection(b) { | ||
return collection | ||
} | ||
} else { | ||
return leaf | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func arrayEncode(enc arrayEncoder, o *CMW) ([]byte, error) { | ||
if !o.typ.IsSet() || !o.val.IsSet() { | ||
return nil, fmt.Errorf("type and value MUST be set in CMW") | ||
} | ||
|
||
a := []any{o.typ, o.val} | ||
|
||
if !o.ind.Empty() { | ||
a = append(a, o.ind) | ||
} | ||
|
||
return enc(a) | ||
return unknownType | ||
} |
Oops, something went wrong.