mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 02:33:34 +00:00
rebase: vendor files required for kmip
Signed-off-by: Rakshith R <rar@redhat.com>
This commit is contained in:
499
vendor/github.com/gemalto/kmip-go/ttlv/decoder.go
generated
vendored
Normal file
499
vendor/github.com/gemalto/kmip-go/ttlv/decoder.go
generated
vendored
Normal file
@ -0,0 +1,499 @@
|
||||
package ttlv
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
"github.com/ansel1/merry"
|
||||
)
|
||||
|
||||
var ErrUnexpectedValue = errors.New("no field was found to unmarshal value into")
|
||||
|
||||
// Unmarshal parses TTLV encoded data and stores the result
|
||||
// in the value pointed to by v.
|
||||
//
|
||||
// An error will be returned if v is nil or not a point, or
|
||||
// if b is not valid TTLV.
|
||||
//
|
||||
// Unmarshal will allocate values to store the result in, similar to the
|
||||
// json.Marshal. Generally, the destination value can be a pointer or
|
||||
// or a direct value. Currently, Unmarshal does not support anonymous fields.
|
||||
// They will be ignored. Private fields are ignored.
|
||||
//
|
||||
// Unmarshal maps TTLV values to golang values according to the following
|
||||
// rules:
|
||||
//
|
||||
// 1. If the destination value is interface{}, it will be set to the result
|
||||
// of TTLV.Value()
|
||||
// 2. If the destination implements Unmarshaler, that will be called.
|
||||
// 3. If the destination is a slice (except for []byte), append the
|
||||
// unmarshalled value to the slice
|
||||
// 4. Structure unmarshals into a struct. See rules
|
||||
// below for matching struct fields to the values in the Structure.
|
||||
// 5. Interval unmarshals into an int64
|
||||
// 6. DateTime and DateTimeExtended ummarshal into time.Time
|
||||
// 7. ByteString unmarshals to a []byte
|
||||
// 8. TextString unmarshals into a string
|
||||
// 9. Boolean unmarshals into a bool
|
||||
// 10. Enumeration can unmarshal into an int, int8, int16, int32, or their
|
||||
// uint counterparts. If the KMIP value overflows the destination, a
|
||||
// *UnmarshalerError with cause ErrIntOverflow is returned.
|
||||
// 11. Integer can unmarshal to the same types as Enumeration, with the
|
||||
// same overflow check.
|
||||
// 12. LongInteger unmarshals to int64 or uint64
|
||||
// 13. BitInteger unmarshals to big.Int.
|
||||
//
|
||||
// If the destination value is not a supported type, an *UnmarshalerError with
|
||||
// cause ErrUnsupportedTypeError is returned. If the source value's type is not recognized,
|
||||
// *UnmarshalerError with cause ErrInvalidType is returned.
|
||||
//
|
||||
// Unmarshaling Structure
|
||||
//
|
||||
// Unmarshal will try to match the values in the Structure with the fields in the
|
||||
// destination struct. Structure is an array of values, while a struct is more like
|
||||
// a map, so not all Structure values can be accurately represented by a golang struct.
|
||||
// In particular, a Structure can hold the same tag multiple times, e.g. 3 TagComment values
|
||||
// in a row.
|
||||
//
|
||||
// For each field in the struct, Unmarshal infers a KMIP Tag by examining both the name
|
||||
// and type of the field. It uses the following rules, in order:
|
||||
//
|
||||
// 1. If the type of a field is a struct, and the struct contains a field named "TTLVTag", and the field
|
||||
// has a "ttlv" struct tag, the value of the struct tag will be parsed using ParseTag(). If
|
||||
// parsing fails, an error is returned. The type and value of the TTLVTag field is ignored.
|
||||
// In this example, the F field will map to TagDeactivationDate:
|
||||
//
|
||||
// type Bar struct {
|
||||
// F Foo
|
||||
// }
|
||||
// type Foo struct {
|
||||
// TTLVTag struct{} `ttlv:"DeactivationDate"`
|
||||
// }
|
||||
//
|
||||
// If Bar uses a struct tag on F indicating a different tag, it is an error:
|
||||
//
|
||||
// type Bar struct {
|
||||
// F Foo `ttlv:"DerivationData"` // this will cause an ErrTagConflict
|
||||
// // because conflict Bar's field tag
|
||||
// // conflicts with Foo's intrinsic tag
|
||||
// F2 Foo `ttlv:"0x420034"` // the value can also be hex
|
||||
// }
|
||||
// 2. If the type of the field is a struct, and the struct contains a field named "TTLVTag",
|
||||
// and that field is of type ttlv.Tag and is not empty, the value of the field will be the
|
||||
// inferred Tag. For example:
|
||||
//
|
||||
// type Foo struct {
|
||||
// TTLVTag ttlv.Tag
|
||||
// }
|
||||
// f := Foo{TTLVTag: ttlv.TagState}
|
||||
//
|
||||
// This allows you to dynamically set the KMIP tag that a value will marshal to.
|
||||
// 3. The "ttlv" struct tag can be used to indicate the tag for a field. The value will
|
||||
// be parsed with ParseTag()
|
||||
//
|
||||
// type Bar struct {
|
||||
// F Foo `ttlv:"DerivationData"`
|
||||
// }
|
||||
//
|
||||
// 4. The name of the field is parsed with ParseTag():
|
||||
//
|
||||
// type Bar struct {
|
||||
// DerivationData int
|
||||
// }
|
||||
//
|
||||
// 5. The name of the field's type is parsed with ParseTab():
|
||||
//
|
||||
// type DerivationData int
|
||||
//
|
||||
// type Bar struct {
|
||||
// dd DerivationData
|
||||
// }
|
||||
//
|
||||
// If no tag value can be inferred, the field is ignored. Multiple fields
|
||||
// *cannot* map to the same KMIP tag. If they do, an ErrTagConflict will
|
||||
// be returned.
|
||||
//
|
||||
// Each value in the Structure will be matched against the first field
|
||||
// in the struct with the same inferred tag.
|
||||
//
|
||||
// If the value cannot be matched with a field, Unmarshal will look for
|
||||
// the first field with the "any" struct flag set and unmarshal into that:
|
||||
//
|
||||
// type Foo struct {
|
||||
// Comment string // the Comment will unmarshal into this
|
||||
// EverythingElse []interface{} `,any` // all other values will unmarshal into this
|
||||
// AnotherAny []interface{} `,any` // allowed, but ignored. first any field will always match
|
||||
// NotLegal []interface{} `TagComment,any` // you cannot specify a tag and the any flag.
|
||||
// // will return error
|
||||
// }
|
||||
//
|
||||
// If after applying these rules no destination field is found, the KMIP value is ignored.
|
||||
func Unmarshal(ttlv TTLV, v interface{}) error {
|
||||
return NewDecoder(bytes.NewReader(ttlv)).Decode(v)
|
||||
}
|
||||
|
||||
// Unmarshaler knows how to unmarshal a ttlv value into itself.
|
||||
// The decoder argument may be used to decode the ttlv value into
|
||||
// intermediary values if needed.
|
||||
type Unmarshaler interface {
|
||||
UnmarshalTTLV(d *Decoder, ttlv TTLV) error
|
||||
}
|
||||
|
||||
// Decoder reads KMIP values from a stream, and decodes them into golang values.
|
||||
// It currently only decodes TTLV encoded KMIP values.
|
||||
// TODO: support decoding XML and JSON, so their decoding can be configured
|
||||
//
|
||||
// If DisallowExtraValues is true, the decoder will return an error when decoding
|
||||
// Structures into structs and a matching field can't get found for every value.
|
||||
type Decoder struct {
|
||||
r io.Reader
|
||||
bufr *bufio.Reader
|
||||
DisallowExtraValues bool
|
||||
|
||||
currStruct reflect.Type
|
||||
currField string
|
||||
}
|
||||
|
||||
func NewDecoder(r io.Reader) *Decoder {
|
||||
return &Decoder{
|
||||
r: r,
|
||||
bufr: bufio.NewReader(r),
|
||||
}
|
||||
}
|
||||
|
||||
// Reset resets the internal state of the decoder for reuse.
|
||||
func (dec *Decoder) Reset(r io.Reader) {
|
||||
*dec = Decoder{
|
||||
r: r,
|
||||
bufr: dec.bufr,
|
||||
}
|
||||
dec.bufr.Reset(r)
|
||||
}
|
||||
|
||||
// Decode the first KMIP value from the reader into v.
|
||||
// See Unmarshal for decoding rules.
|
||||
func (dec *Decoder) Decode(v interface{}) error {
|
||||
ttlv, err := dec.NextTTLV()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return dec.DecodeValue(v, ttlv)
|
||||
}
|
||||
|
||||
// DecodeValue decodes a ttlv value into v. This doesn't read anything
|
||||
// from the Decoder's reader.
|
||||
// See Unmarshal for decoding rules.
|
||||
func (dec *Decoder) DecodeValue(v interface{}, ttlv TTLV) error {
|
||||
val := reflect.ValueOf(v)
|
||||
if val.Kind() != reflect.Ptr {
|
||||
return merry.New("non-pointer passed to Decode")
|
||||
}
|
||||
|
||||
return dec.unmarshal(val, ttlv)
|
||||
}
|
||||
|
||||
func (dec *Decoder) unmarshal(val reflect.Value, ttlv TTLV) error {
|
||||
if len(ttlv) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load value from interface, but only if the result will be
|
||||
// usefully addressable.
|
||||
if val.Kind() == reflect.Interface && !val.IsNil() {
|
||||
e := val.Elem()
|
||||
if e.Kind() == reflect.Ptr && !e.IsNil() {
|
||||
val = e
|
||||
}
|
||||
}
|
||||
|
||||
if val.Kind() == reflect.Ptr {
|
||||
if val.IsNil() {
|
||||
val.Set(reflect.New(val.Type().Elem()))
|
||||
}
|
||||
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
if val.Type().Implements(unmarshalerType) {
|
||||
return val.Interface().(Unmarshaler).UnmarshalTTLV(dec, ttlv) //nolint:forcetypeassert
|
||||
}
|
||||
|
||||
if val.CanAddr() {
|
||||
valAddr := val.Addr()
|
||||
if valAddr.CanInterface() && valAddr.Type().Implements(unmarshalerType) {
|
||||
return valAddr.Interface().(Unmarshaler).UnmarshalTTLV(dec, ttlv) //nolint:forcetypeassert
|
||||
}
|
||||
}
|
||||
|
||||
switch val.Kind() {
|
||||
case reflect.Interface:
|
||||
if ttlv.Type() == TypeStructure {
|
||||
// if the value is a structure, set the whole TTLV
|
||||
// as the value.
|
||||
val.Set(reflect.ValueOf(ttlv))
|
||||
} else {
|
||||
// set blank interface equal to the TTLV.Value()
|
||||
val.Set(reflect.ValueOf(ttlv.Value()))
|
||||
}
|
||||
|
||||
return nil
|
||||
case reflect.Slice:
|
||||
typ := val.Type()
|
||||
if typ.Elem() == byteType {
|
||||
// []byte
|
||||
break
|
||||
}
|
||||
|
||||
// Slice of element values.
|
||||
// Grow slice.
|
||||
n := val.Len()
|
||||
val.Set(reflect.Append(val, reflect.Zero(val.Type().Elem())))
|
||||
|
||||
// Recur to read element into slice.
|
||||
if err := dec.unmarshal(val.Index(n), ttlv); err != nil {
|
||||
val.SetLen(n)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
|
||||
typeMismatchErr := func() error {
|
||||
e := &UnmarshalerError{
|
||||
Struct: dec.currStruct,
|
||||
Field: dec.currField,
|
||||
Tag: ttlv.Tag(),
|
||||
Type: ttlv.Type(),
|
||||
Val: val.Type(),
|
||||
}
|
||||
err := merry.WrapSkipping(e, 1).WithCause(ErrUnsupportedTypeError)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
switch ttlv.Type() {
|
||||
case TypeStructure:
|
||||
if val.Kind() != reflect.Struct {
|
||||
return typeMismatchErr()
|
||||
}
|
||||
// stash currStruct
|
||||
currStruct := dec.currStruct
|
||||
err := dec.unmarshalStructure(ttlv, val)
|
||||
// restore currStruct
|
||||
dec.currStruct = currStruct
|
||||
|
||||
return err
|
||||
case TypeInterval:
|
||||
if val.Kind() != reflect.Int64 {
|
||||
return typeMismatchErr()
|
||||
}
|
||||
|
||||
val.SetInt(int64(ttlv.ValueInterval()))
|
||||
case TypeDateTime, TypeDateTimeExtended:
|
||||
if val.Type() != timeType {
|
||||
return typeMismatchErr()
|
||||
}
|
||||
|
||||
val.Set(reflect.ValueOf(ttlv.ValueDateTime()))
|
||||
case TypeByteString:
|
||||
if val.Kind() != reflect.Slice && val.Type().Elem() != byteType {
|
||||
return typeMismatchErr()
|
||||
}
|
||||
|
||||
val.SetBytes(ttlv.ValueByteString())
|
||||
case TypeTextString:
|
||||
if val.Kind() != reflect.String {
|
||||
return typeMismatchErr()
|
||||
}
|
||||
|
||||
val.SetString(ttlv.ValueTextString())
|
||||
case TypeBoolean:
|
||||
if val.Kind() != reflect.Bool {
|
||||
return typeMismatchErr()
|
||||
}
|
||||
|
||||
val.SetBool(ttlv.ValueBoolean())
|
||||
// nolint:dupl
|
||||
case TypeEnumeration:
|
||||
switch val.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
|
||||
i := int64(ttlv.ValueEnumeration())
|
||||
if val.OverflowInt(i) {
|
||||
return dec.newUnmarshalerError(ttlv, val.Type(), ErrIntOverflow)
|
||||
}
|
||||
|
||||
val.SetInt(i)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
|
||||
i := uint64(ttlv.ValueEnumeration())
|
||||
if val.OverflowUint(i) {
|
||||
return dec.newUnmarshalerError(ttlv, val.Type(), ErrIntOverflow)
|
||||
}
|
||||
|
||||
val.SetUint(i)
|
||||
default:
|
||||
return typeMismatchErr()
|
||||
}
|
||||
// nolint:dupl
|
||||
case TypeInteger:
|
||||
switch val.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
|
||||
i := int64(ttlv.ValueInteger())
|
||||
if val.OverflowInt(i) {
|
||||
return dec.newUnmarshalerError(ttlv, val.Type(), ErrIntOverflow)
|
||||
}
|
||||
|
||||
val.SetInt(i)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
|
||||
i := uint64(ttlv.ValueInteger())
|
||||
if val.OverflowUint(i) {
|
||||
return dec.newUnmarshalerError(ttlv, val.Type(), ErrIntOverflow)
|
||||
}
|
||||
|
||||
val.SetUint(i)
|
||||
default:
|
||||
return typeMismatchErr()
|
||||
}
|
||||
case TypeLongInteger:
|
||||
switch val.Kind() {
|
||||
case reflect.Int64:
|
||||
val.SetInt(ttlv.ValueLongInteger())
|
||||
case reflect.Uint64:
|
||||
val.SetUint(uint64(ttlv.ValueLongInteger()))
|
||||
default:
|
||||
return typeMismatchErr()
|
||||
}
|
||||
case TypeBigInteger:
|
||||
if val.Type() != bigIntType {
|
||||
return typeMismatchErr()
|
||||
}
|
||||
|
||||
val.Set(reflect.ValueOf(*ttlv.ValueBigInteger()))
|
||||
default:
|
||||
return dec.newUnmarshalerError(ttlv, val.Type(), ErrInvalidType)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dec *Decoder) unmarshalStructure(ttlv TTLV, val reflect.Value) error {
|
||||
ti, err := getTypeInfo(val.Type())
|
||||
if err != nil {
|
||||
return dec.newUnmarshalerError(ttlv, val.Type(), err)
|
||||
}
|
||||
|
||||
if ti.tagField != nil && ti.tagField.ti.typ == tagType {
|
||||
val.FieldByIndex(ti.tagField.index).Set(reflect.ValueOf(ttlv.Tag()))
|
||||
}
|
||||
|
||||
fields := ti.valueFields
|
||||
|
||||
// push currStruct (caller will pop)
|
||||
dec.currStruct = val.Type()
|
||||
|
||||
for n := ttlv.ValueStructure(); n != nil; n = n.Next() {
|
||||
fldIdx := -1
|
||||
|
||||
for i := range fields {
|
||||
if fields[i].flags.any() {
|
||||
// if this is the first any field found, keep track
|
||||
// of it as the current candidate match, but
|
||||
// keep looking for a tag match
|
||||
if fldIdx == -1 {
|
||||
fldIdx = i
|
||||
}
|
||||
} else if fields[i].tag == n.Tag() {
|
||||
// tag match found
|
||||
// we can stop looking
|
||||
fldIdx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if fldIdx > -1 {
|
||||
// push currField
|
||||
currField := dec.currField
|
||||
dec.currField = fields[fldIdx].name
|
||||
err := dec.unmarshal(val.FieldByIndex(fields[fldIdx].index), n)
|
||||
// restore currField
|
||||
dec.currField = currField
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if dec.DisallowExtraValues {
|
||||
return dec.newUnmarshalerError(ttlv, val.Type(), ErrUnexpectedValue)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NextTTLV reads the next, full KMIP value off the reader.
|
||||
func (dec *Decoder) NextTTLV() (TTLV, error) {
|
||||
// first, read the header
|
||||
header, err := dec.bufr.Peek(8)
|
||||
if err != nil {
|
||||
return nil, merry.Wrap(err)
|
||||
}
|
||||
|
||||
if err := TTLV(header).ValidHeader(); err != nil {
|
||||
// bad header, abort
|
||||
return TTLV(header), merry.Prependf(err, "invalid header: %v", TTLV(header))
|
||||
}
|
||||
|
||||
// allocate a buffer large enough for the entire message
|
||||
fullLen := TTLV(header).FullLen()
|
||||
buf := make([]byte, fullLen)
|
||||
|
||||
var totRead int
|
||||
|
||||
for {
|
||||
n, err := dec.bufr.Read(buf[totRead:])
|
||||
if err != nil {
|
||||
return TTLV(buf), merry.Wrap(err)
|
||||
}
|
||||
|
||||
totRead += n
|
||||
if totRead >= fullLen {
|
||||
// we've read off a single full message
|
||||
return buf, nil
|
||||
} // else keep reading
|
||||
}
|
||||
}
|
||||
|
||||
func (dec *Decoder) newUnmarshalerError(ttlv TTLV, valType reflect.Type, cause error) merry.Error {
|
||||
e := &UnmarshalerError{
|
||||
Struct: dec.currStruct,
|
||||
Field: dec.currField,
|
||||
Tag: ttlv.Tag(),
|
||||
Type: ttlv.Type(),
|
||||
Val: valType,
|
||||
}
|
||||
|
||||
return merry.WrapSkipping(e, 1).WithCause(cause)
|
||||
}
|
||||
|
||||
type UnmarshalerError struct {
|
||||
// Val is the type of the destination value
|
||||
Val reflect.Type
|
||||
// Struct is the type of the containing struct if the value is a field
|
||||
Struct reflect.Type
|
||||
// Field is the name of the value field
|
||||
Field string
|
||||
Tag Tag
|
||||
Type Type
|
||||
}
|
||||
|
||||
func (e *UnmarshalerError) Error() string {
|
||||
msg := "kmip: error unmarshaling " + e.Tag.String() + " with type " + e.Type.String() + " into value of type " + e.Val.Name()
|
||||
if e.Struct != nil {
|
||||
msg += " in struct field " + e.Struct.Name() + "." + e.Field
|
||||
}
|
||||
|
||||
return msg
|
||||
}
|
22
vendor/github.com/gemalto/kmip-go/ttlv/docs.go
generated
vendored
Normal file
22
vendor/github.com/gemalto/kmip-go/ttlv/docs.go
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
// Package ttlv encodes and decodes the 3 wire formats defined in the KMIP specification:
|
||||
//
|
||||
// 1. TTLV (the default, binary wire format)
|
||||
// 2. JSON
|
||||
// 3. XML
|
||||
//
|
||||
// The core representation of KMIP values is the ttlv.TTLV type, which is
|
||||
// a []byte encoded in the TTLV binary format. The ttlv.TTLV type knows how to marshal/
|
||||
// unmarshal to and from the JSON and XML encoding formats.
|
||||
//
|
||||
// This package also knows how to marshal and unmarshal ttlv.TTLV values to golang structs,
|
||||
// in a way similar to the json or xml packages.
|
||||
//
|
||||
// See Marshal() and Unmarshal() for the rules about how golang values map to KMIP TTLVs.
|
||||
// Encoder and Decoder can be used to process streams of KMIP values.
|
||||
//
|
||||
// This package holds a registry of type, tag, and enum value names, which are used to transcode
|
||||
// strings into these values. KMIP 1.4 names will be automatically loaded into the
|
||||
// DefaultRegistry. See the kmip20 package to add definitions for 2.0 names.
|
||||
//
|
||||
// Print() and PrettyPrintHex() can be used to debug TTLV values.
|
||||
package ttlv
|
962
vendor/github.com/gemalto/kmip-go/ttlv/encoder.go
generated
vendored
Normal file
962
vendor/github.com/gemalto/kmip-go/ttlv/encoder.go
generated
vendored
Normal file
@ -0,0 +1,962 @@
|
||||
package ttlv
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ansel1/merry"
|
||||
)
|
||||
|
||||
const structFieldTag = "ttlv"
|
||||
|
||||
var (
|
||||
ErrIntOverflow = fmt.Errorf("value exceeds max int value %d", math.MaxInt32)
|
||||
ErrUnsupportedEnumTypeError = errors.New("unsupported type for enums, must be string, or int types")
|
||||
ErrUnsupportedTypeError = errors.New("marshaling/unmarshaling is not supported for this type")
|
||||
ErrNoTag = errors.New("unable to determine tag for field")
|
||||
ErrTagConflict = errors.New("tag conflict")
|
||||
)
|
||||
|
||||
// Marshal encodes a golang value into a KMIP value.
|
||||
//
|
||||
// An error will be returned if v is an invalid pointer.
|
||||
//
|
||||
// Currently, Marshal does not support anonymous fields.
|
||||
// Private fields are ignored.
|
||||
//
|
||||
// Marshal maps the golang value to a KMIP tag, type, and value
|
||||
// encoding. To determine the KMIP tag, Marshal uses the same rules
|
||||
// as Unmarshal.
|
||||
//
|
||||
// The appropriate type and encoding are inferred from the golang type
|
||||
// and from the inferred KMIP tag, according to these rules:
|
||||
//
|
||||
// 1. If the value is a TTLV, it is copied byte for byte
|
||||
// 2. If the value implements Marshaler, call that
|
||||
// 3. If the struct field has an "omitempty" flag, and the value is
|
||||
// zero, skip the field:
|
||||
//
|
||||
// type Foo struct {
|
||||
// Comment string `ttlv:,omitempty`
|
||||
// }
|
||||
//
|
||||
// 4. If the value is a slice (except []byte) or array, marshal all
|
||||
// values concatenated
|
||||
// 5. If a tag has not been inferred at this point, return *MarshalerError with
|
||||
// cause ErrNoTag
|
||||
// 6. If the Tag is registered as an enum, or has the "enum" struct tag flag, attempt
|
||||
// to marshal as an Enumeration. int, int8, int16, int32, and their uint counterparts
|
||||
// can be marshaled as an Enumeration. A string can be marshaled to an Enumeration
|
||||
// if the string contains a number, a 4 byte (8 char) hex string with the prefix "0x",
|
||||
// or the normalized name of an enum value registered to this tag. Examples:
|
||||
//
|
||||
// type Foo struct {
|
||||
// CancellationResult string // will encode as an Enumeration because
|
||||
// // the tag CancellationResult is registered
|
||||
// // as an enum.
|
||||
// C int `ttlv:"Comment,enum" // The tag Comment is not registered as an enum
|
||||
// // but the enum flag will force this to encode
|
||||
// // as an enumeration.
|
||||
// }
|
||||
//
|
||||
// If the string can't be interpreted as an enum value, it will be encoded as a TextString. If
|
||||
// the "enum" struct flag is set, the value *must* successfully encode to an Enumeration using
|
||||
// above rules, or an error is returned.
|
||||
// 7. If the Tag is registered as a bitmask, or has the "bitmask" struct tag flag, attempt
|
||||
// to marshal to an Integer, following the same rules as for Enumerations. The ParseInt()
|
||||
// function is used to parse string values.
|
||||
// 9. time.Time marshals to DateTime. If the field has the "datetimeextended" struct flag,
|
||||
// marshal as DateTimeExtended. Example:
|
||||
//
|
||||
// type Foo struct {
|
||||
// ActivationDate time.Time `ttlv:",datetimeextended"`
|
||||
// }
|
||||
//
|
||||
// 10. big.Int marshals to BigInteger
|
||||
// 11. time.Duration marshals to Interval
|
||||
// 12. string marshals to TextString
|
||||
// 13. []byte marshals to ByteString
|
||||
// 14. all int and uint variants except int64 and uint64 marshal to Integer. If the golang
|
||||
// value overflows the KMIP value, *MarshalerError with cause ErrIntOverflow is returned
|
||||
// 15. int64 and uint64 marshal to LongInteger
|
||||
// 16. bool marshals to Boolean
|
||||
// 17. structs marshal to Structure. Each field of the struct will be marshaled into the
|
||||
// values of the Structure according to the above rules.
|
||||
//
|
||||
// Any other golang type will return *MarshalerError with cause ErrUnsupportedTypeError.
|
||||
func Marshal(v interface{}) (TTLV, error) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
|
||||
err := NewEncoder(buf).Encode(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// Marshaler knows how to encode itself to TTLV.
|
||||
// The implementation should use the primitive methods of the encoder,
|
||||
// such as EncodeInteger(), etc.
|
||||
//
|
||||
// The tag inferred by the Encoder from the field or type information is
|
||||
// passed as an argument, but the implementation can choose to ignore it.
|
||||
type Marshaler interface {
|
||||
MarshalTTLV(e *Encoder, tag Tag) error
|
||||
}
|
||||
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
return &Encoder{w: w}
|
||||
}
|
||||
|
||||
// Encode a single value and flush to the writer. The tag will be inferred from
|
||||
// the value. If no tag can be inferred, an error is returned.
|
||||
// See Marshal for encoding rules.
|
||||
func (e *Encoder) Encode(v interface{}) error {
|
||||
return e.EncodeValue(TagNone, v)
|
||||
}
|
||||
|
||||
// EncodeValue encodes a single value with the given tag and flushes it
|
||||
// to the writer.
|
||||
// See Marshal for encoding rules.
|
||||
func (e *Encoder) EncodeValue(tag Tag, v interface{}) error {
|
||||
err := e.encode(tag, reflect.ValueOf(v), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return e.Flush()
|
||||
}
|
||||
|
||||
// EncodeStructure encodes a Structure with the given tag to the writer.
|
||||
// The function argument should encode the enclosed values inside the Structure.
|
||||
// Call Flush() to write the data to the writer.
|
||||
func (e *Encoder) EncodeStructure(tag Tag, f func(e *Encoder) error) error {
|
||||
e.encodeDepth++
|
||||
i := e.encBuf.begin(tag, TypeStructure)
|
||||
err := f(e)
|
||||
e.encBuf.end(i)
|
||||
e.encodeDepth--
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// EncodeEnumeration, along with the other Encode<Type> methods, encodes a
|
||||
// single KMIP value with the given tag to an internal buffer. These methods
|
||||
// do not flush the data to the writer: call Flush() to flush the buffer.
|
||||
func (e *Encoder) EncodeEnumeration(tag Tag, v uint32) {
|
||||
e.encBuf.encodeEnum(tag, v)
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeInteger(tag Tag, v int32) {
|
||||
e.encBuf.encodeInt(tag, v)
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeLongInteger(tag Tag, v int64) {
|
||||
e.encBuf.encodeLongInt(tag, v)
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeInterval(tag Tag, v time.Duration) {
|
||||
e.encBuf.encodeInterval(tag, v)
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeDateTime(tag Tag, v time.Time) {
|
||||
e.encBuf.encodeDateTime(tag, v)
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeDateTimeExtended(tag Tag, v time.Time) {
|
||||
e.encBuf.encodeDateTimeExtended(tag, v)
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeBigInteger(tag Tag, v *big.Int) {
|
||||
e.encBuf.encodeBigInt(tag, v)
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeBoolean(tag Tag, v bool) {
|
||||
e.encBuf.encodeBool(tag, v)
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeTextString(tag Tag, v string) {
|
||||
e.encBuf.encodeTextString(tag, v)
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeByteString(tag Tag, v []byte) {
|
||||
e.encBuf.encodeByteString(tag, v)
|
||||
}
|
||||
|
||||
// Flush flushes the internal encoding buffer to the writer.
|
||||
func (e *Encoder) Flush() error {
|
||||
if e.encodeDepth > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := e.encBuf.WriteTo(e.w)
|
||||
e.encBuf.Reset()
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type MarshalerError struct {
|
||||
// Type is the golang type of the value being marshaled
|
||||
Type reflect.Type
|
||||
// Struct is the name of the enclosing struct if the marshaled value is a field.
|
||||
Struct string
|
||||
// Field is the name of the field being marshaled
|
||||
Field string
|
||||
Tag Tag
|
||||
}
|
||||
|
||||
func (e *MarshalerError) Error() string {
|
||||
msg := "kmip: error marshaling value"
|
||||
if e.Type != nil {
|
||||
msg += " of type " + e.Type.String()
|
||||
}
|
||||
|
||||
if e.Struct != "" {
|
||||
msg += " in struct field " + e.Struct + "." + e.Field
|
||||
}
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
func (e *Encoder) marshalingError(tag Tag, t reflect.Type, cause error) merry.Error {
|
||||
err := &MarshalerError{
|
||||
Type: t,
|
||||
Struct: e.currStruct,
|
||||
Field: e.currField,
|
||||
Tag: tag,
|
||||
}
|
||||
|
||||
return merry.WrapSkipping(err, 1).WithCause(cause)
|
||||
}
|
||||
|
||||
var (
|
||||
byteType = reflect.TypeOf(byte(0))
|
||||
marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
|
||||
unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
|
||||
timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
|
||||
bigIntPtrType = reflect.TypeOf((*big.Int)(nil))
|
||||
bigIntType = bigIntPtrType.Elem()
|
||||
durationType = reflect.TypeOf(time.Nanosecond)
|
||||
ttlvType = reflect.TypeOf((*TTLV)(nil)).Elem()
|
||||
tagType = reflect.TypeOf(Tag(0))
|
||||
)
|
||||
|
||||
var invalidValue = reflect.Value{}
|
||||
|
||||
// indirect dives into interfaces values, and one level deep into pointers
|
||||
// returns an invalid value if the resolved value is nil or invalid.
|
||||
func indirect(v reflect.Value) reflect.Value {
|
||||
if !v.IsValid() {
|
||||
return v
|
||||
}
|
||||
|
||||
if v.Kind() == reflect.Interface {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
if !v.IsValid() {
|
||||
return v
|
||||
}
|
||||
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Func, reflect.Slice, reflect.Map, reflect.Chan, reflect.Ptr, reflect.Interface:
|
||||
if v.IsNil() {
|
||||
return invalidValue
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
var zeroBigInt = big.Int{}
|
||||
|
||||
func isEmptyValue(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
||||
return v.Len() == 0
|
||||
case reflect.Bool:
|
||||
return !v.Bool()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint() == 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float() == 0
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
return v.IsNil()
|
||||
default:
|
||||
}
|
||||
|
||||
switch v.Type() {
|
||||
case timeType:
|
||||
return v.Interface().(time.Time).IsZero() //nolint:forcetypeassert
|
||||
case bigIntType:
|
||||
i := v.Interface().(big.Int) //nolint:forcetypeassert
|
||||
return zeroBigInt.Cmp(&i) == 0
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (e *Encoder) encode(tag Tag, v reflect.Value, fi *fieldInfo) error {
|
||||
// if pointer or interface
|
||||
v = indirect(v)
|
||||
if !v.IsValid() {
|
||||
return nil
|
||||
}
|
||||
|
||||
typ := v.Type()
|
||||
|
||||
if typ == ttlvType {
|
||||
// fast path: if the value is TTLV, we write it directly to the output buffer
|
||||
_, err := e.encBuf.Write(v.Bytes())
|
||||
return err
|
||||
}
|
||||
|
||||
typeInfo, err := getTypeInfo(typ)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tag == TagNone {
|
||||
tag = tagForMarshal(v, typeInfo, fi)
|
||||
}
|
||||
|
||||
var flags fieldFlags
|
||||
if fi != nil {
|
||||
flags = fi.flags
|
||||
}
|
||||
|
||||
// check for Marshaler
|
||||
switch {
|
||||
case typ.Implements(marshalerType):
|
||||
if flags.omitEmpty() && isEmptyValue(v) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return v.Interface().(Marshaler).MarshalTTLV(e, tag) //nolint:forcetypeassert
|
||||
case v.CanAddr():
|
||||
pv := v.Addr()
|
||||
|
||||
pvtyp := pv.Type()
|
||||
if pvtyp.Implements(marshalerType) {
|
||||
if flags.omitEmpty() && isEmptyValue(v) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return pv.Interface().(Marshaler).MarshalTTLV(e, tag) //nolint:forcetypeassert
|
||||
}
|
||||
}
|
||||
|
||||
// If the type doesn't implement Marshaler, then validate the value is a supported kind
|
||||
switch v.Kind() {
|
||||
case reflect.Chan, reflect.Map, reflect.Func, reflect.Ptr, reflect.UnsafePointer, reflect.Uintptr, reflect.Float32,
|
||||
reflect.Float64,
|
||||
reflect.Complex64,
|
||||
reflect.Complex128,
|
||||
reflect.Interface:
|
||||
return e.marshalingError(tag, v.Type(), ErrUnsupportedTypeError)
|
||||
default:
|
||||
}
|
||||
|
||||
// skip if value is empty and tags include omitempty
|
||||
if flags.omitEmpty() && isEmptyValue(v) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// recurse to handle slices of values
|
||||
switch v.Kind() {
|
||||
case reflect.Slice:
|
||||
if typ.Elem() == byteType {
|
||||
// special case, encode as a ByteString, handled below
|
||||
break
|
||||
}
|
||||
|
||||
fallthrough
|
||||
case reflect.Array:
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
// turn off the omit empty flag. applies at the field level,
|
||||
// not to each member of the slice
|
||||
// TODO: is this true?
|
||||
var fi2 *fieldInfo
|
||||
if fi != nil {
|
||||
fi2 = &fieldInfo{}
|
||||
// make a copy.
|
||||
*fi2 = *fi
|
||||
fi2.flags &^= fOmitEmpty
|
||||
}
|
||||
|
||||
err := e.encode(tag, v.Index(i), fi2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
|
||||
if tag == TagNone {
|
||||
return e.marshalingError(tag, v.Type(), ErrNoTag)
|
||||
}
|
||||
|
||||
// handle enums and bitmasks
|
||||
//
|
||||
// If the field has the "enum" or "bitmask" flag, or the tag is registered as an enum or bitmask,
|
||||
// attempt to interpret the go value as such.
|
||||
//
|
||||
// If the field is explicitly flag, return an error if the value can't be interpreted. Otherwise
|
||||
// ignore errors and let processing fallthrough to the type-based encoding.
|
||||
enumMap := DefaultRegistry.EnumForTag(tag)
|
||||
if flags.enum() || flags.bitmask() || enumMap != nil {
|
||||
switch typ.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
|
||||
i := v.Int()
|
||||
|
||||
if flags.bitmask() || (enumMap != nil && enumMap.Bitmask()) {
|
||||
e.encBuf.encodeInt(tag, int32(i))
|
||||
} else {
|
||||
e.encBuf.encodeEnum(tag, uint32(i))
|
||||
}
|
||||
|
||||
return nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
|
||||
i := v.Uint()
|
||||
|
||||
if flags.bitmask() || (enumMap != nil && enumMap.Bitmask()) {
|
||||
e.encBuf.encodeInt(tag, int32(i))
|
||||
} else {
|
||||
e.encBuf.encodeEnum(tag, uint32(i))
|
||||
}
|
||||
|
||||
return nil
|
||||
case reflect.String:
|
||||
s := v.String()
|
||||
|
||||
if flags.bitmask() || (enumMap != nil && enumMap.Bitmask()) {
|
||||
i, err := ParseInt(s, enumMap)
|
||||
if err == nil {
|
||||
e.encBuf.encodeInt(tag, i)
|
||||
return nil
|
||||
}
|
||||
// only throw an error if the field is explicitly marked as a bitmask
|
||||
// otherwise just ignore it, and let it encode as a string later on.
|
||||
if flags.bitmask() {
|
||||
// if we couldn't parse the string as an enum value
|
||||
return e.marshalingError(tag, typ, err)
|
||||
}
|
||||
} else {
|
||||
i, err := ParseEnum(s, enumMap)
|
||||
if err == nil {
|
||||
e.encBuf.encodeEnum(tag, i)
|
||||
return nil
|
||||
}
|
||||
// only throw an error if the field is explicitly marked as an enum
|
||||
// otherwise just ignore it, and let it encode as a string later on.
|
||||
if flags.enum() {
|
||||
// if we couldn't parse the string as an enum value
|
||||
return e.marshalingError(tag, typ, err)
|
||||
}
|
||||
}
|
||||
default:
|
||||
if flags.enum() || flags.bitmask() {
|
||||
return e.marshalingError(tag, typ, ErrUnsupportedEnumTypeError).Append(typ.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle special types
|
||||
switch typ {
|
||||
case timeType:
|
||||
if flags.dateTimeExt() {
|
||||
e.encBuf.encodeDateTimeExtended(tag, v.Interface().(time.Time)) //nolint:forcetypeassert
|
||||
} else {
|
||||
e.encBuf.encodeDateTime(tag, v.Interface().(time.Time)) //nolint:forcetypeassert
|
||||
}
|
||||
|
||||
return nil
|
||||
case bigIntType:
|
||||
bi := v.Interface().(big.Int) //nolint:forcetypeassert
|
||||
e.encBuf.encodeBigInt(tag, &bi)
|
||||
|
||||
return nil
|
||||
case bigIntPtrType:
|
||||
e.encBuf.encodeBigInt(tag, v.Interface().(*big.Int)) //nolint:forcetypeassert
|
||||
return nil
|
||||
case durationType:
|
||||
e.encBuf.encodeInterval(tag, time.Duration(v.Int()))
|
||||
return nil
|
||||
}
|
||||
|
||||
// handle the rest of the kinds
|
||||
switch typ.Kind() {
|
||||
case reflect.Struct:
|
||||
// push current struct onto stack
|
||||
currStruct := e.currStruct
|
||||
e.currStruct = typ.Name()
|
||||
|
||||
err = e.EncodeStructure(tag, func(e *Encoder) error {
|
||||
for _, field := range typeInfo.valueFields {
|
||||
fv := v.FieldByIndex(field.index)
|
||||
|
||||
// note: we're staying in reflection world here instead of
|
||||
// converting back to an interface{} value and going through
|
||||
// the non-reflection path again. Calling Interface()
|
||||
// on the reflect value would make a potentially addressable value
|
||||
// into an unaddressable value, reducing the chances we can coerce
|
||||
// the value into a Marshalable.
|
||||
//
|
||||
// tl;dr
|
||||
// Consider a type which implements Marshaler with
|
||||
// a pointer receiver, and a struct with a non-pointer field of that type:
|
||||
//
|
||||
// type Wheel struct{}
|
||||
// func (*Wheel) MarshalTTLV(...)
|
||||
//
|
||||
// type Car struct{
|
||||
// Wheel Wheel
|
||||
// }
|
||||
//
|
||||
// When traversing the Car struct, should the encoder invoke Wheel's
|
||||
// Marshaler method, or not? Technically, the type `Wheel`
|
||||
// doesn't implement the Marshaler interface. Only the type `*Wheel`
|
||||
// implements it. However, the other encoders in the SDK, like JSON
|
||||
// and XML, will try, if possible, to get a pointer to field values like this, in
|
||||
// order to invoke the Marshaler interface anyway.
|
||||
//
|
||||
// Encoders can only get a pointer to field values if the field
|
||||
// value is `addressable`. Addressability is explained in the docs for reflect.Value#CanAddr().
|
||||
// Using reflection to turn a reflect.Value() back into an interface{}
|
||||
// can make a potentially addressable value (like the field of an addressable struct)
|
||||
// into an unaddressable value (reflect.Value#Interface{} always returns an unaddressable
|
||||
// copy).
|
||||
|
||||
// push the currField
|
||||
currField := e.currField
|
||||
e.currField = field.name
|
||||
err := e.encode(TagNone, fv, &field) //nolint:gosec,scopelint
|
||||
// pop the currField
|
||||
e.currField = currField
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
// pop current struct
|
||||
e.currStruct = currStruct
|
||||
|
||||
return err
|
||||
case reflect.String:
|
||||
e.encBuf.encodeTextString(tag, v.String())
|
||||
case reflect.Slice:
|
||||
// special case, encode as a ByteString
|
||||
// all slices which aren't []byte should have been handled above
|
||||
// the call to v.Bytes() will panic if this assumption is wrong
|
||||
e.encBuf.encodeByteString(tag, v.Bytes())
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
|
||||
i := v.Int()
|
||||
if i > math.MaxInt32 {
|
||||
return e.marshalingError(tag, typ, ErrIntOverflow)
|
||||
}
|
||||
|
||||
e.encBuf.encodeInt(tag, int32(i))
|
||||
|
||||
return nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
|
||||
u := v.Uint()
|
||||
if u > math.MaxInt32 {
|
||||
return e.marshalingError(tag, typ, ErrIntOverflow)
|
||||
}
|
||||
|
||||
e.encBuf.encodeInt(tag, int32(u))
|
||||
|
||||
return nil
|
||||
case reflect.Uint64:
|
||||
u := v.Uint()
|
||||
e.encBuf.encodeLongInt(tag, int64(u))
|
||||
|
||||
return nil
|
||||
case reflect.Int64:
|
||||
e.encBuf.encodeLongInt(tag, v.Int())
|
||||
return nil
|
||||
case reflect.Bool:
|
||||
e.encBuf.encodeBool(tag, v.Bool())
|
||||
default:
|
||||
// all kinds should have been handled by now
|
||||
panic(errors.New("should never get here"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagForMarshal(v reflect.Value, ti typeInfo, fi *fieldInfo) Tag {
|
||||
// the tag on the TTLVTag field
|
||||
if ti.tagField != nil && ti.tagField.explicitTag != TagNone {
|
||||
return ti.tagField.explicitTag
|
||||
}
|
||||
|
||||
// the value of the TTLVTag field of type Tag
|
||||
if v.IsValid() && ti.tagField != nil && ti.tagField.ti.typ == tagType {
|
||||
tag := v.FieldByIndex(ti.tagField.index).Interface().(Tag) //nolint:forcetypeassert
|
||||
if tag != TagNone {
|
||||
return tag
|
||||
}
|
||||
}
|
||||
|
||||
// if value is in a struct field, infer the tag from the field
|
||||
// else infer from the value's type name
|
||||
if fi != nil {
|
||||
return fi.tag
|
||||
}
|
||||
|
||||
return ti.inferredTag
|
||||
}
|
||||
|
||||
// encBuf encodes basic KMIP types into TTLV.
|
||||
type encBuf struct {
|
||||
bytes.Buffer
|
||||
}
|
||||
|
||||
func (h *encBuf) begin(tag Tag, typ Type) int {
|
||||
_ = h.WriteByte(byte(tag >> 16))
|
||||
_ = h.WriteByte(byte(tag >> 8))
|
||||
_ = h.WriteByte(byte(tag))
|
||||
_ = h.WriteByte(byte(typ))
|
||||
_, _ = h.Write(zeros[:4])
|
||||
|
||||
return h.Len()
|
||||
}
|
||||
|
||||
func (h *encBuf) end(i int) {
|
||||
n := h.Len() - i
|
||||
if m := n % 8; m > 0 {
|
||||
_, _ = h.Write(zeros[:8-m])
|
||||
}
|
||||
|
||||
binary.BigEndian.PutUint32(h.Bytes()[i-4:], uint32(n))
|
||||
}
|
||||
|
||||
func (h *encBuf) writeLongIntVal(tag Tag, typ Type, i int64) {
|
||||
s := h.begin(tag, typ)
|
||||
ll := h.Len()
|
||||
_, _ = h.Write(zeros[:8])
|
||||
binary.BigEndian.PutUint64(h.Bytes()[ll:], uint64(i))
|
||||
h.end(s)
|
||||
}
|
||||
|
||||
func (h *encBuf) writeIntVal(tag Tag, typ Type, val uint32) {
|
||||
s := h.begin(tag, typ)
|
||||
ll := h.Len()
|
||||
_, _ = h.Write(zeros[:4])
|
||||
binary.BigEndian.PutUint32(h.Bytes()[ll:], val)
|
||||
h.end(s)
|
||||
}
|
||||
|
||||
var (
|
||||
ones = [8]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
|
||||
zeros = [8]byte{}
|
||||
)
|
||||
|
||||
func (h *encBuf) encodeBigInt(tag Tag, i *big.Int) {
|
||||
if i == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ii := h.begin(tag, TypeBigInteger)
|
||||
|
||||
switch i.Sign() {
|
||||
case 0:
|
||||
_, _ = h.Write(zeros[:8])
|
||||
case 1:
|
||||
b := i.Bytes()
|
||||
l := len(b)
|
||||
// if n is positive, but the first bit is a 1, it will look like
|
||||
// a negative in 2's complement, so prepend zeroes in front
|
||||
if b[0]&0x80 > 0 {
|
||||
_ = h.WriteByte(byte(0))
|
||||
l++
|
||||
}
|
||||
// pad front with zeros to multiple of 8
|
||||
if m := l % 8; m > 0 {
|
||||
_, _ = h.Write(zeros[:8-m])
|
||||
}
|
||||
|
||||
_, _ = h.Write(b)
|
||||
case -1:
|
||||
length := uint(i.BitLen()/8+1) * 8
|
||||
j := new(big.Int).Lsh(one, length)
|
||||
b := j.Add(i, j).Bytes()
|
||||
// When the most significant bit is on a byte
|
||||
// boundary, we can get some extra significant
|
||||
// bits, so strip them off when that happens.
|
||||
if len(b) >= 2 && b[0] == 0xff && b[1]&0x80 != 0 {
|
||||
b = b[1:]
|
||||
}
|
||||
|
||||
l := len(b)
|
||||
// pad front with ones to multiple of 8
|
||||
if m := l % 8; m > 0 {
|
||||
_, _ = h.Write(ones[:8-m])
|
||||
}
|
||||
|
||||
_, _ = h.Write(b)
|
||||
}
|
||||
|
||||
h.end(ii)
|
||||
}
|
||||
|
||||
func (h *encBuf) encodeInt(tag Tag, i int32) {
|
||||
h.writeIntVal(tag, TypeInteger, uint32(i))
|
||||
}
|
||||
|
||||
func (h *encBuf) encodeBool(tag Tag, b bool) {
|
||||
if b {
|
||||
h.writeLongIntVal(tag, TypeBoolean, 1)
|
||||
} else {
|
||||
h.writeLongIntVal(tag, TypeBoolean, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *encBuf) encodeLongInt(tag Tag, i int64) {
|
||||
h.writeLongIntVal(tag, TypeLongInteger, i)
|
||||
}
|
||||
|
||||
func (h *encBuf) encodeDateTime(tag Tag, t time.Time) {
|
||||
h.writeLongIntVal(tag, TypeDateTime, t.Unix())
|
||||
}
|
||||
|
||||
func (h *encBuf) encodeDateTimeExtended(tag Tag, t time.Time) {
|
||||
// take unix seconds, times a million, to get microseconds, then
|
||||
// add nanoseconds remainder/1000
|
||||
//
|
||||
// this gives us a larger ranger of possible values than just t.UnixNano() / 1000.
|
||||
// see UnixNano() docs for its limits.
|
||||
//
|
||||
// this is limited to max(int64) *microseconds* from epoch, rather than
|
||||
// max(int64) nanoseconds like UnixNano().
|
||||
m := (t.Unix() * 1000000) + int64(t.Nanosecond()/1000)
|
||||
h.writeLongIntVal(tag, TypeDateTimeExtended, m)
|
||||
}
|
||||
|
||||
func (h *encBuf) encodeInterval(tag Tag, d time.Duration) {
|
||||
h.writeIntVal(tag, TypeInterval, uint32(d/time.Second))
|
||||
}
|
||||
|
||||
func (h *encBuf) encodeEnum(tag Tag, i uint32) {
|
||||
h.writeIntVal(tag, TypeEnumeration, i)
|
||||
}
|
||||
|
||||
func (h *encBuf) encodeTextString(tag Tag, s string) {
|
||||
i := h.begin(tag, TypeTextString)
|
||||
_, _ = h.WriteString(s)
|
||||
h.end(i)
|
||||
}
|
||||
|
||||
func (h *encBuf) encodeByteString(tag Tag, b []byte) {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
|
||||
i := h.begin(tag, TypeByteString)
|
||||
_, _ = h.Write(b)
|
||||
h.end(i)
|
||||
}
|
||||
|
||||
func getTypeInfo(typ reflect.Type) (ti typeInfo, err error) {
|
||||
ti.inferredTag, _ = DefaultRegistry.ParseTag(typ.Name())
|
||||
ti.typ = typ
|
||||
err = ti.getFieldsInfo()
|
||||
|
||||
return ti, err
|
||||
}
|
||||
|
||||
var errSkip = errors.New("skip")
|
||||
|
||||
func getFieldInfo(typ reflect.Type, sf reflect.StructField) (fieldInfo, error) {
|
||||
var fi fieldInfo
|
||||
|
||||
// skip anonymous and unexported fields
|
||||
if sf.Anonymous || /*unexported:*/ sf.PkgPath != "" {
|
||||
return fi, errSkip
|
||||
}
|
||||
|
||||
fi.name = sf.Name
|
||||
fi.structType = typ
|
||||
fi.index = sf.Index
|
||||
|
||||
var anyField bool
|
||||
|
||||
// handle field tags
|
||||
parts := strings.Split(sf.Tag.Get(structFieldTag), ",")
|
||||
for i, value := range parts {
|
||||
if i == 0 {
|
||||
switch value {
|
||||
case "-":
|
||||
// skip
|
||||
return fi, errSkip
|
||||
case "":
|
||||
default:
|
||||
var err error
|
||||
|
||||
fi.explicitTag, err = DefaultRegistry.ParseTag(value)
|
||||
if err != nil {
|
||||
return fi, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch strings.ToLower(value) {
|
||||
case "enum":
|
||||
fi.flags |= fEnum
|
||||
case "omitempty":
|
||||
fi.flags |= fOmitEmpty
|
||||
case "datetimeextended":
|
||||
fi.flags |= fDateTimeExtended
|
||||
case "bitmask":
|
||||
fi.flags |= fBitBask
|
||||
case "any":
|
||||
anyField = true
|
||||
fi.flags |= fAny
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if anyField && fi.explicitTag != TagNone {
|
||||
return fi, merry.Here(ErrTagConflict).Appendf(`field %s.%s may not specify a TTLV tag and the "any" flag`, fi.structType.Name(), fi.name)
|
||||
}
|
||||
|
||||
// extract type info for the field. The KMIP tag
|
||||
// for this field is derived from either the field name,
|
||||
// the field tags, or the field type.
|
||||
var err error
|
||||
|
||||
fi.ti, err = getTypeInfo(sf.Type)
|
||||
if err != nil {
|
||||
return fi, err
|
||||
}
|
||||
|
||||
if fi.ti.tagField != nil && fi.ti.tagField.explicitTag != TagNone {
|
||||
fi.tag = fi.ti.tagField.explicitTag
|
||||
if fi.explicitTag != TagNone && fi.explicitTag != fi.tag {
|
||||
// if there was a tag on the struct field containing this value, it must
|
||||
// agree with the value's intrinsic tag
|
||||
return fi, merry.Here(ErrTagConflict).Appendf(`TTLV tag "%s" in tag of %s.%s conflicts with TTLV tag "%s" in %s.%s`, fi.explicitTag, fi.structType.Name(), fi.name, fi.ti.tagField.explicitTag, fi.ti.typ.Name(), fi.ti.tagField.name)
|
||||
}
|
||||
}
|
||||
|
||||
// pre-calculate the tag for this field. This intentional duplicates
|
||||
// some of tagForMarshaling(). The value is primarily used in unmarshaling
|
||||
// where the dynamic value of the field is not needed.
|
||||
if fi.tag == TagNone {
|
||||
fi.tag = fi.explicitTag
|
||||
}
|
||||
|
||||
if fi.tag == TagNone {
|
||||
fi.tag, _ = DefaultRegistry.ParseTag(fi.name)
|
||||
}
|
||||
|
||||
return fi, nil
|
||||
}
|
||||
|
||||
func (ti *typeInfo) getFieldsInfo() error {
|
||||
if ti.typ.Kind() != reflect.Struct {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := 0; i < ti.typ.NumField(); i++ {
|
||||
fi, err := getFieldInfo(ti.typ, ti.typ.Field(i))
|
||||
|
||||
switch {
|
||||
case err == errSkip: //nolint:errorlint
|
||||
// skip
|
||||
case err != nil:
|
||||
return err
|
||||
case fi.name == "TTLVTag":
|
||||
ti.tagField = &fi
|
||||
default:
|
||||
ti.valueFields = append(ti.valueFields, fi)
|
||||
}
|
||||
}
|
||||
|
||||
// verify that multiple fields don't have the same tag
|
||||
names := map[Tag]string{}
|
||||
|
||||
for _, f := range ti.valueFields {
|
||||
if f.flags.any() {
|
||||
// ignore any fields
|
||||
continue
|
||||
}
|
||||
|
||||
tag := f.tag
|
||||
if tag != TagNone {
|
||||
if fname, ok := names[tag]; ok {
|
||||
return merry.Here(ErrTagConflict).Appendf("field resolves to the same tag (%s) as other field (%s)", tag, fname)
|
||||
}
|
||||
|
||||
names[tag] = f.name
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type typeInfo struct {
|
||||
typ reflect.Type
|
||||
inferredTag Tag
|
||||
tagField *fieldInfo
|
||||
valueFields []fieldInfo
|
||||
}
|
||||
|
||||
const (
|
||||
fOmitEmpty fieldFlags = 1 << iota
|
||||
fEnum
|
||||
fDateTimeExtended
|
||||
fAny
|
||||
fBitBask
|
||||
)
|
||||
|
||||
type fieldFlags int
|
||||
|
||||
func (f fieldFlags) omitEmpty() bool {
|
||||
return f&fOmitEmpty != 0
|
||||
}
|
||||
|
||||
func (f fieldFlags) any() bool {
|
||||
return f&fAny != 0
|
||||
}
|
||||
|
||||
func (f fieldFlags) dateTimeExt() bool {
|
||||
return f&fDateTimeExtended != 0
|
||||
}
|
||||
|
||||
func (f fieldFlags) enum() bool {
|
||||
return f&fEnum != 0
|
||||
}
|
||||
|
||||
func (f fieldFlags) bitmask() bool {
|
||||
return f&fBitBask != 0
|
||||
}
|
||||
|
||||
type fieldInfo struct {
|
||||
structType reflect.Type
|
||||
explicitTag, tag Tag
|
||||
name string
|
||||
index []int
|
||||
flags fieldFlags
|
||||
ti typeInfo
|
||||
}
|
8
vendor/github.com/gemalto/kmip-go/ttlv/errors.go
generated
vendored
Normal file
8
vendor/github.com/gemalto/kmip-go/ttlv/errors.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
package ttlv
|
||||
|
||||
import "github.com/ansel1/merry"
|
||||
|
||||
// Details prints details from the error, including a stacktrace when available.
|
||||
func Details(err error) string {
|
||||
return merry.Details(err)
|
||||
}
|
314
vendor/github.com/gemalto/kmip-go/ttlv/formatting.go
generated
vendored
Normal file
314
vendor/github.com/gemalto/kmip-go/ttlv/formatting.go
generated
vendored
Normal file
@ -0,0 +1,314 @@
|
||||
package ttlv
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ansel1/merry"
|
||||
"github.com/gemalto/kmip-go/internal/kmiputil"
|
||||
)
|
||||
|
||||
// FormatType formats a byte as a KMIP Type string,
|
||||
// as described in the KMIP Profiles spec. If the value is registered,
|
||||
// the normalized name of the value will be returned.
|
||||
//
|
||||
// Otherwise, a 1 byte hex string is returned, but this is not
|
||||
// technically a valid encoding for types in the JSON and XML encoding
|
||||
// specs. Hex values Should only be used for debugging. Examples:
|
||||
//
|
||||
// - Integer
|
||||
// - 0x42
|
||||
func FormatType(b byte, enumMap EnumMap) string {
|
||||
if enumMap != nil {
|
||||
if s, ok := enumMap.Name(uint32(b)); ok {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%#02x", b)
|
||||
}
|
||||
|
||||
// FormatTag formats an uint32 as a KMIP Tag string,
|
||||
// as described in the KMIP Profiles spec. If the value is registered,
|
||||
// the normalized name of the value will be returned. Otherwise, a
|
||||
// 3 byte hex string is returned. Examples:
|
||||
//
|
||||
// - ActivationDate
|
||||
// - 0x420001
|
||||
func FormatTag(v uint32, enumMap EnumMap) string {
|
||||
if enumMap != nil {
|
||||
if s, ok := enumMap.Name(v); ok {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%#06x", v)
|
||||
}
|
||||
|
||||
// FormatTagCanonical formats an uint32 as a canonical Tag name
|
||||
// from the KMIP spec. If the value is registered,
|
||||
// the canonical name of the value will be returned. Otherwise, a
|
||||
// 3 byte hex string is returned. Examples:
|
||||
//
|
||||
// - Activation Date
|
||||
// - 0x420001
|
||||
//
|
||||
// Canonical tag names are used in the AttributeName of Attribute structs.
|
||||
func FormatTagCanonical(v uint32, enumMap EnumMap) string {
|
||||
if enumMap != nil {
|
||||
if s, ok := enumMap.CanonicalName(v); ok {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%#06x", v)
|
||||
}
|
||||
|
||||
// FormatEnum formats an uint32 as a KMIP Enumeration string,
|
||||
// as described in the KMIP Profiles spec. If the value is registered,
|
||||
// the normalized name of the value will be returned. Otherwise, a
|
||||
// four byte hex string is returned. Examples:
|
||||
//
|
||||
// - SymmetricKey
|
||||
// - 0x00000002
|
||||
func FormatEnum(v uint32, enumMap EnumMap) string {
|
||||
if enumMap != nil {
|
||||
if s, ok := enumMap.Name(v); ok {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%#08x", v)
|
||||
}
|
||||
|
||||
// FormatInt formats an integer as a KMIP bitmask string, as
|
||||
// described in the KMIP Profiles spec for JSON under
|
||||
// the "Special case for Masks" section. Examples:
|
||||
//
|
||||
// - 0x0000100c
|
||||
// - Encrypt|Decrypt|CertificateSign
|
||||
// - CertificateSign|0x00000004|0x0000008
|
||||
// - CertificateSign|0x0000000c
|
||||
func FormatInt(i int32, enumMap EnumMap) string {
|
||||
if enumMap == nil {
|
||||
return fmt.Sprintf("%#08x", i)
|
||||
}
|
||||
|
||||
values := enumMap.Values()
|
||||
if len(values) == 0 {
|
||||
return fmt.Sprintf("%#08x", i)
|
||||
}
|
||||
|
||||
v := uint32(i)
|
||||
|
||||
// bitmask
|
||||
// decompose mask into the names of set flags, concatenated by pipe
|
||||
// if remaining value (minus registered flags) is not zero, append
|
||||
// the remaining value as hex.
|
||||
|
||||
var sb strings.Builder
|
||||
|
||||
for _, v1 := range values {
|
||||
if v1&v == v1 {
|
||||
if name, ok := enumMap.Name(v1); ok {
|
||||
if sb.Len() > 0 {
|
||||
sb.WriteString("|")
|
||||
}
|
||||
|
||||
sb.WriteString(name)
|
||||
|
||||
v ^= v1
|
||||
}
|
||||
}
|
||||
|
||||
if v == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if v != 0 {
|
||||
if sb.Len() > 0 {
|
||||
sb.WriteString("|")
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(&sb, "%#08x", v)
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// ParseEnum parses a string into a uint32 according to the rules
|
||||
// in the KMIP Profiles regarding encoding enumeration values.
|
||||
// See FormatEnum for examples of the formats which can be parsed.
|
||||
// It will also parse numeric strings. Examples:
|
||||
//
|
||||
// ParseEnum("UnableToCancel", registry.EnumForTag(TagCancellationResult))
|
||||
// ParseEnum("0x00000002")
|
||||
// ParseEnum("2")
|
||||
//
|
||||
// Returns ErrInvalidHexString if the string is invalid hex, or
|
||||
// if the hex value is less than 1 byte or more than 4 bytes (ignoring
|
||||
// leading zeroes).
|
||||
//
|
||||
// Returns ErrUnregisteredEnumName if string value is not a
|
||||
// registered enum value name.
|
||||
func ParseEnum(s string, enumMap EnumMap) (uint32, error) {
|
||||
u, err := strconv.ParseUint(s, 10, 32)
|
||||
if err == nil {
|
||||
// it was a raw number
|
||||
return uint32(u), nil
|
||||
}
|
||||
|
||||
v, err := parseHexOrName(s, 4, enumMap)
|
||||
if err != nil {
|
||||
return 0, merry.Here(err)
|
||||
}
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// ParseInt parses a string into an int32 according the rules
|
||||
// in the KMIP Profiles regarding encoding integers, including
|
||||
// the special rules for bitmasks. See FormatInt for examples
|
||||
// of the formats which can be parsed.
|
||||
//
|
||||
// Returns ErrInvalidHexString if the string is invalid hex, or
|
||||
// if the hex value is less than 1 byte or more than 4 bytes (ignoring
|
||||
// leading zeroes).
|
||||
//
|
||||
// Returns ErrUnregisteredEnumName if string value is not a
|
||||
// registered enum value name.
|
||||
func ParseInt(s string, enumMap EnumMap) (int32, error) {
|
||||
i, err := strconv.ParseInt(s, 10, 32)
|
||||
if err == nil {
|
||||
// it was a raw number
|
||||
return int32(i), nil
|
||||
}
|
||||
|
||||
if !strings.ContainsAny(s, "| ") {
|
||||
v, err := parseHexOrName(s, 4, enumMap)
|
||||
if err != nil {
|
||||
return 0, merry.Here(err)
|
||||
}
|
||||
|
||||
return int32(v), nil
|
||||
}
|
||||
|
||||
// split values, look up each, and recombine
|
||||
s = strings.ReplaceAll(s, "|", " ")
|
||||
parts := strings.Split(s, " ")
|
||||
var v uint32
|
||||
|
||||
for _, part := range parts {
|
||||
if len(part) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
i, err := parseHexOrName(part, 4, enumMap)
|
||||
if err != nil {
|
||||
return 0, merry.Here(err)
|
||||
}
|
||||
|
||||
v |= i
|
||||
}
|
||||
|
||||
return int32(v), nil
|
||||
}
|
||||
|
||||
func parseHexOrName(s string, max int, enumMap EnumMap) (uint32, error) {
|
||||
b, err := kmiputil.ParseHexValue(s, max)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if b != nil {
|
||||
return kmiputil.DecodeUint32(b), nil
|
||||
}
|
||||
|
||||
if enumMap != nil {
|
||||
if v, ok := enumMap.Value(s); ok {
|
||||
return v, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, merry.Append(ErrUnregisteredEnumName, s)
|
||||
}
|
||||
|
||||
// ParseTag parses a string into Tag according the rules
|
||||
// in the KMIP Profiles regarding encoding tag values.
|
||||
// See FormatTag for examples of the formats which can be parsed.
|
||||
//
|
||||
// Returns ErrInvalidHexString if the string is invalid hex, or
|
||||
// if the hex value is less than 1 byte or more than 3 bytes (ignoring
|
||||
// leading zeroes).
|
||||
//
|
||||
// Returns ErrUnregisteredEnumName if string value is not a
|
||||
// registered enum value name.
|
||||
func ParseTag(s string, enumMap EnumMap) (Tag, error) {
|
||||
v, err := parseHexOrName(s, 3, enumMap)
|
||||
if err != nil {
|
||||
return 0, merry.Here(err)
|
||||
}
|
||||
|
||||
return Tag(v), nil
|
||||
}
|
||||
|
||||
// ParseType parses a string into Type according the rules
|
||||
// in the KMIP Profiles regarding encoding type values.
|
||||
// See FormatType for examples of the formats which can be parsed.
|
||||
// This also supports parsing a hex string type (e.g. "0x01"), though
|
||||
// this is not technically a valid encoding of a type in the spec.
|
||||
//
|
||||
// Returns ErrInvalidHexString if the string is invalid hex, or
|
||||
// if the hex value is less than 1 byte or more than 3 bytes (ignoring
|
||||
// leading zeroes).
|
||||
//
|
||||
// Returns ErrUnregisteredEnumName if string value is not a
|
||||
// registered enum value name.
|
||||
func ParseType(s string, enumMap EnumMap) (Type, error) {
|
||||
b, err := kmiputil.ParseHexValue(s, 1)
|
||||
if err != nil {
|
||||
return 0, merry.Here(err)
|
||||
}
|
||||
|
||||
if b != nil {
|
||||
return Type(b[0]), nil
|
||||
}
|
||||
|
||||
if enumMap != nil {
|
||||
if v, ok := enumMap.Value(s); ok {
|
||||
return Type(v), nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, merry.Here(ErrUnregisteredEnumName).Append(s)
|
||||
}
|
||||
|
||||
// EnumMap defines a set of named enumeration values. Canonical names should
|
||||
// be the name from the spec. Names should be in the normalized format
|
||||
// described in the KMIP spec (see NormalizeName()).
|
||||
//
|
||||
//
|
||||
// Value enumerations are used for encoding and decoding KMIP Enumeration values,
|
||||
// KMIP Integer bitmask values, Types, and Tags.
|
||||
type EnumMap interface {
|
||||
// Name returns the normalized name for a value, e.g. AttributeName.
|
||||
// If the name is not registered, it returns "", false.
|
||||
Name(v uint32) (string, bool)
|
||||
// CanonicalName returns the canonical name for the value from the spec,
|
||||
// e.g. Attribute Name.
|
||||
// If the name is not registered, it returns "", false
|
||||
CanonicalName(v uint32) (string, bool)
|
||||
// Value returns the value registered for the name argument. If there is
|
||||
// no name registered for this value, it returns 0, false.
|
||||
// The name argument may be the canonical name (e.g. "Cryptographic Algorithm") or
|
||||
// the normalized name (e.g. "CryptographicAlgorithm").
|
||||
Value(name string) (uint32, bool)
|
||||
// Values returns the complete set of registered values. The order
|
||||
// they are returned in will be the order they are encoded in when
|
||||
// encoding bitmasks as strings.
|
||||
Values() []uint32
|
||||
// Bitmask returns true if this is an enumeration of bitmask flags.
|
||||
Bitmask() bool
|
||||
}
|
248
vendor/github.com/gemalto/kmip-go/ttlv/registry.go
generated
vendored
Normal file
248
vendor/github.com/gemalto/kmip-go/ttlv/registry.go
generated
vendored
Normal file
@ -0,0 +1,248 @@
|
||||
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] }
|
50
vendor/github.com/gemalto/kmip-go/ttlv/tag.go
generated
vendored
Normal file
50
vendor/github.com/gemalto/kmip-go/ttlv/tag.go
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
package ttlv
|
||||
|
||||
const (
|
||||
TagNone = Tag(0)
|
||||
tagAttributeName Tag = 0x42000a
|
||||
tagAttributeValue Tag = 0x42000b
|
||||
)
|
||||
|
||||
// Tag
|
||||
// 9.1.3.1
|
||||
type Tag uint32
|
||||
|
||||
// String returns the normalized name of the tag.
|
||||
func (t Tag) String() string {
|
||||
return DefaultRegistry.FormatTag(t)
|
||||
}
|
||||
|
||||
// CanonicalName returns the canonical name of the tag.
|
||||
func (t Tag) CanonicalName() string {
|
||||
return DefaultRegistry.FormatTagCanonical(t)
|
||||
}
|
||||
|
||||
func (t Tag) MarshalText() (text []byte, err error) {
|
||||
return []byte(t.String()), nil
|
||||
}
|
||||
|
||||
func (t *Tag) UnmarshalText(text []byte) (err error) {
|
||||
*t, err = DefaultRegistry.ParseTag(string(text))
|
||||
return
|
||||
}
|
||||
|
||||
const (
|
||||
minStandardTag uint32 = 0x00420000
|
||||
maxStandardTag uint32 = 0x00430000
|
||||
minCustomTag uint32 = 0x00540000
|
||||
maxCustomTag uint32 = 0x00550000
|
||||
)
|
||||
|
||||
// Valid checks whether the tag's numeric value is valid according to
|
||||
// the ranges in the spec.
|
||||
func (t Tag) Valid() bool {
|
||||
switch {
|
||||
case uint32(t) >= minStandardTag && uint32(t) < maxStandardTag:
|
||||
return true
|
||||
case uint32(t) >= minCustomTag && uint32(t) < maxCustomTag:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
1252
vendor/github.com/gemalto/kmip-go/ttlv/ttlv.go
generated
vendored
Normal file
1252
vendor/github.com/gemalto/kmip-go/ttlv/ttlv.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
196
vendor/github.com/gemalto/kmip-go/ttlv/types.go
generated
vendored
Normal file
196
vendor/github.com/gemalto/kmip-go/ttlv/types.go
generated
vendored
Normal file
@ -0,0 +1,196 @@
|
||||
package ttlv
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
func RegisterTypes(r *Registry) {
|
||||
m := map[string]Type{
|
||||
"BigInteger": TypeBigInteger,
|
||||
"Boolean": TypeBoolean,
|
||||
"ByteString": TypeByteString,
|
||||
"DateTime": TypeDateTime,
|
||||
"Enumeration": TypeEnumeration,
|
||||
"Integer": TypeInteger,
|
||||
"Interval": TypeInterval,
|
||||
"LongInteger": TypeLongInteger,
|
||||
"Structure": TypeStructure,
|
||||
"TextString": TypeTextString,
|
||||
"DateTimeExtended": TypeDateTimeExtended,
|
||||
}
|
||||
|
||||
for name, v := range m {
|
||||
r.RegisterType(v, name)
|
||||
}
|
||||
}
|
||||
|
||||
// Type describes the type of a KMIP TTLV.
|
||||
// 2 and 9.1.1.2
|
||||
type Type byte
|
||||
|
||||
const (
|
||||
TypeStructure Type = 0x01
|
||||
TypeInteger Type = 0x02
|
||||
TypeLongInteger Type = 0x03
|
||||
TypeBigInteger Type = 0x04
|
||||
TypeEnumeration Type = 0x05
|
||||
TypeBoolean Type = 0x06
|
||||
TypeTextString Type = 0x07
|
||||
TypeByteString Type = 0x08
|
||||
TypeDateTime Type = 0x09
|
||||
TypeInterval Type = 0x0A
|
||||
TypeDateTimeExtended Type = 0x0B
|
||||
)
|
||||
|
||||
// String returns the normalized name of the type. If the type
|
||||
// name isn't registered, it returns the hex value of the type,
|
||||
// e.g. "0x01" (TypeStructure). The value of String() is suitable
|
||||
// for use in the JSON or XML encoding of TTLV.
|
||||
func (t Type) String() string {
|
||||
return DefaultRegistry.FormatType(t)
|
||||
}
|
||||
|
||||
func (t Type) MarshalText() (text []byte, err error) {
|
||||
return []byte(t.String()), nil
|
||||
}
|
||||
|
||||
func (t *Type) UnmarshalText(text []byte) (err error) {
|
||||
*t, err = DefaultRegistry.ParseType(string(text))
|
||||
return
|
||||
}
|
||||
|
||||
// DateTimeExtended is a time wrapper which always marshals to a DateTimeExtended.
|
||||
type DateTimeExtended struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
func (t *DateTimeExtended) UnmarshalTTLV(d *Decoder, ttlv TTLV) error {
|
||||
if len(ttlv) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if t == nil {
|
||||
*t = DateTimeExtended{}
|
||||
}
|
||||
|
||||
err := d.DecodeValue(&t.Time, ttlv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t DateTimeExtended) MarshalTTLV(e *Encoder, tag Tag) error {
|
||||
e.EncodeDateTimeExtended(tag, t.Time)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value is a go-typed mapping for a TTLV value. It holds a tag, and the value in
|
||||
// the form of a native go type.
|
||||
//
|
||||
// Value supports marshaling and unmarshaling, allowing a mapping between encoded TTLV
|
||||
// bytes and native go types. It's useful in tests, or where you want to construct
|
||||
// an arbitrary TTLV structure in code without declaring a bespoke type, e.g.:
|
||||
//
|
||||
// v := ttlv.Value{Tag: TagBatchCount, Value: Values{
|
||||
// Value{Tag: TagComment, Value: "red"},
|
||||
// Value{Tag: TagComment, Value: "blue"},
|
||||
// Value{Tag: TagComment, Value: "green"},
|
||||
// }
|
||||
// t, err := ttlv.Marshal(v)
|
||||
//
|
||||
// KMIP Structure types are mapped to the Values go type. When marshaling, if the Value
|
||||
// field is set to a Values{}, the resulting TTLV will be TypeStructure. When unmarshaling
|
||||
// a TTLV with TypeStructure, the Value field will be set to a Values{}.
|
||||
type Value struct {
|
||||
Tag Tag
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
// UnmarshalTTLV implements Unmarshaler
|
||||
func (t *Value) UnmarshalTTLV(d *Decoder, ttlv TTLV) error {
|
||||
t.Tag = ttlv.Tag()
|
||||
|
||||
switch ttlv.Type() {
|
||||
case TypeStructure:
|
||||
var v Values
|
||||
|
||||
ttlv = ttlv.ValueStructure()
|
||||
for ttlv.Valid() == nil {
|
||||
err := d.DecodeValue(&v, ttlv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ttlv = ttlv.Next()
|
||||
}
|
||||
|
||||
t.Value = v
|
||||
default:
|
||||
t.Value = ttlv.Value()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalTTLV implements Marshaler
|
||||
func (t Value) MarshalTTLV(e *Encoder, tag Tag) error {
|
||||
// if tag is set, override the suggested tag
|
||||
if t.Tag != TagNone {
|
||||
tag = t.Tag
|
||||
}
|
||||
|
||||
if tvs, ok := t.Value.(Values); ok {
|
||||
return e.EncodeStructure(tag, func(e *Encoder) error {
|
||||
for _, v := range tvs {
|
||||
if err := e.Encode(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
return e.EncodeValue(tag, t.Value)
|
||||
}
|
||||
|
||||
// Values is a slice of Value objects. It represents the body of a TTLV with a type of Structure.
|
||||
type Values []Value
|
||||
|
||||
// NewValue creates a new tagged value.
|
||||
func NewValue(tag Tag, val interface{}) Value {
|
||||
return Value{
|
||||
Tag: tag,
|
||||
Value: val,
|
||||
}
|
||||
}
|
||||
|
||||
// NewStruct creates a new tagged value which is of type struct.
|
||||
func NewStruct(tag Tag, vals ...Value) Value {
|
||||
return Value{
|
||||
Tag: tag,
|
||||
Value: Values(vals),
|
||||
}
|
||||
}
|
||||
|
||||
type Encoder struct {
|
||||
encodeDepth int
|
||||
w io.Writer
|
||||
encBuf encBuf
|
||||
|
||||
// these fields store where the encoder is when marshaling a nested struct. its
|
||||
// used to construct error messages.
|
||||
currStruct string
|
||||
currField string
|
||||
}
|
||||
|
||||
// EnumValue is a uint32 wrapper which always encodes as an enumeration.
|
||||
type EnumValue uint32
|
||||
|
||||
func (v EnumValue) MarshalTTLV(e *Encoder, tag Tag) error {
|
||||
e.EncodeEnumeration(tag, uint32(v))
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user