Support encoding map types to CycloneDX properties (#1332)

This commit is contained in:
Keith Zantow 2022-11-08 18:59:37 -05:00 committed by GitHub
parent 5ed002e1a9
commit f3528132a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 68 additions and 0 deletions

View File

@ -85,6 +85,7 @@ func Sorted(values map[string]string) (out []NameValue) {
return
}
//nolint:funlen
func encode(out map[string]string, value reflect.Value, prefix string, fn FieldName) {
if !value.IsValid() || value.Type() == nil {
return
@ -130,6 +131,11 @@ func encode(out map[string]string, value reflect.Value, prefix string, fn FieldN
}
encode(out, pv, name, fn)
}
case reflect.Map:
// currently only map[string]string is really supported
for _, key := range value.MapKeys() {
encode(out, value.MapIndex(key), fmt.Sprintf("%s:%v", prefix, key.Interface()), fn)
}
default:
log.Warnf("skipping encoding of unsupported property: %s", prefix)
}
@ -284,6 +290,55 @@ func decode(vals map[string]string, value reflect.Value, prefix string, fn Field
} else {
return false
}
case reflect.Map:
values := false
keyType := typ.Key()
valueType := typ.Elem()
outMap := reflect.MakeMap(typ)
str := fmt.Sprintf("%s:", prefix)
keyVals := map[string]string{}
// iterate through all keys to find those prefixed with a reference to this map
// NOTE: this will not work for nested maps
for key := range vals {
// test for map prefix
if strings.HasPrefix(key, str) {
keyVals[key] = strings.TrimPrefix(key, str)
// create new placeholder and decode key
newKeyType := keyType
if keyType.Kind() == reflect.Ptr {
newKeyType = keyType.Elem()
}
k := reflect.New(newKeyType)
if !decode(keyVals, k.Elem(), key, fn) {
log.Debugf("unable to decode key for: %s", key)
continue
}
if keyType.Kind() != reflect.Ptr {
k = k.Elem()
}
// create new placeholder and decode value
newValueType := valueType
if valueType.Kind() == reflect.Ptr {
newValueType = valueType.Elem()
}
v := reflect.New(newValueType)
if decode(vals, v.Elem(), key, fn) {
if valueType.Kind() != reflect.Ptr {
v = v.Elem()
}
// set in map
outMap.SetMapIndex(k, v)
values = true
}
}
}
if values {
value.Set(outMap)
} else {
return false
}
case reflect.Struct:
values := false
for i := 0; i < typ.NumField(); i++ {

View File

@ -37,6 +37,10 @@ type T4 struct {
IntPtr *int
}
type T5 struct {
Map map[string]string
}
func Test_EncodeDecodeCycle(t *testing.T) {
val := 99
@ -118,6 +122,15 @@ func Test_EncodeDecodeCycle(t *testing.T) {
{"t2 elem 1"},
},
},
{
name: "map of strings",
value: &T5{
Map: map[string]string{
"key1": "value1",
"key2": "value2",
},
},
},
}
for _, test := range tests {