vendor
This commit is contained in:
parent
07ec5529ac
commit
f501abe660
532 changed files with 271781 additions and 0 deletions
896
vendor/github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2/decode.go
generated
vendored
Normal file
896
vendor/github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2/decode.go
generated
vendored
Normal file
|
|
@ -0,0 +1,896 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2014 Dave Collins <dave@davec.name>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
package xdr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
errMaxSlice = "data exceeds max slice limit"
|
||||
errIODecode = "%s while decoding %d bytes"
|
||||
)
|
||||
|
||||
/*
|
||||
Unmarshal parses XDR-encoded data into the value pointed to by v reading from
|
||||
reader r and returning the total number of bytes read. An addressable pointer
|
||||
must be provided since Unmarshal needs to both store the result of the decode as
|
||||
well as obtain target type information. Unmarhsal traverses v recursively and
|
||||
automatically indirects pointers through arbitrary depth, allocating them as
|
||||
necessary, to decode the data into the underlying value pointed to.
|
||||
|
||||
Unmarshal uses reflection to determine the type of the concrete value contained
|
||||
by v and performs a mapping of underlying XDR types to Go types as follows:
|
||||
|
||||
Go Type <- XDR Type
|
||||
--------------------
|
||||
int8, int16, int32, int <- XDR Integer
|
||||
uint8, uint16, uint32, uint <- XDR Unsigned Integer
|
||||
int64 <- XDR Hyper Integer
|
||||
uint64 <- XDR Unsigned Hyper Integer
|
||||
bool <- XDR Boolean
|
||||
float32 <- XDR Floating-Point
|
||||
float64 <- XDR Double-Precision Floating-Point
|
||||
string <- XDR String
|
||||
byte <- XDR Integer
|
||||
[]byte <- XDR Variable-Length Opaque Data
|
||||
[#]byte <- XDR Fixed-Length Opaque Data
|
||||
[]<type> <- XDR Variable-Length Array
|
||||
[#]<type> <- XDR Fixed-Length Array
|
||||
struct <- XDR Structure
|
||||
map <- XDR Variable-Length Array of two-element XDR Structures
|
||||
time.Time <- XDR String encoded with RFC3339 nanosecond precision
|
||||
|
||||
Notes and Limitations:
|
||||
|
||||
* Automatic unmarshalling of variable and fixed-length arrays of uint8s
|
||||
requires a special struct tag `xdropaque:"false"` since byte slices
|
||||
and byte arrays are assumed to be opaque data and byte is a Go alias
|
||||
for uint8 thus indistinguishable under reflection
|
||||
* Cyclic data structures are not supported and will result in infinite
|
||||
loops
|
||||
|
||||
If any issues are encountered during the unmarshalling process, an
|
||||
UnmarshalError is returned with a human readable description as well as
|
||||
an ErrorCode value for further inspection from sophisticated callers. Some
|
||||
potential issues are unsupported Go types, attempting to decode a value which is
|
||||
too large to fit into a specified Go type, and exceeding max slice limitations.
|
||||
*/
|
||||
func Unmarshal(r io.Reader, v interface{}) (int, error) {
|
||||
d := Decoder{r: r}
|
||||
return d.Decode(v)
|
||||
}
|
||||
|
||||
// UnmarshalLimited is identical to Unmarshal but it sets maxReadSize in order
|
||||
// to cap reads.
|
||||
func UnmarshalLimited(r io.Reader, v interface{}, maxSize uint) (int, error) {
|
||||
d := Decoder{r: r, maxReadSize: maxSize}
|
||||
return d.Decode(v)
|
||||
}
|
||||
|
||||
// TypeDecoder lets a caller provide a custom decode routine for a custom type.
|
||||
type TypeDecoder interface {
|
||||
Decode(*Decoder, reflect.Value) (int, error)
|
||||
}
|
||||
|
||||
// A Decoder wraps an io.Reader that is expected to provide an XDR-encoded byte
|
||||
// stream and provides several exposed methods to manually decode various XDR
|
||||
// primitives without relying on reflection. The NewDecoder function can be
|
||||
// used to get a new Decoder directly.
|
||||
//
|
||||
// Typically, Unmarshal should be used instead of manual decoding. A Decoder
|
||||
// is exposed so it is possible to perform manual decoding should it be
|
||||
// necessary in complex scenarios where automatic reflection-based decoding
|
||||
// won't work.
|
||||
type Decoder struct {
|
||||
r io.Reader
|
||||
|
||||
// maxReadSize is the default maximum bytes an element can contain. 0
|
||||
// is unlimited and provides backwards compatability. Setting it to a
|
||||
// non-zero value caps reads.
|
||||
maxReadSize uint
|
||||
|
||||
// customTypes is a map allowing the caller to provide decoder routines for
|
||||
// custom types known only to itself.
|
||||
customTypes map[string]TypeDecoder
|
||||
}
|
||||
|
||||
// DecodeInt treats the next 4 bytes as an XDR encoded integer and returns the
|
||||
// result as an int32 along with the number of bytes actually read.
|
||||
//
|
||||
// An UnmarshalError is returned if there are insufficient bytes remaining.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.1 - Integer
|
||||
// 32-bit big-endian signed integer in range [-2147483648, 2147483647]
|
||||
func (d *Decoder) DecodeInt() (int32, int, error) {
|
||||
var buf [4]byte
|
||||
n, err := io.ReadFull(d.r, buf[:])
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf(errIODecode, err.Error(), 4)
|
||||
err := unmarshalError("DecodeInt", ErrIO, msg, buf[:n], err)
|
||||
return 0, n, err
|
||||
}
|
||||
|
||||
rv := int32(buf[3]) | int32(buf[2])<<8 |
|
||||
int32(buf[1])<<16 | int32(buf[0])<<24
|
||||
return rv, n, nil
|
||||
}
|
||||
|
||||
// DecodeUint treats the next 4 bytes as an XDR encoded unsigned integer and
|
||||
// returns the result as a uint32 along with the number of bytes actually read.
|
||||
//
|
||||
// An UnmarshalError is returned if there are insufficient bytes remaining.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.2 - Unsigned Integer
|
||||
// 32-bit big-endian unsigned integer in range [0, 4294967295]
|
||||
func (d *Decoder) DecodeUint() (uint32, int, error) {
|
||||
var buf [4]byte
|
||||
n, err := io.ReadFull(d.r, buf[:])
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf(errIODecode, err.Error(), 4)
|
||||
err := unmarshalError("DecodeUint", ErrIO, msg, buf[:n], err)
|
||||
return 0, n, err
|
||||
}
|
||||
|
||||
rv := uint32(buf[3]) | uint32(buf[2])<<8 |
|
||||
uint32(buf[1])<<16 | uint32(buf[0])<<24
|
||||
return rv, n, nil
|
||||
}
|
||||
|
||||
// DecodeEnum treats the next 4 bytes as an XDR encoded enumeration value and
|
||||
// returns the result as an int32 after verifying that the value is in the
|
||||
// provided map of valid values. It also returns the number of bytes actually
|
||||
// read.
|
||||
//
|
||||
// An UnmarshalError is returned if there are insufficient bytes remaining or
|
||||
// the parsed enumeration value is not one of the provided valid values.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.3 - Enumeration
|
||||
// Represented as an XDR encoded signed integer
|
||||
func (d *Decoder) DecodeEnum(validEnums map[int32]bool) (int32, int, error) {
|
||||
val, n, err := d.DecodeInt()
|
||||
if err != nil {
|
||||
return 0, n, err
|
||||
}
|
||||
|
||||
if !validEnums[val] {
|
||||
err := unmarshalError("DecodeEnum", ErrBadEnumValue,
|
||||
"invalid enum", val, nil)
|
||||
return 0, n, err
|
||||
}
|
||||
return val, n, nil
|
||||
}
|
||||
|
||||
// DecodeBool treats the next 4 bytes as an XDR encoded boolean value and
|
||||
// returns the result as a bool along with the number of bytes actually read.
|
||||
//
|
||||
// An UnmarshalError is returned if there are insufficient bytes remaining or
|
||||
// the parsed value is not a 0 or 1.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.4 - Boolean
|
||||
// Represented as an XDR encoded enumeration where 0 is false and 1 is true
|
||||
func (d *Decoder) DecodeBool() (bool, int, error) {
|
||||
val, n, err := d.DecodeInt()
|
||||
if err != nil {
|
||||
return false, n, err
|
||||
}
|
||||
switch val {
|
||||
case 0:
|
||||
return false, n, nil
|
||||
case 1:
|
||||
return true, n, nil
|
||||
}
|
||||
|
||||
err = unmarshalError("DecodeBool", ErrBadEnumValue, "bool not 0 or 1",
|
||||
val, nil)
|
||||
return false, n, err
|
||||
}
|
||||
|
||||
// DecodeHyper treats the next 8 bytes as an XDR encoded hyper value and
|
||||
// returns the result as an int64 along with the number of bytes actually read.
|
||||
//
|
||||
// An UnmarshalError is returned if there are insufficient bytes remaining.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.5 - Hyper Integer
|
||||
// 64-bit big-endian signed integer in range [-9223372036854775808, 9223372036854775807]
|
||||
func (d *Decoder) DecodeHyper() (int64, int, error) {
|
||||
var buf [8]byte
|
||||
n, err := io.ReadFull(d.r, buf[:])
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf(errIODecode, err.Error(), 8)
|
||||
err := unmarshalError("DecodeHyper", ErrIO, msg, buf[:n], err)
|
||||
return 0, n, err
|
||||
}
|
||||
|
||||
rv := int64(buf[7]) | int64(buf[6])<<8 |
|
||||
int64(buf[5])<<16 | int64(buf[4])<<24 |
|
||||
int64(buf[3])<<32 | int64(buf[2])<<40 |
|
||||
int64(buf[1])<<48 | int64(buf[0])<<56
|
||||
return rv, n, err
|
||||
}
|
||||
|
||||
// DecodeUhyper treats the next 8 bytes as an XDR encoded unsigned hyper value
|
||||
// and returns the result as a uint64 along with the number of bytes actually
|
||||
// read.
|
||||
//
|
||||
// An UnmarshalError is returned if there are insufficient bytes remaining.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.5 - Unsigned Hyper Integer
|
||||
// 64-bit big-endian unsigned integer in range [0, 18446744073709551615]
|
||||
func (d *Decoder) DecodeUhyper() (uint64, int, error) {
|
||||
var buf [8]byte
|
||||
n, err := io.ReadFull(d.r, buf[:])
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf(errIODecode, err.Error(), 8)
|
||||
err := unmarshalError("DecodeUhyper", ErrIO, msg, buf[:n], err)
|
||||
return 0, n, err
|
||||
}
|
||||
|
||||
rv := uint64(buf[7]) | uint64(buf[6])<<8 |
|
||||
uint64(buf[5])<<16 | uint64(buf[4])<<24 |
|
||||
uint64(buf[3])<<32 | uint64(buf[2])<<40 |
|
||||
uint64(buf[1])<<48 | uint64(buf[0])<<56
|
||||
return rv, n, nil
|
||||
}
|
||||
|
||||
// DecodeFloat treats the next 4 bytes as an XDR encoded floating point and
|
||||
// returns the result as a float32 along with the number of bytes actually read.
|
||||
//
|
||||
// An UnmarshalError is returned if there are insufficient bytes remaining.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.6 - Floating Point
|
||||
// 32-bit single-precision IEEE 754 floating point
|
||||
func (d *Decoder) DecodeFloat() (float32, int, error) {
|
||||
var buf [4]byte
|
||||
n, err := io.ReadFull(d.r, buf[:])
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf(errIODecode, err.Error(), 4)
|
||||
err := unmarshalError("DecodeFloat", ErrIO, msg, buf[:n], err)
|
||||
return 0, n, err
|
||||
}
|
||||
|
||||
val := uint32(buf[3]) | uint32(buf[2])<<8 |
|
||||
uint32(buf[1])<<16 | uint32(buf[0])<<24
|
||||
return math.Float32frombits(val), n, nil
|
||||
}
|
||||
|
||||
// DecodeDouble treats the next 8 bytes as an XDR encoded double-precision
|
||||
// floating point and returns the result as a float64 along with the number of
|
||||
// bytes actually read.
|
||||
//
|
||||
// An UnmarshalError is returned if there are insufficient bytes remaining.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.7 - Double-Precision Floating Point
|
||||
// 64-bit double-precision IEEE 754 floating point
|
||||
func (d *Decoder) DecodeDouble() (float64, int, error) {
|
||||
var buf [8]byte
|
||||
n, err := io.ReadFull(d.r, buf[:])
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf(errIODecode, err.Error(), 8)
|
||||
err := unmarshalError("DecodeDouble", ErrIO, msg, buf[:n], err)
|
||||
return 0, n, err
|
||||
}
|
||||
|
||||
val := uint64(buf[7]) | uint64(buf[6])<<8 |
|
||||
uint64(buf[5])<<16 | uint64(buf[4])<<24 |
|
||||
uint64(buf[3])<<32 | uint64(buf[2])<<40 |
|
||||
uint64(buf[1])<<48 | uint64(buf[0])<<56
|
||||
return math.Float64frombits(val), n, nil
|
||||
}
|
||||
|
||||
// RFC Section 4.8 - Quadruple-Precision Floating Point
|
||||
// 128-bit quadruple-precision floating point
|
||||
// Not Implemented
|
||||
|
||||
// DecodeFixedOpaque treats the next 'size' bytes as XDR encoded opaque data and
|
||||
// returns the result as a byte slice along with the number of bytes actually
|
||||
// read.
|
||||
//
|
||||
// An UnmarshalError is returned if there are insufficient bytes remaining to
|
||||
// satisfy the passed size, including the necessary padding to make it a
|
||||
// multiple of 4.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.9 - Fixed-Length Opaque Data
|
||||
// Fixed-length uninterpreted data zero-padded to a multiple of four
|
||||
func (d *Decoder) DecodeFixedOpaque(size int32) ([]byte, int, error) {
|
||||
// Nothing to do if size is 0.
|
||||
if size == 0 {
|
||||
return nil, 0, nil
|
||||
}
|
||||
|
||||
pad := (4 - (size % 4)) % 4
|
||||
paddedSize := size + pad
|
||||
if uint(paddedSize) > uint(math.MaxInt32) {
|
||||
err := unmarshalError("DecodeFixedOpaque", ErrOverflow,
|
||||
errMaxSlice, paddedSize, nil)
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
buf := make([]byte, paddedSize)
|
||||
n, err := io.ReadFull(d.r, buf)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf(errIODecode, err.Error(), paddedSize)
|
||||
err := unmarshalError("DecodeFixedOpaque", ErrIO, msg, buf[:n],
|
||||
err)
|
||||
return nil, n, err
|
||||
}
|
||||
return buf[0:size], n, nil
|
||||
}
|
||||
|
||||
// DecodeOpaque treats the next bytes as variable length XDR encoded opaque
|
||||
// data and returns the result as a byte slice along with the number of bytes
|
||||
// actually read.
|
||||
//
|
||||
// An UnmarshalError is returned if there are insufficient bytes remaining or
|
||||
// the opaque data is larger than the max length of a Go slice.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.10 - Variable-Length Opaque Data
|
||||
// Unsigned integer length followed by fixed opaque data of that length
|
||||
func (d *Decoder) DecodeOpaque() ([]byte, int, error) {
|
||||
dataLen, n, err := d.DecodeUint()
|
||||
if err != nil {
|
||||
return nil, n, err
|
||||
}
|
||||
if uint(dataLen) > uint(math.MaxInt32) ||
|
||||
(d.maxReadSize != 0 && uint(dataLen) > d.maxReadSize) {
|
||||
err := unmarshalError("DecodeOpaque", ErrOverflow, errMaxSlice,
|
||||
dataLen, nil)
|
||||
return nil, n, err
|
||||
}
|
||||
|
||||
rv, n2, err := d.DecodeFixedOpaque(int32(dataLen))
|
||||
n += n2
|
||||
if err != nil {
|
||||
return nil, n, err
|
||||
}
|
||||
return rv, n, nil
|
||||
}
|
||||
|
||||
// DecodeString treats the next bytes as a variable length XDR encoded string
|
||||
// and returns the result as a string along with the number of bytes actually
|
||||
// read. Character encoding is assumed to be UTF-8 and therefore ASCII
|
||||
// compatible. If the underlying character encoding is not compatibile with
|
||||
// this assumption, the data can instead be read as variable-length opaque data
|
||||
// (DecodeOpaque) and manually converted as needed.
|
||||
//
|
||||
// An UnmarshalError is returned if there are insufficient bytes remaining or
|
||||
// the string data is larger than the max length of a Go slice.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.11 - String
|
||||
// Unsigned integer length followed by bytes zero-padded to a multiple of
|
||||
// four
|
||||
func (d *Decoder) DecodeString() (string, int, error) {
|
||||
dataLen, n, err := d.DecodeUint()
|
||||
if err != nil {
|
||||
return "", n, err
|
||||
}
|
||||
if uint(dataLen) > uint(math.MaxInt32) ||
|
||||
(d.maxReadSize != 0 && uint(dataLen) > d.maxReadSize) {
|
||||
err = unmarshalError("DecodeString", ErrOverflow, errMaxSlice,
|
||||
dataLen, nil)
|
||||
return "", n, err
|
||||
}
|
||||
|
||||
opaque, n2, err := d.DecodeFixedOpaque(int32(dataLen))
|
||||
n += n2
|
||||
if err != nil {
|
||||
return "", n, err
|
||||
}
|
||||
return string(opaque), n, nil
|
||||
}
|
||||
|
||||
// decodeFixedArray treats the next bytes as a series of XDR encoded elements
|
||||
// of the same type as the array represented by the reflection value and decodes
|
||||
// each element into the passed array. The ignoreOpaque flag controls whether
|
||||
// or not uint8 (byte) elements should be decoded individually or as a fixed
|
||||
// sequence of opaque data. It returns the the number of bytes actually read.
|
||||
//
|
||||
// An UnmarshalError is returned if any issues are encountered while decoding
|
||||
// the array elements.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.12 - Fixed-Length Array
|
||||
// Individually XDR encoded array elements
|
||||
func (d *Decoder) decodeFixedArray(v reflect.Value, ignoreOpaque bool) (int, error) {
|
||||
// Treat [#]byte (byte is alias for uint8) as opaque data unless
|
||||
// ignored.
|
||||
if !ignoreOpaque && v.Type().Elem().Kind() == reflect.Uint8 {
|
||||
data, n, err := d.DecodeFixedOpaque(int32(v.Len()))
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
reflect.Copy(v, reflect.ValueOf(data))
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Decode each array element.
|
||||
var n int
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
n2, err := d.decode(v.Index(i))
|
||||
n += n2
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// decodeArray treats the next bytes as a variable length series of XDR encoded
|
||||
// elements of the same type as the array represented by the reflection value.
|
||||
// The number of elements is obtained by first decoding the unsigned integer
|
||||
// element count. Then each element is decoded into the passed array. The
|
||||
// ignoreOpaque flag controls whether or not uint8 (byte) elements should be
|
||||
// decoded individually or as a variable sequence of opaque data. It returns
|
||||
// the number of bytes actually read.
|
||||
//
|
||||
// An UnmarshalError is returned if any issues are encountered while decoding
|
||||
// the array elements.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.13 - Variable-Length Array
|
||||
// Unsigned integer length followed by individually XDR encoded array
|
||||
// elements
|
||||
func (d *Decoder) decodeArray(v reflect.Value, ignoreOpaque bool) (int, error) {
|
||||
dataLen, n, err := d.DecodeUint()
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
if uint(dataLen) > uint(math.MaxInt32) ||
|
||||
(d.maxReadSize != 0 && uint(dataLen) > d.maxReadSize) {
|
||||
err := unmarshalError("decodeArray", ErrOverflow, errMaxSlice,
|
||||
dataLen, nil)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Allocate storage for the slice elements (the underlying array) if
|
||||
// existing slice does not have enough capacity.
|
||||
sliceLen := int(dataLen)
|
||||
if v.Cap() < sliceLen {
|
||||
v.Set(reflect.MakeSlice(v.Type(), sliceLen, sliceLen))
|
||||
}
|
||||
if v.Len() < sliceLen {
|
||||
v.SetLen(sliceLen)
|
||||
}
|
||||
|
||||
// Treat []byte (byte is alias for uint8) as opaque data unless ignored.
|
||||
if !ignoreOpaque && v.Type().Elem().Kind() == reflect.Uint8 {
|
||||
data, n2, err := d.DecodeFixedOpaque(int32(sliceLen))
|
||||
n += n2
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
v.SetBytes(data)
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Decode each slice element.
|
||||
for i := 0; i < sliceLen; i++ {
|
||||
n2, err := d.decode(v.Index(i))
|
||||
n += n2
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// decodeStruct treats the next bytes as a series of XDR encoded elements
|
||||
// of the same type as the exported fields of the struct represented by the
|
||||
// passed reflection value. Pointers are automatically indirected and
|
||||
// allocated as necessary. It returns the the number of bytes actually read.
|
||||
//
|
||||
// An UnmarshalError is returned if any issues are encountered while decoding
|
||||
// the elements.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.14 - Structure
|
||||
// XDR encoded elements in the order of their declaration in the struct
|
||||
func (d *Decoder) decodeStruct(v reflect.Value) (int, error) {
|
||||
var n int
|
||||
vt := v.Type()
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
// Skip unexported fields.
|
||||
vtf := vt.Field(i)
|
||||
if vtf.PkgPath != "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Indirect through pointers allocating them as needed and
|
||||
// ensure the field is settable.
|
||||
vf := v.Field(i)
|
||||
vf, err := d.indirect(vf)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
if !vf.CanSet() {
|
||||
msg := fmt.Sprintf("can't decode to unsettable '%v'",
|
||||
vf.Type().String())
|
||||
err := unmarshalError("decodeStruct", ErrNotSettable,
|
||||
msg, nil, nil)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Handle non-opaque data to []uint8 and [#]uint8 based on
|
||||
// struct tag.
|
||||
tag := vtf.Tag.Get("xdropaque")
|
||||
if tag == "false" {
|
||||
switch vf.Kind() {
|
||||
case reflect.Slice:
|
||||
n2, err := d.decodeArray(vf, true)
|
||||
n += n2
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
continue
|
||||
|
||||
case reflect.Array:
|
||||
n2, err := d.decodeFixedArray(vf, true)
|
||||
n += n2
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Decode each struct field.
|
||||
n2, err := d.decode(vf)
|
||||
n += n2
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// RFC Section 4.15 - Discriminated Union
|
||||
// RFC Section 4.16 - Void
|
||||
// RFC Section 4.17 - Constant
|
||||
// RFC Section 4.18 - Typedef
|
||||
// RFC Section 4.19 - Optional data
|
||||
// RFC Sections 4.15 though 4.19 only apply to the data specification language
|
||||
// which is not implemented by this package. In the case of discriminated
|
||||
// unions, struct tags are used to perform a similar function.
|
||||
|
||||
// decodeMap treats the next bytes as an XDR encoded variable array of 2-element
|
||||
// structures whose fields are of the same type as the map keys and elements
|
||||
// represented by the passed reflection value. Pointers are automatically
|
||||
// indirected and allocated as necessary. It returns the the number of bytes
|
||||
// actually read.
|
||||
//
|
||||
// An UnmarshalError is returned if any issues are encountered while decoding
|
||||
// the elements.
|
||||
func (d *Decoder) decodeMap(v reflect.Value) (int, error) {
|
||||
dataLen, n, err := d.DecodeUint()
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Allocate storage for the underlying map if needed.
|
||||
vt := v.Type()
|
||||
if v.IsNil() {
|
||||
v.Set(reflect.MakeMap(vt))
|
||||
}
|
||||
|
||||
// Decode each key and value according to their type.
|
||||
keyType := vt.Key()
|
||||
elemType := vt.Elem()
|
||||
for i := uint32(0); i < dataLen; i++ {
|
||||
key := reflect.New(keyType).Elem()
|
||||
n2, err := d.decode(key)
|
||||
n += n2
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
||||
val := reflect.New(elemType).Elem()
|
||||
n2, err = d.decode(val)
|
||||
n += n2
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
v.SetMapIndex(key, val)
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// decodeInterface examines the interface represented by the passed reflection
|
||||
// value to detect whether it is an interface that can be decoded into and
|
||||
// if it is, extracts the underlying value to pass back into the decode function
|
||||
// for decoding according to its type. It returns the the number of bytes
|
||||
// actually read.
|
||||
//
|
||||
// An UnmarshalError is returned if any issues are encountered while decoding
|
||||
// the interface.
|
||||
func (d *Decoder) decodeInterface(v reflect.Value) (int, error) {
|
||||
if v.IsNil() || !v.CanInterface() {
|
||||
msg := fmt.Sprintf("can't decode to nil interface")
|
||||
err := unmarshalError("decodeInterface", ErrNilInterface, msg,
|
||||
nil, nil)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Extract underlying value from the interface and indirect through
|
||||
// pointers allocating them as needed.
|
||||
ve := reflect.ValueOf(v.Interface())
|
||||
ve, err := d.indirect(ve)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if !ve.CanSet() {
|
||||
msg := fmt.Sprintf("can't decode to unsettable '%v'",
|
||||
ve.Type().String())
|
||||
err := unmarshalError("decodeInterface", ErrNotSettable, msg,
|
||||
nil, nil)
|
||||
return 0, err
|
||||
}
|
||||
return d.decode(ve)
|
||||
}
|
||||
|
||||
// decode is the main workhorse for unmarshalling via reflection. It uses
|
||||
// the passed reflection value to choose the XDR primitives to decode from
|
||||
// the encapsulated reader. It is a recursive function,
|
||||
// so cyclic data structures are not supported and will result in an infinite
|
||||
// loop. It returns the the number of bytes actually read.
|
||||
func (d *Decoder) decode(v reflect.Value) (int, error) {
|
||||
if !v.IsValid() {
|
||||
msg := fmt.Sprintf("type '%s' is not valid", v.Kind().String())
|
||||
err := unmarshalError("decode", ErrUnsupportedType, msg, nil, nil)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Indirect through pointers allocating them as needed.
|
||||
ve, err := d.indirect(v)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Handle time.Time values by decoding them as an RFC3339 formatted
|
||||
// string with nanosecond precision. Check the type string rather
|
||||
// than doing a full blown conversion to interface and type assertion
|
||||
// since checking a string is much quicker.
|
||||
switch ve.Type().String() {
|
||||
case "time.Time":
|
||||
// Read the value as a string and parse it.
|
||||
timeString, n, err := d.DecodeString()
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
ttv, err := time.Parse(time.RFC3339, timeString)
|
||||
if err != nil {
|
||||
err := unmarshalError("decode", ErrParseTime,
|
||||
err.Error(), timeString, err)
|
||||
return n, err
|
||||
}
|
||||
ve.Set(reflect.ValueOf(ttv))
|
||||
return n, nil
|
||||
}
|
||||
// If this type is in our custom types map, call the decode routine set up
|
||||
// for it.
|
||||
if dt, ok := d.customTypes[ve.Type().String()]; ok {
|
||||
return dt.Decode(d, v)
|
||||
}
|
||||
|
||||
// Handle native Go types.
|
||||
switch ve.Kind() {
|
||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int:
|
||||
i, n, err := d.DecodeInt()
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
if ve.OverflowInt(int64(i)) {
|
||||
msg := fmt.Sprintf("signed integer too large to fit '%s'",
|
||||
ve.Kind().String())
|
||||
err = unmarshalError("decode", ErrOverflow, msg, i, nil)
|
||||
return n, err
|
||||
}
|
||||
ve.SetInt(int64(i))
|
||||
return n, nil
|
||||
|
||||
case reflect.Int64:
|
||||
i, n, err := d.DecodeHyper()
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
ve.SetInt(i)
|
||||
return n, nil
|
||||
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint:
|
||||
ui, n, err := d.DecodeUint()
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
if ve.OverflowUint(uint64(ui)) {
|
||||
msg := fmt.Sprintf("unsigned integer too large to fit '%s'",
|
||||
ve.Kind().String())
|
||||
err = unmarshalError("decode", ErrOverflow, msg, ui, nil)
|
||||
return n, err
|
||||
}
|
||||
ve.SetUint(uint64(ui))
|
||||
return n, nil
|
||||
|
||||
case reflect.Uint64:
|
||||
ui, n, err := d.DecodeUhyper()
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
ve.SetUint(ui)
|
||||
return n, nil
|
||||
|
||||
case reflect.Bool:
|
||||
b, n, err := d.DecodeBool()
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
ve.SetBool(b)
|
||||
return n, nil
|
||||
|
||||
case reflect.Float32:
|
||||
f, n, err := d.DecodeFloat()
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
ve.SetFloat(float64(f))
|
||||
return n, nil
|
||||
|
||||
case reflect.Float64:
|
||||
f, n, err := d.DecodeDouble()
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
ve.SetFloat(f)
|
||||
return n, nil
|
||||
|
||||
case reflect.String:
|
||||
s, n, err := d.DecodeString()
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
ve.SetString(s)
|
||||
return n, nil
|
||||
|
||||
case reflect.Array:
|
||||
n, err := d.decodeFixedArray(ve, false)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
return n, nil
|
||||
|
||||
case reflect.Slice:
|
||||
n, err := d.decodeArray(ve, false)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
return n, nil
|
||||
|
||||
case reflect.Struct:
|
||||
n, err := d.decodeStruct(ve)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
return n, nil
|
||||
|
||||
case reflect.Map:
|
||||
n, err := d.decodeMap(ve)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
return n, nil
|
||||
|
||||
case reflect.Interface:
|
||||
n, err := d.decodeInterface(ve)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// The only unhandled types left are unsupported. At the time of this
|
||||
// writing the only remaining unsupported types that exist are
|
||||
// reflect.Uintptr and reflect.UnsafePointer.
|
||||
msg := fmt.Sprintf("unsupported Go type '%s'", ve.Kind().String())
|
||||
err = unmarshalError("decode", ErrUnsupportedType, msg, nil, nil)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// indirect dereferences pointers allocating them as needed until it reaches
|
||||
// a non-pointer. This allows transparent decoding through arbitrary levels
|
||||
// of indirection.
|
||||
func (d *Decoder) indirect(v reflect.Value) (reflect.Value, error) {
|
||||
rv := v
|
||||
for rv.Kind() == reflect.Ptr {
|
||||
// Allocate pointer if needed.
|
||||
isNil := rv.IsNil()
|
||||
if isNil && !rv.CanSet() {
|
||||
msg := fmt.Sprintf("unable to allocate pointer for '%v'",
|
||||
rv.Type().String())
|
||||
err := unmarshalError("indirect", ErrNotSettable, msg,
|
||||
nil, nil)
|
||||
return rv, err
|
||||
}
|
||||
if isNil {
|
||||
rv.Set(reflect.New(rv.Type().Elem()))
|
||||
}
|
||||
rv = rv.Elem()
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
// Decode operates identically to the Unmarshal function with the exception of
|
||||
// using the reader associated with the Decoder as the source of XDR-encoded
|
||||
// data instead of a user-supplied reader. See the Unmarhsal documentation for
|
||||
// specifics.
|
||||
func (d *Decoder) Decode(v interface{}) (int, error) {
|
||||
if v == nil {
|
||||
msg := "can't unmarshal to nil interface"
|
||||
return 0, unmarshalError("Unmarshal", ErrNilInterface, msg, nil,
|
||||
nil)
|
||||
}
|
||||
|
||||
vv := reflect.ValueOf(v)
|
||||
if vv.Kind() != reflect.Ptr {
|
||||
msg := fmt.Sprintf("can't unmarshal to non-pointer '%v' - use "+
|
||||
"& operator", vv.Type().String())
|
||||
err := unmarshalError("Unmarshal", ErrBadArguments, msg, nil, nil)
|
||||
return 0, err
|
||||
}
|
||||
if vv.IsNil() && !vv.CanSet() {
|
||||
msg := fmt.Sprintf("can't unmarshal to unsettable '%v' - use "+
|
||||
"& operator", vv.Type().String())
|
||||
err := unmarshalError("Unmarshal", ErrNotSettable, msg, nil, nil)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return d.decode(vv)
|
||||
}
|
||||
|
||||
// NewDecoder returns a Decoder that can be used to manually decode XDR data
|
||||
// from a provided reader. Typically, Unmarshal should be used instead of
|
||||
// manually creating a Decoder.
|
||||
func NewDecoder(r io.Reader) *Decoder {
|
||||
return &Decoder{r: r}
|
||||
}
|
||||
|
||||
// NewDecoderLimited is identical to NewDecoder but it sets maxReadSize in
|
||||
// order to cap reads.
|
||||
func NewDecoderLimited(r io.Reader, maxSize uint) *Decoder {
|
||||
return &Decoder{r: r, maxReadSize: maxSize}
|
||||
}
|
||||
|
||||
// NewDecoderCustomTypes returns a decoder with support for custom types known
|
||||
// to the caller. The second parameter is a map of the type name to the decoder
|
||||
// routine. When the decoder finds a type matching one of the entries in the map
|
||||
// it will call the custom routine for that type.
|
||||
func NewDecoderCustomTypes(r io.Reader, maxSize uint, ct map[string]TypeDecoder) *Decoder {
|
||||
return &Decoder{r: r, maxReadSize: maxSize, customTypes: ct}
|
||||
}
|
||||
171
vendor/github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2/doc.go
generated
vendored
Normal file
171
vendor/github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2014 Dave Collins <dave@davec.name>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
Package xdr implements the data representation portion of the External Data
|
||||
Representation (XDR) standard protocol as specified in RFC 4506 (obsoletes
|
||||
RFC 1832 and RFC 1014).
|
||||
|
||||
The XDR RFC defines both a data specification language and a data
|
||||
representation standard. This package implements methods to encode and decode
|
||||
XDR data per the data representation standard with the exception of 128-bit
|
||||
quadruple-precision floating points. It does not currently implement parsing of
|
||||
the data specification language. In other words, the ability to automatically
|
||||
generate Go code by parsing an XDR data specification file (typically .x
|
||||
extension) is not supported. In practice, this limitation of the package is
|
||||
fairly minor since it is largely unnecessary due to the reflection capabilities
|
||||
of Go as described below.
|
||||
|
||||
This package provides two approaches for encoding and decoding XDR data:
|
||||
|
||||
1) Marshal/Unmarshal functions which automatically map between XDR and Go types
|
||||
2) Individual Encoder/Decoder objects to manually work with XDR primitives
|
||||
|
||||
For the Marshal/Unmarshal functions, Go reflection capabilities are used to
|
||||
choose the type of the underlying XDR data based upon the Go type to encode or
|
||||
the target Go type to decode into. A description of how each type is mapped is
|
||||
provided below, however one important type worth reviewing is Go structs. In
|
||||
the case of structs, each exported field (first letter capitalized) is reflected
|
||||
and mapped in order. As a result, this means a Go struct with exported fields
|
||||
of the appropriate types listed in the expected order can be used to
|
||||
automatically encode / decode the XDR data thereby eliminating the need to write
|
||||
a lot of boilerplate code to encode/decode and error check each piece of XDR
|
||||
data as is typically required with C based XDR libraries.
|
||||
|
||||
Go Type to XDR Type Mappings
|
||||
|
||||
The following chart shows an overview of how Go types are mapped to XDR types
|
||||
for automatic marshalling and unmarshalling. The documentation for the Marshal
|
||||
and Unmarshal functions has specific details of how the mapping proceeds.
|
||||
|
||||
Go Type <-> XDR Type
|
||||
--------------------
|
||||
int8, int16, int32, int <-> XDR Integer
|
||||
uint8, uint16, uint32, uint <-> XDR Unsigned Integer
|
||||
int64 <-> XDR Hyper Integer
|
||||
uint64 <-> XDR Unsigned Hyper Integer
|
||||
bool <-> XDR Boolean
|
||||
float32 <-> XDR Floating-Point
|
||||
float64 <-> XDR Double-Precision Floating-Point
|
||||
string <-> XDR String
|
||||
byte <-> XDR Integer
|
||||
[]byte <-> XDR Variable-Length Opaque Data
|
||||
[#]byte <-> XDR Fixed-Length Opaque Data
|
||||
[]<type> <-> XDR Variable-Length Array
|
||||
[#]<type> <-> XDR Fixed-Length Array
|
||||
struct <-> XDR Structure
|
||||
map <-> XDR Variable-Length Array of two-element XDR Structures
|
||||
time.Time <-> XDR String encoded with RFC3339 nanosecond precision
|
||||
|
||||
Notes and Limitations:
|
||||
|
||||
* Automatic marshalling and unmarshalling of variable and fixed-length
|
||||
arrays of uint8s require a special struct tag `xdropaque:"false"`
|
||||
since byte slices and byte arrays are assumed to be opaque data and
|
||||
byte is a Go alias for uint8 thus indistinguishable under reflection
|
||||
* Channel, complex, and function types cannot be encoded
|
||||
* Interfaces without a concrete value cannot be encoded
|
||||
* Cyclic data structures are not supported and will result in infinite
|
||||
loops
|
||||
* Strings are marshalled and unmarshalled with UTF-8 character encoding
|
||||
which differs from the XDR specification of ASCII, however UTF-8 is
|
||||
backwards compatible with ASCII so this should rarely cause issues
|
||||
|
||||
|
||||
Encoding
|
||||
|
||||
To encode XDR data, use the Marshal function.
|
||||
func Marshal(w io.Writer, v interface{}) (int, error)
|
||||
|
||||
For example, given the following code snippet:
|
||||
|
||||
type ImageHeader struct {
|
||||
Signature [3]byte
|
||||
Version uint32
|
||||
IsGrayscale bool
|
||||
NumSections uint32
|
||||
}
|
||||
h := ImageHeader{[3]byte{0xAB, 0xCD, 0xEF}, 2, true, 10}
|
||||
|
||||
var w bytes.Buffer
|
||||
bytesWritten, err := xdr.Marshal(&w, &h)
|
||||
// Error check elided
|
||||
|
||||
The result, encodedData, will then contain the following XDR encoded byte
|
||||
sequence:
|
||||
|
||||
0xAB, 0xCD, 0xEF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x0A
|
||||
|
||||
|
||||
In addition, while the automatic marshalling discussed above will work for the
|
||||
vast majority of cases, an Encoder object is provided that can be used to
|
||||
manually encode XDR primitives for complex scenarios where automatic
|
||||
reflection-based encoding won't work. The included examples provide a sample of
|
||||
manual usage via an Encoder.
|
||||
|
||||
|
||||
Decoding
|
||||
|
||||
To decode XDR data, use the Unmarshal function.
|
||||
func Unmarshal(r io.Reader, v interface{}) (int, error)
|
||||
|
||||
For example, given the following code snippet:
|
||||
|
||||
type ImageHeader struct {
|
||||
Signature [3]byte
|
||||
Version uint32
|
||||
IsGrayscale bool
|
||||
NumSections uint32
|
||||
}
|
||||
|
||||
// Using output from the Encoding section above.
|
||||
encodedData := []byte{
|
||||
0xAB, 0xCD, 0xEF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x0A,
|
||||
}
|
||||
|
||||
var h ImageHeader
|
||||
bytesRead, err := xdr.Unmarshal(bytes.NewReader(encodedData), &h)
|
||||
// Error check elided
|
||||
|
||||
The struct instance, h, will then contain the following values:
|
||||
|
||||
h.Signature = [3]byte{0xAB, 0xCD, 0xEF}
|
||||
h.Version = 2
|
||||
h.IsGrayscale = true
|
||||
h.NumSections = 10
|
||||
|
||||
In addition, while the automatic unmarshalling discussed above will work for the
|
||||
vast majority of cases, a Decoder object is provided that can be used to
|
||||
manually decode XDR primitives for complex scenarios where automatic
|
||||
reflection-based decoding won't work. The included examples provide a sample of
|
||||
manual usage via a Decoder.
|
||||
|
||||
Errors
|
||||
|
||||
All errors are either of type UnmarshalError or MarshalError. Both provide
|
||||
human-readable output as well as an ErrorCode field which can be inspected by
|
||||
sophisticated callers if necessary.
|
||||
|
||||
See the documentation of UnmarshalError, MarshalError, and ErrorCode for further
|
||||
details.
|
||||
*/
|
||||
package xdr
|
||||
669
vendor/github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2/encode.go
generated
vendored
Normal file
669
vendor/github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2/encode.go
generated
vendored
Normal file
|
|
@ -0,0 +1,669 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2014 Dave Collins <dave@davec.name>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
package xdr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
var errIOEncode = "%s while encoding %d bytes"
|
||||
|
||||
/*
|
||||
Marshal writes the XDR encoding of v to writer w and returns the number of bytes
|
||||
written. It traverses v recursively and automatically indirects pointers
|
||||
through arbitrary depth to encode the actual value pointed to.
|
||||
|
||||
Marshal uses reflection to determine the type of the concrete value contained by
|
||||
v and performs a mapping of Go types to the underlying XDR types as follows:
|
||||
|
||||
Go Type -> XDR Type
|
||||
--------------------
|
||||
int8, int16, int32, int -> XDR Integer
|
||||
uint8, uint16, uint32, uint -> XDR Unsigned Integer
|
||||
int64 -> XDR Hyper Integer
|
||||
uint64 -> XDR Unsigned Hyper Integer
|
||||
bool -> XDR Boolean
|
||||
float32 -> XDR Floating-Point
|
||||
float64 -> XDR Double-Precision Floating-Point
|
||||
string -> XDR String
|
||||
byte -> XDR Integer
|
||||
[]byte -> XDR Variable-Length Opaque Data
|
||||
[#]byte -> XDR Fixed-Length Opaque Data
|
||||
[]<type> -> XDR Variable-Length Array
|
||||
[#]<type> -> XDR Fixed-Length Array
|
||||
struct -> XDR Structure
|
||||
map -> XDR Variable-Length Array of two-element XDR Structures
|
||||
time.Time -> XDR String encoded with RFC3339 nanosecond precision
|
||||
|
||||
Notes and Limitations:
|
||||
|
||||
* Automatic marshalling of variable and fixed-length arrays of uint8s
|
||||
requires a special struct tag `xdropaque:"false"` since byte slices and
|
||||
byte arrays are assumed to be opaque data and byte is a Go alias for uint8
|
||||
thus indistinguishable under reflection
|
||||
* Channel, complex, and function types cannot be encoded
|
||||
* Interfaces without a concrete value cannot be encoded
|
||||
* Cyclic data structures are not supported and will result in infinite loops
|
||||
* Strings are marshalled with UTF-8 character encoding which differs from
|
||||
the XDR specification of ASCII, however UTF-8 is backwards compatible with
|
||||
ASCII so this should rarely cause issues
|
||||
|
||||
If any issues are encountered during the marshalling process, a MarshalError is
|
||||
returned with a human readable description as well as an ErrorCode value for
|
||||
further inspection from sophisticated callers. Some potential issues are
|
||||
unsupported Go types, attempting to encode more opaque data than can be
|
||||
represented by a single opaque XDR entry, and exceeding max slice limitations.
|
||||
*/
|
||||
func Marshal(w io.Writer, v interface{}) (int, error) {
|
||||
enc := Encoder{w: w}
|
||||
return enc.Encode(v)
|
||||
}
|
||||
|
||||
// An Encoder wraps an io.Writer that will receive the XDR encoded byte stream.
|
||||
// See NewEncoder.
|
||||
type Encoder struct {
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
// EncodeInt writes the XDR encoded representation of the passed 32-bit signed
|
||||
// integer to the encapsulated writer and returns the number of bytes written.
|
||||
//
|
||||
// A MarshalError with an error code of ErrIO is returned if writing the data
|
||||
// fails.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.1 - Integer
|
||||
// 32-bit big-endian signed integer in range [-2147483648, 2147483647]
|
||||
func (enc *Encoder) EncodeInt(v int32) (int, error) {
|
||||
var b [4]byte
|
||||
b[0] = byte(v >> 24)
|
||||
b[1] = byte(v >> 16)
|
||||
b[2] = byte(v >> 8)
|
||||
b[3] = byte(v)
|
||||
|
||||
n, err := enc.w.Write(b[:])
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf(errIOEncode, err.Error(), 4)
|
||||
err := marshalError("EncodeInt", ErrIO, msg, b[:n], err)
|
||||
return n, err
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// EncodeUint writes the XDR encoded representation of the passed 32-bit
|
||||
// unsigned integer to the encapsulated writer and returns the number of bytes
|
||||
// written.
|
||||
//
|
||||
// A MarshalError with an error code of ErrIO is returned if writing the data
|
||||
// fails.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.2 - Unsigned Integer
|
||||
// 32-bit big-endian unsigned integer in range [0, 4294967295]
|
||||
func (enc *Encoder) EncodeUint(v uint32) (int, error) {
|
||||
var b [4]byte
|
||||
b[0] = byte(v >> 24)
|
||||
b[1] = byte(v >> 16)
|
||||
b[2] = byte(v >> 8)
|
||||
b[3] = byte(v)
|
||||
|
||||
n, err := enc.w.Write(b[:])
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf(errIOEncode, err.Error(), 4)
|
||||
err := marshalError("EncodeUint", ErrIO, msg, b[:n], err)
|
||||
return n, err
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// EncodeEnum treats the passed 32-bit signed integer as an enumeration value
|
||||
// and, if it is in the list of passed valid enumeration values, writes the XDR
|
||||
// encoded representation of it to the encapsulated writer. It returns the
|
||||
// number of bytes written.
|
||||
//
|
||||
// A MarshalError is returned if the enumeration value is not one of the
|
||||
// provided valid values or if writing the data fails.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.3 - Enumeration
|
||||
// Represented as an XDR encoded signed integer
|
||||
func (enc *Encoder) EncodeEnum(v int32, validEnums map[int32]bool) (int, error) {
|
||||
if !validEnums[v] {
|
||||
err := marshalError("EncodeEnum", ErrBadEnumValue,
|
||||
"invalid enum", v, nil)
|
||||
return 0, err
|
||||
}
|
||||
return enc.EncodeInt(v)
|
||||
}
|
||||
|
||||
// EncodeBool writes the XDR encoded representation of the passed boolean to the
|
||||
// encapsulated writer and returns the number of bytes written.
|
||||
//
|
||||
// A MarshalError with an error code of ErrIO is returned if writing the data
|
||||
// fails.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.4 - Boolean
|
||||
// Represented as an XDR encoded enumeration where 0 is false and 1 is true
|
||||
func (enc *Encoder) EncodeBool(v bool) (int, error) {
|
||||
i := int32(0)
|
||||
if v == true {
|
||||
i = 1
|
||||
}
|
||||
return enc.EncodeInt(i)
|
||||
}
|
||||
|
||||
// EncodeHyper writes the XDR encoded representation of the passed 64-bit
|
||||
// signed integer to the encapsulated writer and returns the number of bytes
|
||||
// written.
|
||||
//
|
||||
// A MarshalError with an error code of ErrIO is returned if writing the data
|
||||
// fails.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.5 - Hyper Integer
|
||||
// 64-bit big-endian signed integer in range [-9223372036854775808, 9223372036854775807]
|
||||
func (enc *Encoder) EncodeHyper(v int64) (int, error) {
|
||||
var b [8]byte
|
||||
b[0] = byte(v >> 56)
|
||||
b[1] = byte(v >> 48)
|
||||
b[2] = byte(v >> 40)
|
||||
b[3] = byte(v >> 32)
|
||||
b[4] = byte(v >> 24)
|
||||
b[5] = byte(v >> 16)
|
||||
b[6] = byte(v >> 8)
|
||||
b[7] = byte(v)
|
||||
|
||||
n, err := enc.w.Write(b[:])
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf(errIOEncode, err.Error(), 8)
|
||||
err := marshalError("EncodeHyper", ErrIO, msg, b[:n], err)
|
||||
return n, err
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// EncodeUhyper writes the XDR encoded representation of the passed 64-bit
|
||||
// unsigned integer to the encapsulated writer and returns the number of bytes
|
||||
// written.
|
||||
//
|
||||
// A MarshalError with an error code of ErrIO is returned if writing the data
|
||||
// fails.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.5 - Unsigned Hyper Integer
|
||||
// 64-bit big-endian unsigned integer in range [0, 18446744073709551615]
|
||||
func (enc *Encoder) EncodeUhyper(v uint64) (int, error) {
|
||||
var b [8]byte
|
||||
b[0] = byte(v >> 56)
|
||||
b[1] = byte(v >> 48)
|
||||
b[2] = byte(v >> 40)
|
||||
b[3] = byte(v >> 32)
|
||||
b[4] = byte(v >> 24)
|
||||
b[5] = byte(v >> 16)
|
||||
b[6] = byte(v >> 8)
|
||||
b[7] = byte(v)
|
||||
|
||||
n, err := enc.w.Write(b[:])
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf(errIOEncode, err.Error(), 8)
|
||||
err := marshalError("EncodeUhyper", ErrIO, msg, b[:n], err)
|
||||
return n, err
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// EncodeFloat writes the XDR encoded representation of the passed 32-bit
|
||||
// (single-precision) floating point to the encapsulated writer and returns the
|
||||
// number of bytes written.
|
||||
//
|
||||
// A MarshalError with an error code of ErrIO is returned if writing the data
|
||||
// fails.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.6 - Floating Point
|
||||
// 32-bit single-precision IEEE 754 floating point
|
||||
func (enc *Encoder) EncodeFloat(v float32) (int, error) {
|
||||
ui := math.Float32bits(v)
|
||||
return enc.EncodeUint(ui)
|
||||
}
|
||||
|
||||
// EncodeDouble writes the XDR encoded representation of the passed 64-bit
|
||||
// (double-precision) floating point to the encapsulated writer and returns the
|
||||
// number of bytes written.
|
||||
//
|
||||
// A MarshalError with an error code of ErrIO is returned if writing the data
|
||||
// fails.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.7 - Double-Precision Floating Point
|
||||
// 64-bit double-precision IEEE 754 floating point
|
||||
func (enc *Encoder) EncodeDouble(v float64) (int, error) {
|
||||
ui := math.Float64bits(v)
|
||||
return enc.EncodeUhyper(ui)
|
||||
}
|
||||
|
||||
// RFC Section 4.8 - Quadruple-Precision Floating Point
|
||||
// 128-bit quadruple-precision floating point
|
||||
// Not Implemented
|
||||
|
||||
// EncodeFixedOpaque treats the passed byte slice as opaque data of a fixed
|
||||
// size and writes the XDR encoded representation of it to the encapsulated
|
||||
// writer. It returns the number of bytes written.
|
||||
//
|
||||
// A MarshalError with an error code of ErrIO is returned if writing the data
|
||||
// fails.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.9 - Fixed-Length Opaque Data
|
||||
// Fixed-length uninterpreted data zero-padded to a multiple of four
|
||||
func (enc *Encoder) EncodeFixedOpaque(v []byte) (int, error) {
|
||||
l := len(v)
|
||||
pad := (4 - (l % 4)) % 4
|
||||
|
||||
// Write the actual bytes.
|
||||
n, err := enc.w.Write(v)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf(errIOEncode, err.Error(), len(v))
|
||||
err := marshalError("EncodeFixedOpaque", ErrIO, msg, v[:n], err)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Write any padding if needed.
|
||||
if pad > 0 {
|
||||
b := make([]byte, pad)
|
||||
n2, err := enc.w.Write(b)
|
||||
n += n2
|
||||
if err != nil {
|
||||
written := make([]byte, l+n2)
|
||||
copy(written, v)
|
||||
copy(written[l:], b[:n2])
|
||||
msg := fmt.Sprintf(errIOEncode, err.Error(), l+pad)
|
||||
err := marshalError("EncodeFixedOpaque", ErrIO, msg,
|
||||
written, err)
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// EncodeOpaque treats the passed byte slice as opaque data of a variable
|
||||
// size and writes the XDR encoded representation of it to the encapsulated
|
||||
// writer. It returns the number of bytes written.
|
||||
//
|
||||
// A MarshalError with an error code of ErrIO is returned if writing the data
|
||||
// fails.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.10 - Variable-Length Opaque Data
|
||||
// Unsigned integer length followed by fixed opaque data of that length
|
||||
func (enc *Encoder) EncodeOpaque(v []byte) (int, error) {
|
||||
// Length of opaque data.
|
||||
n, err := enc.EncodeUint(uint32(len(v)))
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
||||
n2, err := enc.EncodeFixedOpaque(v)
|
||||
n += n2
|
||||
return n, err
|
||||
}
|
||||
|
||||
// EncodeString writes the XDR encoded representation of the passed string
|
||||
// to the encapsulated writer and returns the number of bytes written.
|
||||
// Character encoding is assumed to be UTF-8 and therefore ASCII compatible. If
|
||||
// the underlying character encoding is not compatible with this assumption, the
|
||||
// data can instead be written as variable-length opaque data (EncodeOpaque) and
|
||||
// manually converted as needed.
|
||||
//
|
||||
// A MarshalError with an error code of ErrIO is returned if writing the data
|
||||
// fails.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.11 - String
|
||||
// Unsigned integer length followed by bytes zero-padded to a multiple of four
|
||||
func (enc *Encoder) EncodeString(v string) (int, error) {
|
||||
// Length of string.
|
||||
n, err := enc.EncodeUint(uint32(len(v)))
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
||||
n2, err := enc.EncodeFixedOpaque([]byte(v))
|
||||
n += n2
|
||||
return n, err
|
||||
}
|
||||
|
||||
// encodeFixedArray writes the XDR encoded representation of each element
|
||||
// in the passed array represented by the reflection value to the encapsulated
|
||||
// writer and returns the number of bytes written. The ignoreOpaque flag
|
||||
// controls whether or not uint8 (byte) elements should be encoded individually
|
||||
// or as a fixed sequence of opaque data.
|
||||
//
|
||||
// A MarshalError is returned if any issues are encountered while encoding
|
||||
// the array elements.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.12 - Fixed-Length Array
|
||||
// Individually XDR encoded array elements
|
||||
func (enc *Encoder) encodeFixedArray(v reflect.Value, ignoreOpaque bool) (int, error) {
|
||||
// Treat [#]byte (byte is alias for uint8) as opaque data unless ignored.
|
||||
if !ignoreOpaque && v.Type().Elem().Kind() == reflect.Uint8 {
|
||||
// Create a slice of the underlying array for better efficiency
|
||||
// when possible. Can't create a slice of an unaddressable
|
||||
// value.
|
||||
if v.CanAddr() {
|
||||
return enc.EncodeFixedOpaque(v.Slice(0, v.Len()).Bytes())
|
||||
}
|
||||
|
||||
// When the underlying array isn't addressable fall back to
|
||||
// copying the array into a new slice. This is rather ugly, but
|
||||
// the inability to create a constant slice from an
|
||||
// unaddressable array is a limitation of Go.
|
||||
slice := make([]byte, v.Len(), v.Len())
|
||||
reflect.Copy(reflect.ValueOf(slice), v)
|
||||
return enc.EncodeFixedOpaque(slice)
|
||||
}
|
||||
|
||||
// Encode each array element.
|
||||
var n int
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
n2, err := enc.encode(v.Index(i))
|
||||
n += n2
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// encodeArray writes an XDR encoded integer representing the number of
|
||||
// elements in the passed slice represented by the reflection value followed by
|
||||
// the XDR encoded representation of each element in slice to the encapsulated
|
||||
// writer and returns the number of bytes written. The ignoreOpaque flag
|
||||
// controls whether or not uint8 (byte) elements should be encoded individually
|
||||
// or as a variable sequence of opaque data.
|
||||
//
|
||||
// A MarshalError is returned if any issues are encountered while encoding
|
||||
// the array elements.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.13 - Variable-Length Array
|
||||
// Unsigned integer length followed by individually XDR encoded array elements
|
||||
func (enc *Encoder) encodeArray(v reflect.Value, ignoreOpaque bool) (int, error) {
|
||||
numItems := uint32(v.Len())
|
||||
n, err := enc.EncodeUint(numItems)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
||||
n2, err := enc.encodeFixedArray(v, ignoreOpaque)
|
||||
n += n2
|
||||
return n, err
|
||||
}
|
||||
|
||||
// encodeStruct writes an XDR encoded representation of each value in the
|
||||
// exported fields of the struct represented by the passed reflection value to
|
||||
// the encapsulated writer and returns the number of bytes written. Pointers
|
||||
// are automatically indirected through arbitrary depth to encode the actual
|
||||
// value pointed to.
|
||||
//
|
||||
// A MarshalError is returned if any issues are encountered while encoding
|
||||
// the elements.
|
||||
//
|
||||
// Reference:
|
||||
// RFC Section 4.14 - Structure
|
||||
// XDR encoded elements in the order of their declaration in the struct
|
||||
func (enc *Encoder) encodeStruct(v reflect.Value) (int, error) {
|
||||
var n int
|
||||
vt := v.Type()
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
// Skip unexported fields and indirect through pointers.
|
||||
vtf := vt.Field(i)
|
||||
if vtf.PkgPath != "" {
|
||||
continue
|
||||
}
|
||||
vf := v.Field(i)
|
||||
vf = enc.indirect(vf)
|
||||
|
||||
// Handle non-opaque data to []uint8 and [#]uint8 based on struct tag.
|
||||
tag := vtf.Tag.Get("xdropaque")
|
||||
if tag == "false" {
|
||||
switch vf.Kind() {
|
||||
case reflect.Slice:
|
||||
n2, err := enc.encodeArray(vf, true)
|
||||
n += n2
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
continue
|
||||
|
||||
case reflect.Array:
|
||||
n2, err := enc.encodeFixedArray(vf, true)
|
||||
n += n2
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Encode each struct field.
|
||||
n2, err := enc.encode(vf)
|
||||
n += n2
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// RFC Section 4.15 - Discriminated Union
|
||||
// RFC Section 4.16 - Void
|
||||
// RFC Section 4.17 - Constant
|
||||
// RFC Section 4.18 - Typedef
|
||||
// RFC Section 4.19 - Optional data
|
||||
// RFC Sections 4.15 though 4.19 only apply to the data specification language
|
||||
// which is not implemented by this package. In the case of discriminated
|
||||
// unions, struct tags are used to perform a similar function.
|
||||
|
||||
// encodeMap treats the map represented by the passed reflection value as a
|
||||
// variable-length array of 2-element structures whose fields are of the same
|
||||
// type as the map keys and elements and writes its XDR encoded representation
|
||||
// to the encapsulated writer. It returns the number of bytes written.
|
||||
//
|
||||
// A MarshalError is returned if any issues are encountered while encoding
|
||||
// the elements.
|
||||
func (enc *Encoder) encodeMap(v reflect.Value) (int, error) {
|
||||
// Number of elements.
|
||||
n, err := enc.EncodeUint(uint32(v.Len()))
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Encode each key and value according to their type.
|
||||
for _, key := range v.MapKeys() {
|
||||
n2, err := enc.encode(key)
|
||||
n += n2
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
||||
n2, err = enc.encode(v.MapIndex(key))
|
||||
n += n2
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// encodeInterface examines the interface represented by the passed reflection
|
||||
// value to detect whether it is an interface that can be encoded if it is,
|
||||
// extracts the underlying value to pass back into the encode function for
|
||||
// encoding according to its type.
|
||||
//
|
||||
// A MarshalError is returned if any issues are encountered while encoding
|
||||
// the interface.
|
||||
func (enc *Encoder) encodeInterface(v reflect.Value) (int, error) {
|
||||
if v.IsNil() || !v.CanInterface() {
|
||||
msg := fmt.Sprintf("can't encode nil interface")
|
||||
err := marshalError("encodeInterface", ErrNilInterface, msg,
|
||||
nil, nil)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Extract underlying value from the interface and indirect through pointers.
|
||||
ve := reflect.ValueOf(v.Interface())
|
||||
ve = enc.indirect(ve)
|
||||
return enc.encode(ve)
|
||||
}
|
||||
|
||||
// encode is the main workhorse for marshalling via reflection. It uses
|
||||
// the passed reflection value to choose the XDR primitives to encode into
|
||||
// the encapsulated writer and returns the number of bytes written. It is a
|
||||
// recursive function, so cyclic data structures are not supported and will
|
||||
// result in an infinite loop.
|
||||
func (enc *Encoder) encode(v reflect.Value) (int, error) {
|
||||
if !v.IsValid() {
|
||||
msg := fmt.Sprintf("type '%s' is not valid", v.Kind().String())
|
||||
err := marshalError("encode", ErrUnsupportedType, msg, nil, nil)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Indirect through pointers to get at the concrete value.
|
||||
ve := enc.indirect(v)
|
||||
|
||||
// Handle time.Time values by encoding them as an RFC3339 formatted
|
||||
// string with nanosecond precision. Check the type string before
|
||||
// doing a full blown conversion to interface and type assertion since
|
||||
// checking a string is much quicker.
|
||||
if ve.Type().String() == "time.Time" && ve.CanInterface() {
|
||||
viface := ve.Interface()
|
||||
if tv, ok := viface.(time.Time); ok {
|
||||
return enc.EncodeString(tv.Format(time.RFC3339Nano))
|
||||
}
|
||||
}
|
||||
|
||||
// Handle native Go types.
|
||||
switch ve.Kind() {
|
||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int:
|
||||
return enc.EncodeInt(int32(ve.Int()))
|
||||
|
||||
case reflect.Int64:
|
||||
return enc.EncodeHyper(ve.Int())
|
||||
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint:
|
||||
return enc.EncodeUint(uint32(ve.Uint()))
|
||||
|
||||
case reflect.Uint64:
|
||||
return enc.EncodeUhyper(ve.Uint())
|
||||
|
||||
case reflect.Bool:
|
||||
return enc.EncodeBool(ve.Bool())
|
||||
|
||||
case reflect.Float32:
|
||||
return enc.EncodeFloat(float32(ve.Float()))
|
||||
|
||||
case reflect.Float64:
|
||||
return enc.EncodeDouble(ve.Float())
|
||||
|
||||
case reflect.String:
|
||||
return enc.EncodeString(ve.String())
|
||||
|
||||
case reflect.Array:
|
||||
return enc.encodeFixedArray(ve, false)
|
||||
|
||||
case reflect.Slice:
|
||||
return enc.encodeArray(ve, false)
|
||||
|
||||
case reflect.Struct:
|
||||
return enc.encodeStruct(ve)
|
||||
|
||||
case reflect.Map:
|
||||
return enc.encodeMap(ve)
|
||||
|
||||
case reflect.Interface:
|
||||
return enc.encodeInterface(ve)
|
||||
}
|
||||
|
||||
// The only unhandled types left are unsupported. At the time of this
|
||||
// writing the only remaining unsupported types that exist are
|
||||
// reflect.Uintptr and reflect.UnsafePointer.
|
||||
msg := fmt.Sprintf("unsupported Go type '%s'", ve.Kind().String())
|
||||
err := marshalError("encode", ErrUnsupportedType, msg, nil, nil)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// indirect dereferences pointers until it reaches a non-pointer. This allows
|
||||
// transparent encoding through arbitrary levels of indirection.
|
||||
func (enc *Encoder) indirect(v reflect.Value) reflect.Value {
|
||||
rv := v
|
||||
for rv.Kind() == reflect.Ptr {
|
||||
rv = rv.Elem()
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
// Encode operates identically to the Marshal function with the exception of
|
||||
// using the writer associated with the Encoder for the destination of the
|
||||
// XDR-encoded data instead of a user-supplied writer. See the Marshal
|
||||
// documentation for specifics.
|
||||
func (enc *Encoder) Encode(v interface{}) (int, error) {
|
||||
if v == nil {
|
||||
msg := "can't marshal nil interface"
|
||||
err := marshalError("Marshal", ErrNilInterface, msg, nil, nil)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
vv := reflect.ValueOf(v)
|
||||
vve := vv
|
||||
for vve.Kind() == reflect.Ptr {
|
||||
if vve.IsNil() {
|
||||
msg := fmt.Sprintf("can't marshal nil pointer '%v'",
|
||||
vv.Type().String())
|
||||
err := marshalError("Marshal", ErrBadArguments, msg,
|
||||
nil, nil)
|
||||
return 0, err
|
||||
}
|
||||
vve = vve.Elem()
|
||||
}
|
||||
|
||||
return enc.encode(vve)
|
||||
}
|
||||
|
||||
// NewEncoder returns an object that can be used to manually choose fields to
|
||||
// XDR encode to the passed writer w. Typically, Marshal should be used instead
|
||||
// of manually creating an Encoder. An Encoder, along with several of its
|
||||
// methods to encode XDR primitives, is exposed so it is possible to perform
|
||||
// manual encoding of data without relying on reflection should it be necessary
|
||||
// in complex scenarios where automatic reflection-based encoding won't work.
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
return &Encoder{w: w}
|
||||
}
|
||||
177
vendor/github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2/error.go
generated
vendored
Normal file
177
vendor/github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2/error.go
generated
vendored
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2014 Dave Collins <dave@davec.name>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
package xdr
|
||||
|
||||
import "fmt"
|
||||
|
||||
// ErrorCode identifies a kind of error.
|
||||
type ErrorCode int
|
||||
|
||||
const (
|
||||
// ErrBadArguments indicates arguments passed to the function are not
|
||||
// what was expected.
|
||||
ErrBadArguments ErrorCode = iota
|
||||
|
||||
// ErrUnsupportedType indicates the Go type is not a supported type for
|
||||
// marshalling and unmarshalling XDR data.
|
||||
ErrUnsupportedType
|
||||
|
||||
// ErrBadEnumValue indicates an enumeration value is not in the list of
|
||||
// valid values.
|
||||
ErrBadEnumValue
|
||||
|
||||
// ErrNotSettable indicates an interface value cannot be written to.
|
||||
// This usually means the interface value was not passed with the &
|
||||
// operator, but it can also happen if automatic pointer allocation
|
||||
// fails.
|
||||
ErrNotSettable
|
||||
|
||||
// ErrOverflow indicates that the data in question is too large to fit
|
||||
// into the corresponding Go or XDR data type. For example, an integer
|
||||
// decoded from XDR that is too large to fit into a target type of int8,
|
||||
// or opaque data that exceeds the max length of a Go slice.
|
||||
ErrOverflow
|
||||
|
||||
// ErrNilInterface indicates an interface with no concrete type
|
||||
// information was encountered. Type information is necessary to
|
||||
// perform mapping between XDR and Go types.
|
||||
ErrNilInterface
|
||||
|
||||
// ErrIO indicates an error was encountered while reading or writing to
|
||||
// an io.Reader or io.Writer, respectively. The actual underlying error
|
||||
// will be available via the Err field of the MarshalError or
|
||||
// UnmarshalError struct.
|
||||
ErrIO
|
||||
|
||||
// ErrParseTime indicates an error was encountered while parsing an
|
||||
// RFC3339 formatted time value. The actual underlying error will be
|
||||
// available via the Err field of the UnmarshalError struct.
|
||||
ErrParseTime
|
||||
)
|
||||
|
||||
// Map of ErrorCode values back to their constant names for pretty printing.
|
||||
var errorCodeStrings = map[ErrorCode]string{
|
||||
ErrBadArguments: "ErrBadArguments",
|
||||
ErrUnsupportedType: "ErrUnsupportedType",
|
||||
ErrBadEnumValue: "ErrBadEnumValue",
|
||||
ErrNotSettable: "ErrNotSettable",
|
||||
ErrOverflow: "ErrOverflow",
|
||||
ErrNilInterface: "ErrNilInterface",
|
||||
ErrIO: "ErrIO",
|
||||
ErrParseTime: "ErrParseTime",
|
||||
}
|
||||
|
||||
// String returns the ErrorCode as a human-readable name.
|
||||
func (e ErrorCode) String() string {
|
||||
if s := errorCodeStrings[e]; s != "" {
|
||||
return s
|
||||
}
|
||||
return fmt.Sprintf("Unknown ErrorCode (%d)", e)
|
||||
}
|
||||
|
||||
// UnmarshalError describes a problem encountered while unmarshaling data.
|
||||
// Some potential issues are unsupported Go types, attempting to decode a value
|
||||
// which is too large to fit into a specified Go type, and exceeding max slice
|
||||
// limitations.
|
||||
type UnmarshalError struct {
|
||||
ErrorCode ErrorCode // Describes the kind of error
|
||||
Func string // Function name
|
||||
Value interface{} // Value actually parsed where appropriate
|
||||
Description string // Human readable description of the issue
|
||||
Err error // The underlying error for IO errors
|
||||
}
|
||||
|
||||
// Error satisfies the error interface and prints human-readable errors.
|
||||
func (e *UnmarshalError) Error() string {
|
||||
switch e.ErrorCode {
|
||||
case ErrBadEnumValue, ErrOverflow, ErrIO, ErrParseTime:
|
||||
return fmt.Sprintf("xdr:%s: %s - read: '%v'", e.Func,
|
||||
e.Description, e.Value)
|
||||
}
|
||||
return fmt.Sprintf("xdr:%s: %s", e.Func, e.Description)
|
||||
}
|
||||
|
||||
// unmarshalError creates an error given a set of arguments and will copy byte
|
||||
// slices into the Value field since they might otherwise be changed from from
|
||||
// the original value.
|
||||
func unmarshalError(f string, c ErrorCode, desc string, v interface{}, err error) *UnmarshalError {
|
||||
e := &UnmarshalError{ErrorCode: c, Func: f, Description: desc, Err: err}
|
||||
switch t := v.(type) {
|
||||
case []byte:
|
||||
slice := make([]byte, len(t))
|
||||
copy(slice, t)
|
||||
e.Value = slice
|
||||
default:
|
||||
e.Value = v
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
// IsIO returns a boolean indicating whether the error is known to report that
|
||||
// the underlying reader or writer encountered an ErrIO.
|
||||
func IsIO(err error) bool {
|
||||
switch e := err.(type) {
|
||||
case *UnmarshalError:
|
||||
return e.ErrorCode == ErrIO
|
||||
case *MarshalError:
|
||||
return e.ErrorCode == ErrIO
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// MarshalError describes a problem encountered while marshaling data.
|
||||
// Some potential issues are unsupported Go types, attempting to encode more
|
||||
// opaque data than can be represented by a single opaque XDR entry, and
|
||||
// exceeding max slice limitations.
|
||||
type MarshalError struct {
|
||||
ErrorCode ErrorCode // Describes the kind of error
|
||||
Func string // Function name
|
||||
Value interface{} // Value actually parsed where appropriate
|
||||
Description string // Human readable description of the issue
|
||||
Err error // The underlying error for IO errors
|
||||
}
|
||||
|
||||
// Error satisfies the error interface and prints human-readable errors.
|
||||
func (e *MarshalError) Error() string {
|
||||
switch e.ErrorCode {
|
||||
case ErrIO:
|
||||
return fmt.Sprintf("xdr:%s: %s - wrote: '%v'", e.Func,
|
||||
e.Description, e.Value)
|
||||
case ErrBadEnumValue:
|
||||
return fmt.Sprintf("xdr:%s: %s - value: '%v'", e.Func,
|
||||
e.Description, e.Value)
|
||||
}
|
||||
return fmt.Sprintf("xdr:%s: %s", e.Func, e.Description)
|
||||
}
|
||||
|
||||
// marshalError creates an error given a set of arguments and will copy byte
|
||||
// slices into the Value field since they might otherwise be changed from from
|
||||
// the original value.
|
||||
func marshalError(f string, c ErrorCode, desc string, v interface{}, err error) *MarshalError {
|
||||
e := &MarshalError{ErrorCode: c, Func: f, Description: desc, Err: err}
|
||||
switch t := v.(type) {
|
||||
case []byte:
|
||||
slice := make([]byte, len(t))
|
||||
copy(slice, t)
|
||||
e.Value = slice
|
||||
default:
|
||||
e.Value = v
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue