mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-12-23 05:20:19 +00:00
249 lines
6.3 KiB
Go
249 lines
6.3 KiB
Go
|
package ttlv
|
||
|
|
||
|
import (
|
||
|
"sort"
|
||
|
|
||
|
"github.com/ansel1/merry"
|
||
|
"github.com/gemalto/kmip-go/internal/kmiputil"
|
||
|
)
|
||
|
|
||
|
// DefaultRegistry holds the default mappings of types, tags, enums, and bitmasks
|
||
|
// to canonical names and normalized names from the KMIP spec. It is pre-populated with the 1.4 spec's
|
||
|
// values. It can be replaced, or additional values can be registered with it.
|
||
|
//
|
||
|
// It is not currently concurrent-safe, so replace or configure it early in your
|
||
|
// program.
|
||
|
var DefaultRegistry Registry
|
||
|
|
||
|
// nolint:gochecknoinits
|
||
|
func init() {
|
||
|
RegisterTypes(&DefaultRegistry)
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
ErrInvalidHexString = kmiputil.ErrInvalidHexString
|
||
|
ErrUnregisteredEnumName = merry.New("unregistered enum name")
|
||
|
)
|
||
|
|
||
|
// NormalizeName tranforms KMIP names from the spec into the
|
||
|
// normalized form of the name. Typically, this means removing spaces,
|
||
|
// and replacing some special characters. The normalized form of the name
|
||
|
// is used in the JSON and XML encodings from the KMIP Profiles.
|
||
|
// The spec describes the normalization process in 5.4.1.1 and 5.5.1.1
|
||
|
func NormalizeName(s string) string {
|
||
|
return kmiputil.NormalizeName(s)
|
||
|
}
|
||
|
|
||
|
// Enum represents an enumeration of KMIP values (as uint32), and maps them
|
||
|
// to the canonical string names and the normalized string names of the
|
||
|
// value as declared in the KMIP specs.
|
||
|
// Enum is used to transpose values from strings to byte values, as required
|
||
|
// by the JSON and XML encodings defined in the KMIP Profiles spec.
|
||
|
// These mappings are also used to pretty print KMIP values, and to marshal
|
||
|
// and unmarshal enum and bitmask values to golang string values.
|
||
|
//
|
||
|
// Enum currently uses plain maps, so it is not thread safe to register new values
|
||
|
// concurrently. You should register all values at the start of your program before
|
||
|
// using this package concurrently.
|
||
|
//
|
||
|
// Enums are used in the KMIP spec for two purposes: for defining the possible values
|
||
|
// for values encoded as the KMIP Enumeration type, and for bitmask values. Bitmask
|
||
|
// values are encoded as Integers, but are really enum values bitwise-OR'd together.
|
||
|
//
|
||
|
// Enums are registered with a Registry. The code to register enums is typically
|
||
|
// generated by the kmipgen tool.
|
||
|
type Enum struct {
|
||
|
valuesToName map[uint32]string
|
||
|
valuesToCanonicalName map[uint32]string
|
||
|
nameToValue map[string]uint32
|
||
|
canonicalNamesToValue map[string]uint32
|
||
|
bitMask bool
|
||
|
}
|
||
|
|
||
|
func NewEnum() Enum {
|
||
|
return Enum{}
|
||
|
}
|
||
|
|
||
|
func NewBitmask() Enum {
|
||
|
return Enum{
|
||
|
bitMask: true,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// RegisterValue adds a mapping of a uint32 value to a name. The name will be
|
||
|
// processed by NormalizeName to produce the normalized enum value name as described
|
||
|
// in the KMIP spec.
|
||
|
func (e *Enum) RegisterValue(v uint32, name string) {
|
||
|
nn := NormalizeName(name)
|
||
|
|
||
|
if e.valuesToName == nil {
|
||
|
e.valuesToName = map[uint32]string{}
|
||
|
e.nameToValue = map[string]uint32{}
|
||
|
e.valuesToCanonicalName = map[uint32]string{}
|
||
|
e.canonicalNamesToValue = map[string]uint32{}
|
||
|
}
|
||
|
|
||
|
e.valuesToName[v] = nn
|
||
|
e.nameToValue[nn] = v
|
||
|
e.valuesToCanonicalName[v] = name
|
||
|
e.canonicalNamesToValue[name] = v
|
||
|
}
|
||
|
|
||
|
func (e *Enum) Name(v uint32) (string, bool) {
|
||
|
if e == nil {
|
||
|
return "", false
|
||
|
}
|
||
|
|
||
|
name, ok := e.valuesToName[v]
|
||
|
|
||
|
return name, ok
|
||
|
}
|
||
|
|
||
|
func (e *Enum) CanonicalName(v uint32) (string, bool) {
|
||
|
if e == nil {
|
||
|
return "", false
|
||
|
}
|
||
|
|
||
|
name, ok := e.valuesToCanonicalName[v]
|
||
|
|
||
|
return name, ok
|
||
|
}
|
||
|
|
||
|
func (e *Enum) Value(name string) (uint32, bool) {
|
||
|
if e == nil {
|
||
|
return 0, false
|
||
|
}
|
||
|
|
||
|
v, ok := e.nameToValue[name]
|
||
|
if !ok {
|
||
|
v, ok = e.canonicalNamesToValue[name]
|
||
|
}
|
||
|
|
||
|
return v, ok
|
||
|
}
|
||
|
|
||
|
func (e *Enum) Values() []uint32 {
|
||
|
values := make([]uint32, 0, len(e.valuesToName))
|
||
|
for v := range e.valuesToName {
|
||
|
values = append(values, v)
|
||
|
}
|
||
|
// Always list them in order of value so output is stable.
|
||
|
sort.Sort(uint32Slice(values))
|
||
|
|
||
|
return values
|
||
|
}
|
||
|
|
||
|
func (e *Enum) Bitmask() bool {
|
||
|
if e == nil {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
return e.bitMask
|
||
|
}
|
||
|
|
||
|
// Registry holds all the known tags, types, enums and bitmaps declared in
|
||
|
// a KMIP spec. It's used throughout the package to map values their canonical
|
||
|
// and normalized names.
|
||
|
type Registry struct {
|
||
|
enums map[Tag]EnumMap
|
||
|
tags Enum
|
||
|
types Enum
|
||
|
}
|
||
|
|
||
|
func (r *Registry) RegisterType(t Type, name string) {
|
||
|
r.types.RegisterValue(uint32(t), name)
|
||
|
}
|
||
|
|
||
|
func (r *Registry) RegisterTag(t Tag, name string) {
|
||
|
r.tags.RegisterValue(uint32(t), name)
|
||
|
}
|
||
|
|
||
|
func (r *Registry) RegisterEnum(t Tag, def EnumMap) {
|
||
|
if r.enums == nil {
|
||
|
r.enums = map[Tag]EnumMap{}
|
||
|
}
|
||
|
|
||
|
r.enums[t] = def
|
||
|
}
|
||
|
|
||
|
// EnumForTag returns the enum map registered for a tag. Returns
|
||
|
// nil if no map is registered for this tag.
|
||
|
func (r *Registry) EnumForTag(t Tag) EnumMap {
|
||
|
if r.enums == nil {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
return r.enums[t]
|
||
|
}
|
||
|
|
||
|
func (r *Registry) IsBitmask(t Tag) bool {
|
||
|
if e := r.EnumForTag(t); e != nil {
|
||
|
return e.Bitmask()
|
||
|
}
|
||
|
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (r *Registry) IsEnum(t Tag) bool {
|
||
|
if e := r.EnumForTag(t); e != nil {
|
||
|
return !e.Bitmask()
|
||
|
}
|
||
|
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (r *Registry) Tags() EnumMap {
|
||
|
return &r.tags
|
||
|
}
|
||
|
|
||
|
func (r *Registry) Types() EnumMap {
|
||
|
return &r.types
|
||
|
}
|
||
|
|
||
|
func (r *Registry) FormatEnum(t Tag, v uint32) string {
|
||
|
return FormatEnum(v, r.EnumForTag(t))
|
||
|
}
|
||
|
|
||
|
func (r *Registry) FormatInt(t Tag, v int32) string {
|
||
|
return FormatInt(v, r.EnumForTag(t))
|
||
|
}
|
||
|
|
||
|
func (r *Registry) FormatTag(t Tag) string {
|
||
|
return FormatTag(uint32(t), &r.tags)
|
||
|
}
|
||
|
|
||
|
func (r *Registry) FormatTagCanonical(t Tag) string {
|
||
|
return FormatTagCanonical(uint32(t), &r.tags)
|
||
|
}
|
||
|
|
||
|
func (r *Registry) FormatType(t Type) string {
|
||
|
return FormatType(byte(t), &r.types)
|
||
|
}
|
||
|
|
||
|
func (r *Registry) ParseEnum(t Tag, s string) (uint32, error) {
|
||
|
return ParseEnum(s, r.EnumForTag(t))
|
||
|
}
|
||
|
|
||
|
func (r *Registry) ParseInt(t Tag, s string) (int32, error) {
|
||
|
return ParseInt(s, r.EnumForTag(t))
|
||
|
}
|
||
|
|
||
|
// ParseTag parses a string into Tag according the rules
|
||
|
// in the KMIP Profiles regarding encoding tag values.
|
||
|
// Returns TagNone if not found.
|
||
|
// Returns error if s is a malformed hex string, or a hex string of incorrect length
|
||
|
func (r *Registry) ParseTag(s string) (Tag, error) {
|
||
|
return ParseTag(s, &r.tags)
|
||
|
}
|
||
|
|
||
|
func (r *Registry) ParseType(s string) (Type, error) {
|
||
|
return ParseType(s, &r.types)
|
||
|
}
|
||
|
|
||
|
// uint32Slice attaches the methods of Interface to []int, sorting in increasing order.
|
||
|
type uint32Slice []uint32
|
||
|
|
||
|
func (p uint32Slice) Len() int { return len(p) }
|
||
|
func (p uint32Slice) Less(i, j int) bool { return p[i] < p[j] }
|
||
|
func (p uint32Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|