podman
669 строк · 20.7 Кб
1/*
2* Copyright (c) 2012-2014 Dave Collins <dave@davec.name>
3*
4* Permission to use, copy, modify, and distribute this software for any
5* purpose with or without fee is hereby granted, provided that the above
6* copyright notice and this permission notice appear in all copies.
7*
8* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*/
16
17package xdr18
19import (20"fmt"21"io"22"math"23"reflect"24"time"25)
26
27var errIOEncode = "%s while encoding %d bytes"28
29/*
30Marshal writes the XDR encoding of v to writer w and returns the number of bytes
31written. It traverses v recursively and automatically indirects pointers
32through arbitrary depth to encode the actual value pointed to.
33
34Marshal uses reflection to determine the type of the concrete value contained by
35v and performs a mapping of Go types to the underlying XDR types as follows:
36
37Go Type -> XDR Type
38--------------------
39int8, int16, int32, int -> XDR Integer
40uint8, uint16, uint32, uint -> XDR Unsigned Integer
41int64 -> XDR Hyper Integer
42uint64 -> XDR Unsigned Hyper Integer
43bool -> XDR Boolean
44float32 -> XDR Floating-Point
45float64 -> XDR Double-Precision Floating-Point
46string -> XDR String
47byte -> XDR Integer
48[]byte -> XDR Variable-Length Opaque Data
49[#]byte -> XDR Fixed-Length Opaque Data
50[]<type> -> XDR Variable-Length Array
51[#]<type> -> XDR Fixed-Length Array
52struct -> XDR Structure
53map -> XDR Variable-Length Array of two-element XDR Structures
54time.Time -> XDR String encoded with RFC3339 nanosecond precision
55
56Notes and Limitations:
57
58* Automatic marshalling of variable and fixed-length arrays of uint8s
59requires a special struct tag `xdropaque:"false"` since byte slices and
60byte arrays are assumed to be opaque data and byte is a Go alias for uint8
61thus indistinguishable under reflection
62* Channel, complex, and function types cannot be encoded
63* Interfaces without a concrete value cannot be encoded
64* Cyclic data structures are not supported and will result in infinite loops
65* Strings are marshalled with UTF-8 character encoding which differs from
66the XDR specification of ASCII, however UTF-8 is backwards compatible with
67ASCII so this should rarely cause issues
68
69If any issues are encountered during the marshalling process, a MarshalError is
70returned with a human readable description as well as an ErrorCode value for
71further inspection from sophisticated callers. Some potential issues are
72unsupported Go types, attempting to encode more opaque data than can be
73represented by a single opaque XDR entry, and exceeding max slice limitations.
74*/
75func Marshal(w io.Writer, v interface{}) (int, error) {76enc := Encoder{w: w}77return enc.Encode(v)78}
79
80// An Encoder wraps an io.Writer that will receive the XDR encoded byte stream.
81// See NewEncoder.
82type Encoder struct {83w io.Writer84}
85
86// EncodeInt writes the XDR encoded representation of the passed 32-bit signed
87// integer to the encapsulated writer and returns the number of bytes written.
88//
89// A MarshalError with an error code of ErrIO is returned if writing the data
90// fails.
91//
92// Reference:
93// RFC Section 4.1 - Integer
94// 32-bit big-endian signed integer in range [-2147483648, 2147483647]
95func (enc *Encoder) EncodeInt(v int32) (int, error) {96var b [4]byte97b[0] = byte(v >> 24)98b[1] = byte(v >> 16)99b[2] = byte(v >> 8)100b[3] = byte(v)101
102n, err := enc.w.Write(b[:])103if err != nil {104msg := fmt.Sprintf(errIOEncode, err.Error(), 4)105err := marshalError("EncodeInt", ErrIO, msg, b[:n], err)106return n, err107}108
109return n, nil110}
111
112// EncodeUint writes the XDR encoded representation of the passed 32-bit
113// unsigned integer to the encapsulated writer and returns the number of bytes
114// written.
115//
116// A MarshalError with an error code of ErrIO is returned if writing the data
117// fails.
118//
119// Reference:
120// RFC Section 4.2 - Unsigned Integer
121// 32-bit big-endian unsigned integer in range [0, 4294967295]
122func (enc *Encoder) EncodeUint(v uint32) (int, error) {123var b [4]byte124b[0] = byte(v >> 24)125b[1] = byte(v >> 16)126b[2] = byte(v >> 8)127b[3] = byte(v)128
129n, err := enc.w.Write(b[:])130if err != nil {131msg := fmt.Sprintf(errIOEncode, err.Error(), 4)132err := marshalError("EncodeUint", ErrIO, msg, b[:n], err)133return n, err134}135
136return n, nil137}
138
139// EncodeEnum treats the passed 32-bit signed integer as an enumeration value
140// and, if it is in the list of passed valid enumeration values, writes the XDR
141// encoded representation of it to the encapsulated writer. It returns the
142// number of bytes written.
143//
144// A MarshalError is returned if the enumeration value is not one of the
145// provided valid values or if writing the data fails.
146//
147// Reference:
148// RFC Section 4.3 - Enumeration
149// Represented as an XDR encoded signed integer
150func (enc *Encoder) EncodeEnum(v int32, validEnums map[int32]bool) (int, error) {151if !validEnums[v] {152err := marshalError("EncodeEnum", ErrBadEnumValue,153"invalid enum", v, nil)154return 0, err155}156return enc.EncodeInt(v)157}
158
159// EncodeBool writes the XDR encoded representation of the passed boolean to the
160// encapsulated writer and returns the number of bytes written.
161//
162// A MarshalError with an error code of ErrIO is returned if writing the data
163// fails.
164//
165// Reference:
166// RFC Section 4.4 - Boolean
167// Represented as an XDR encoded enumeration where 0 is false and 1 is true
168func (enc *Encoder) EncodeBool(v bool) (int, error) {169i := int32(0)170if v == true {171i = 1172}173return enc.EncodeInt(i)174}
175
176// EncodeHyper writes the XDR encoded representation of the passed 64-bit
177// signed integer to the encapsulated writer and returns the number of bytes
178// written.
179//
180// A MarshalError with an error code of ErrIO is returned if writing the data
181// fails.
182//
183// Reference:
184// RFC Section 4.5 - Hyper Integer
185// 64-bit big-endian signed integer in range [-9223372036854775808, 9223372036854775807]
186func (enc *Encoder) EncodeHyper(v int64) (int, error) {187var b [8]byte188b[0] = byte(v >> 56)189b[1] = byte(v >> 48)190b[2] = byte(v >> 40)191b[3] = byte(v >> 32)192b[4] = byte(v >> 24)193b[5] = byte(v >> 16)194b[6] = byte(v >> 8)195b[7] = byte(v)196
197n, err := enc.w.Write(b[:])198if err != nil {199msg := fmt.Sprintf(errIOEncode, err.Error(), 8)200err := marshalError("EncodeHyper", ErrIO, msg, b[:n], err)201return n, err202}203
204return n, nil205}
206
207// EncodeUhyper writes the XDR encoded representation of the passed 64-bit
208// unsigned integer to the encapsulated writer and returns the number of bytes
209// written.
210//
211// A MarshalError with an error code of ErrIO is returned if writing the data
212// fails.
213//
214// Reference:
215// RFC Section 4.5 - Unsigned Hyper Integer
216// 64-bit big-endian unsigned integer in range [0, 18446744073709551615]
217func (enc *Encoder) EncodeUhyper(v uint64) (int, error) {218var b [8]byte219b[0] = byte(v >> 56)220b[1] = byte(v >> 48)221b[2] = byte(v >> 40)222b[3] = byte(v >> 32)223b[4] = byte(v >> 24)224b[5] = byte(v >> 16)225b[6] = byte(v >> 8)226b[7] = byte(v)227
228n, err := enc.w.Write(b[:])229if err != nil {230msg := fmt.Sprintf(errIOEncode, err.Error(), 8)231err := marshalError("EncodeUhyper", ErrIO, msg, b[:n], err)232return n, err233}234
235return n, nil236}
237
238// EncodeFloat writes the XDR encoded representation of the passed 32-bit
239// (single-precision) floating point to the encapsulated writer and returns the
240// number of bytes written.
241//
242// A MarshalError with an error code of ErrIO is returned if writing the data
243// fails.
244//
245// Reference:
246// RFC Section 4.6 - Floating Point
247// 32-bit single-precision IEEE 754 floating point
248func (enc *Encoder) EncodeFloat(v float32) (int, error) {249ui := math.Float32bits(v)250return enc.EncodeUint(ui)251}
252
253// EncodeDouble writes the XDR encoded representation of the passed 64-bit
254// (double-precision) floating point to the encapsulated writer and returns the
255// number of bytes written.
256//
257// A MarshalError with an error code of ErrIO is returned if writing the data
258// fails.
259//
260// Reference:
261// RFC Section 4.7 - Double-Precision Floating Point
262// 64-bit double-precision IEEE 754 floating point
263func (enc *Encoder) EncodeDouble(v float64) (int, error) {264ui := math.Float64bits(v)265return enc.EncodeUhyper(ui)266}
267
268// RFC Section 4.8 - Quadruple-Precision Floating Point
269// 128-bit quadruple-precision floating point
270// Not Implemented
271
272// EncodeFixedOpaque treats the passed byte slice as opaque data of a fixed
273// size and writes the XDR encoded representation of it to the encapsulated
274// writer. It returns the number of bytes written.
275//
276// A MarshalError with an error code of ErrIO is returned if writing the data
277// fails.
278//
279// Reference:
280// RFC Section 4.9 - Fixed-Length Opaque Data
281// Fixed-length uninterpreted data zero-padded to a multiple of four
282func (enc *Encoder) EncodeFixedOpaque(v []byte) (int, error) {283l := len(v)284pad := (4 - (l % 4)) % 4285
286// Write the actual bytes.287n, err := enc.w.Write(v)288if err != nil {289msg := fmt.Sprintf(errIOEncode, err.Error(), len(v))290err := marshalError("EncodeFixedOpaque", ErrIO, msg, v[:n], err)291return n, err292}293
294// Write any padding if needed.295if pad > 0 {296b := make([]byte, pad)297n2, err := enc.w.Write(b)298n += n2299if err != nil {300written := make([]byte, l+n2)301copy(written, v)302copy(written[l:], b[:n2])303msg := fmt.Sprintf(errIOEncode, err.Error(), l+pad)304err := marshalError("EncodeFixedOpaque", ErrIO, msg,305written, err)306return n, err307}308}309
310return n, nil311}
312
313// EncodeOpaque treats the passed byte slice as opaque data of a variable
314// size and writes the XDR encoded representation of it to the encapsulated
315// writer. It returns the number of bytes written.
316//
317// A MarshalError with an error code of ErrIO is returned if writing the data
318// fails.
319//
320// Reference:
321// RFC Section 4.10 - Variable-Length Opaque Data
322// Unsigned integer length followed by fixed opaque data of that length
323func (enc *Encoder) EncodeOpaque(v []byte) (int, error) {324// Length of opaque data.325n, err := enc.EncodeUint(uint32(len(v)))326if err != nil {327return n, err328}329
330n2, err := enc.EncodeFixedOpaque(v)331n += n2332return n, err333}
334
335// EncodeString writes the XDR encoded representation of the passed string
336// to the encapsulated writer and returns the number of bytes written.
337// Character encoding is assumed to be UTF-8 and therefore ASCII compatible. If
338// the underlying character encoding is not compatible with this assumption, the
339// data can instead be written as variable-length opaque data (EncodeOpaque) and
340// manually converted as needed.
341//
342// A MarshalError with an error code of ErrIO is returned if writing the data
343// fails.
344//
345// Reference:
346// RFC Section 4.11 - String
347// Unsigned integer length followed by bytes zero-padded to a multiple of four
348func (enc *Encoder) EncodeString(v string) (int, error) {349// Length of string.350n, err := enc.EncodeUint(uint32(len(v)))351if err != nil {352return n, err353}354
355n2, err := enc.EncodeFixedOpaque([]byte(v))356n += n2357return n, err358}
359
360// encodeFixedArray writes the XDR encoded representation of each element
361// in the passed array represented by the reflection value to the encapsulated
362// writer and returns the number of bytes written. The ignoreOpaque flag
363// controls whether or not uint8 (byte) elements should be encoded individually
364// or as a fixed sequence of opaque data.
365//
366// A MarshalError is returned if any issues are encountered while encoding
367// the array elements.
368//
369// Reference:
370// RFC Section 4.12 - Fixed-Length Array
371// Individually XDR encoded array elements
372func (enc *Encoder) encodeFixedArray(v reflect.Value, ignoreOpaque bool) (int, error) {373// Treat [#]byte (byte is alias for uint8) as opaque data unless ignored.374if !ignoreOpaque && v.Type().Elem().Kind() == reflect.Uint8 {375// Create a slice of the underlying array for better efficiency376// when possible. Can't create a slice of an unaddressable377// value.378if v.CanAddr() {379return enc.EncodeFixedOpaque(v.Slice(0, v.Len()).Bytes())380}381
382// When the underlying array isn't addressable fall back to383// copying the array into a new slice. This is rather ugly, but384// the inability to create a constant slice from an385// unaddressable array is a limitation of Go.386slice := make([]byte, v.Len(), v.Len())387reflect.Copy(reflect.ValueOf(slice), v)388return enc.EncodeFixedOpaque(slice)389}390
391// Encode each array element.392var n int393for i := 0; i < v.Len(); i++ {394n2, err := enc.encode(v.Index(i))395n += n2396if err != nil {397return n, err398}399}400
401return n, nil402}
403
404// encodeArray writes an XDR encoded integer representing the number of
405// elements in the passed slice represented by the reflection value followed by
406// the XDR encoded representation of each element in slice to the encapsulated
407// writer and returns the number of bytes written. The ignoreOpaque flag
408// controls whether or not uint8 (byte) elements should be encoded individually
409// or as a variable sequence of opaque data.
410//
411// A MarshalError is returned if any issues are encountered while encoding
412// the array elements.
413//
414// Reference:
415// RFC Section 4.13 - Variable-Length Array
416// Unsigned integer length followed by individually XDR encoded array elements
417func (enc *Encoder) encodeArray(v reflect.Value, ignoreOpaque bool) (int, error) {418numItems := uint32(v.Len())419n, err := enc.EncodeUint(numItems)420if err != nil {421return n, err422}423
424n2, err := enc.encodeFixedArray(v, ignoreOpaque)425n += n2426return n, err427}
428
429// encodeStruct writes an XDR encoded representation of each value in the
430// exported fields of the struct represented by the passed reflection value to
431// the encapsulated writer and returns the number of bytes written. Pointers
432// are automatically indirected through arbitrary depth to encode the actual
433// value pointed to.
434//
435// A MarshalError is returned if any issues are encountered while encoding
436// the elements.
437//
438// Reference:
439// RFC Section 4.14 - Structure
440// XDR encoded elements in the order of their declaration in the struct
441func (enc *Encoder) encodeStruct(v reflect.Value) (int, error) {442var n int443vt := v.Type()444for i := 0; i < v.NumField(); i++ {445// Skip unexported fields and indirect through pointers.446vtf := vt.Field(i)447if vtf.PkgPath != "" {448continue449}450vf := v.Field(i)451vf = enc.indirect(vf)452
453// Handle non-opaque data to []uint8 and [#]uint8 based on struct tag.454tag := vtf.Tag.Get("xdropaque")455if tag == "false" {456switch vf.Kind() {457case reflect.Slice:458n2, err := enc.encodeArray(vf, true)459n += n2460if err != nil {461return n, err462}463continue464
465case reflect.Array:466n2, err := enc.encodeFixedArray(vf, true)467n += n2468if err != nil {469return n, err470}471continue472}473}474
475// Encode each struct field.476n2, err := enc.encode(vf)477n += n2478if err != nil {479return n, err480}481}482
483return n, nil484}
485
486// RFC Section 4.15 - Discriminated Union
487// RFC Section 4.16 - Void
488// RFC Section 4.17 - Constant
489// RFC Section 4.18 - Typedef
490// RFC Section 4.19 - Optional data
491// RFC Sections 4.15 though 4.19 only apply to the data specification language
492// which is not implemented by this package. In the case of discriminated
493// unions, struct tags are used to perform a similar function.
494
495// encodeMap treats the map represented by the passed reflection value as a
496// variable-length array of 2-element structures whose fields are of the same
497// type as the map keys and elements and writes its XDR encoded representation
498// to the encapsulated writer. It returns the number of bytes written.
499//
500// A MarshalError is returned if any issues are encountered while encoding
501// the elements.
502func (enc *Encoder) encodeMap(v reflect.Value) (int, error) {503// Number of elements.504n, err := enc.EncodeUint(uint32(v.Len()))505if err != nil {506return n, err507}508
509// Encode each key and value according to their type.510for _, key := range v.MapKeys() {511n2, err := enc.encode(key)512n += n2513if err != nil {514return n, err515}516
517n2, err = enc.encode(v.MapIndex(key))518n += n2519if err != nil {520return n, err521}522}523
524return n, nil525}
526
527// encodeInterface examines the interface represented by the passed reflection
528// value to detect whether it is an interface that can be encoded if it is,
529// extracts the underlying value to pass back into the encode function for
530// encoding according to its type.
531//
532// A MarshalError is returned if any issues are encountered while encoding
533// the interface.
534func (enc *Encoder) encodeInterface(v reflect.Value) (int, error) {535if v.IsNil() || !v.CanInterface() {536msg := fmt.Sprintf("can't encode nil interface")537err := marshalError("encodeInterface", ErrNilInterface, msg,538nil, nil)539return 0, err540}541
542// Extract underlying value from the interface and indirect through pointers.543ve := reflect.ValueOf(v.Interface())544ve = enc.indirect(ve)545return enc.encode(ve)546}
547
548// encode is the main workhorse for marshalling via reflection. It uses
549// the passed reflection value to choose the XDR primitives to encode into
550// the encapsulated writer and returns the number of bytes written. It is a
551// recursive function, so cyclic data structures are not supported and will
552// result in an infinite loop.
553func (enc *Encoder) encode(v reflect.Value) (int, error) {554if !v.IsValid() {555msg := fmt.Sprintf("type '%s' is not valid", v.Kind().String())556err := marshalError("encode", ErrUnsupportedType, msg, nil, nil)557return 0, err558}559
560// Indirect through pointers to get at the concrete value.561ve := enc.indirect(v)562
563// Handle time.Time values by encoding them as an RFC3339 formatted564// string with nanosecond precision. Check the type string before565// doing a full blown conversion to interface and type assertion since566// checking a string is much quicker.567if ve.Type().String() == "time.Time" && ve.CanInterface() {568viface := ve.Interface()569if tv, ok := viface.(time.Time); ok {570return enc.EncodeString(tv.Format(time.RFC3339Nano))571}572}573
574// Handle native Go types.575switch ve.Kind() {576case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int:577return enc.EncodeInt(int32(ve.Int()))578
579case reflect.Int64:580return enc.EncodeHyper(ve.Int())581
582case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint:583return enc.EncodeUint(uint32(ve.Uint()))584
585case reflect.Uint64:586return enc.EncodeUhyper(ve.Uint())587
588case reflect.Bool:589return enc.EncodeBool(ve.Bool())590
591case reflect.Float32:592return enc.EncodeFloat(float32(ve.Float()))593
594case reflect.Float64:595return enc.EncodeDouble(ve.Float())596
597case reflect.String:598return enc.EncodeString(ve.String())599
600case reflect.Array:601return enc.encodeFixedArray(ve, false)602
603case reflect.Slice:604return enc.encodeArray(ve, false)605
606case reflect.Struct:607return enc.encodeStruct(ve)608
609case reflect.Map:610return enc.encodeMap(ve)611
612case reflect.Interface:613return enc.encodeInterface(ve)614}615
616// The only unhandled types left are unsupported. At the time of this617// writing the only remaining unsupported types that exist are618// reflect.Uintptr and reflect.UnsafePointer.619msg := fmt.Sprintf("unsupported Go type '%s'", ve.Kind().String())620err := marshalError("encode", ErrUnsupportedType, msg, nil, nil)621return 0, err622}
623
624// indirect dereferences pointers until it reaches a non-pointer. This allows
625// transparent encoding through arbitrary levels of indirection.
626func (enc *Encoder) indirect(v reflect.Value) reflect.Value {627rv := v628for rv.Kind() == reflect.Ptr {629rv = rv.Elem()630}631return rv632}
633
634// Encode operates identically to the Marshal function with the exception of
635// using the writer associated with the Encoder for the destination of the
636// XDR-encoded data instead of a user-supplied writer. See the Marshal
637// documentation for specifics.
638func (enc *Encoder) Encode(v interface{}) (int, error) {639if v == nil {640msg := "can't marshal nil interface"641err := marshalError("Marshal", ErrNilInterface, msg, nil, nil)642return 0, err643}644
645vv := reflect.ValueOf(v)646vve := vv647for vve.Kind() == reflect.Ptr {648if vve.IsNil() {649msg := fmt.Sprintf("can't marshal nil pointer '%v'",650vv.Type().String())651err := marshalError("Marshal", ErrBadArguments, msg,652nil, nil)653return 0, err654}655vve = vve.Elem()656}657
658return enc.encode(vve)659}
660
661// NewEncoder returns an object that can be used to manually choose fields to
662// XDR encode to the passed writer w. Typically, Marshal should be used instead
663// of manually creating an Encoder. An Encoder, along with several of its
664// methods to encode XDR primitives, is exposed so it is possible to perform
665// manual encoding of data without relying on reflection should it be necessary
666// in complex scenarios where automatic reflection-based encoding won't work.
667func NewEncoder(w io.Writer) *Encoder {668return &Encoder{w: w}669}
670