github.com/davecgh/go-xdr@v0.0.0-20161123171359-e6a2ba005892/xdr/encode.go (about) 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 17 package xdr 18 19 import ( 20 "fmt" 21 "math" 22 "reflect" 23 "time" 24 ) 25 26 var errMaxXdr = "data exceeds max xdr size limit" 27 28 /* 29 Marshal returns the XDR encoding of v. It traverses v recursively and 30 automatically indirects pointers through arbitrary depth to encode the actual 31 value pointed to. 32 33 Marshal uses reflection to determine the type of the concrete value contained 34 by v and performs a mapping of Go types to the underlying XDR types as follows: 35 36 Go Type -> XDR Type 37 -------------------- 38 int8, int16, int32, int -> XDR Integer 39 uint8, uint16, uint32, uint -> XDR Unsigned Integer 40 int64 -> XDR Hyper Integer 41 uint64 -> XDR Unsigned Hyper Integer 42 bool -> XDR Boolean 43 float32 -> XDR Floating-Point 44 float64 -> XDR Double-Precision Floating-Point 45 string -> XDR String 46 byte -> XDR Integer 47 []byte -> XDR Variable-Length Opaque Data 48 [#]byte -> XDR Fixed-Length Opaque Data 49 []<type> -> XDR Variable-Length Array 50 [#]<type> -> XDR Fixed-Length Array 51 struct -> XDR Structure 52 map -> XDR Variable-Length Array of two-element XDR Structures 53 time.Time -> XDR String encoded with RFC3339 nanosecond precision 54 55 Notes and Limitations: 56 57 * Automatic marshalling of variable and fixed-length arrays of uint8s 58 requires a special struct tag `xdropaque:"false"` since byte slices and 59 byte arrays are assumed to be opaque data and byte is a Go alias for uint8 60 thus indistinguishable under reflection 61 * Channel, complex, and function types cannot be encoded 62 * Interfaces without a concrete value cannot be encoded 63 * Cyclic data structures are not supported and will result in infinite loops 64 * Strings are marshalled with UTF-8 character encoding which differs from 65 the XDR specification of ASCII, however UTF-8 is backwards compatible with 66 ASCII so this should rarely cause issues 67 68 If any issues are encountered during the marshalling process, a MarshalError is 69 returned with a human readable description as well as an ErrorCode value for 70 further inspection from sophisticated callers. Some potential issues are 71 unsupported Go types, attempting to encode more opaque data than can be 72 represented by a single opaque XDR entry, and exceeding max slice limitations. 73 */ 74 func Marshal(v interface{}) (rv []byte, err error) { 75 if v == nil { 76 msg := "can't marshal nil interface" 77 err = marshalError("Marshal", ErrNilInterface, msg, nil) 78 return nil, err 79 } 80 81 vv := reflect.ValueOf(v) 82 vve := vv 83 for vve.Kind() == reflect.Ptr { 84 if vve.IsNil() { 85 msg := fmt.Sprintf("can't marshal nil pointer '%v'", 86 vv.Type().String()) 87 err = marshalError("Marshal", ErrBadArguments, msg, nil) 88 return nil, err 89 } 90 vve = vve.Elem() 91 } 92 93 enc := Encoder{} 94 err = enc.encode(vve) 95 return enc.data, err 96 } 97 98 // An Encoder contains information about the state of an encode operation 99 // from an interface value into an XDR-encoded byte slice. See NewEncoder. 100 type Encoder struct { 101 data []byte 102 off int 103 } 104 105 // EncodeInt appends the XDR encoded representation of the passed 32-bit signed 106 // integer to the Encoder's data. 107 // 108 // A MarshalError is returned if appending the data would overflow the 109 // internal data slice. 110 // 111 // Reference: 112 // RFC Section 4.1 - Integer 113 // 32-bit big-endian signed integer in range [-2147483648, 2147483647] 114 func (enc *Encoder) EncodeInt(v int32) (err error) { 115 b := make([]byte, 4, 4) 116 b[0] = byte(v >> 24) 117 b[1] = byte(v >> 16) 118 b[2] = byte(v >> 8) 119 b[3] = byte(v) 120 121 if len(enc.data) > maxInt-4 { 122 err = marshalError("EncodeInt", ErrOverflow, errMaxSlice, b) 123 return 124 } 125 126 enc.data = append(enc.data, b...) 127 return 128 } 129 130 // EncodeInt appends the XDR encoded representation of the passed 32-bit 131 // unsigned integer to the Encoder's data. 132 // 133 // A MarshalError is returned if appending the data would overflow the 134 // internal data slice. 135 // 136 // Reference: 137 // RFC Section 4.2 - Unsigned Integer 138 // 32-bit big-endian unsigned integer in range [0, 4294967295] 139 func (enc *Encoder) EncodeUint(v uint32) (err error) { 140 b := make([]byte, 4, 4) 141 b[0] = byte(v >> 24) 142 b[1] = byte(v >> 16) 143 b[2] = byte(v >> 8) 144 b[3] = byte(v) 145 146 if len(enc.data) > maxInt-4 { 147 err = marshalError("EncodeUint", ErrOverflow, errMaxSlice, b) 148 return 149 } 150 151 enc.data = append(enc.data, b...) 152 return 153 } 154 155 // EncodeEnum treats the passed 32-bit signed integer as an enumeration value 156 // and, if it is in the list of passed valid enumeration values, appends the XDR 157 // encoded representation of it to the Encoder's data. 158 // 159 // A MarshalError is returned if the enumeration value is not one of the provided 160 // valid values or appending the data would overflow the internal data slice. 161 // 162 // Reference: 163 // RFC Section 4.3 - Enumeration 164 // Represented as an XDR encoded signed integer 165 func (enc *Encoder) EncodeEnum(v int32, validEnums map[int32]bool) (err error) { 166 if !validEnums[v] { 167 err = marshalError("EncodeEnum", ErrBadEnumValue, "invalid enum", v) 168 return 169 } 170 return enc.EncodeInt(v) 171 } 172 173 // EncodeInt appends the XDR encoded representation of the passed boolean 174 // to the Encoder's data. 175 // 176 // A MarshalError is returned if appending the data would overflow the 177 // internal data slice. 178 // 179 // Reference: 180 // RFC Section 4.4 - Boolean 181 // Represented as an XDR encoded enumeration where 0 is false and 1 is true 182 func (enc *Encoder) EncodeBool(v bool) (err error) { 183 i := int32(0) 184 if v == true { 185 i = 1 186 } 187 return enc.EncodeInt(i) 188 } 189 190 // EncodeHyper appends the XDR encoded representation of the passed 64-bit 191 // signed integer to the Encoder's data. 192 // 193 // A MarshalError is returned if appending the data would overflow the 194 // internal data slice. 195 // 196 // Reference: 197 // RFC Section 4.5 - Hyper Integer 198 // 64-bit big-endian signed integer in range [-9223372036854775808, 9223372036854775807] 199 func (enc *Encoder) EncodeHyper(v int64) (err error) { 200 b := make([]byte, 8, 8) 201 b[0] = byte(v >> 56) 202 b[1] = byte(v >> 48) 203 b[2] = byte(v >> 40) 204 b[3] = byte(v >> 32) 205 b[4] = byte(v >> 24) 206 b[5] = byte(v >> 16) 207 b[6] = byte(v >> 8) 208 b[7] = byte(v) 209 210 if len(enc.data) > maxInt-8 { 211 err = marshalError("EncodeHyper", ErrOverflow, errMaxSlice, b) 212 return 213 } 214 215 enc.data = append(enc.data, b...) 216 return 217 } 218 219 // EncodeUhyper appends the XDR encoded representation of the passed 64-bit 220 // unsigned integer to the Encoder's data. 221 // 222 // A MarshalError is returned if appending the data would overflow the 223 // internal data slice. 224 // 225 // Reference: 226 // RFC Section 4.5 - Unsigned Hyper Integer 227 // 64-bit big-endian unsigned integer in range [0, 18446744073709551615] 228 func (enc *Encoder) EncodeUhyper(v uint64) (err error) { 229 b := make([]byte, 8, 8) 230 b[0] = byte(v >> 56) 231 b[1] = byte(v >> 48) 232 b[2] = byte(v >> 40) 233 b[3] = byte(v >> 32) 234 b[4] = byte(v >> 24) 235 b[5] = byte(v >> 16) 236 b[6] = byte(v >> 8) 237 b[7] = byte(v) 238 239 if len(enc.data) > maxInt-8 { 240 err = marshalError("EncodeUhyper", ErrOverflow, errMaxSlice, b) 241 return 242 } 243 244 enc.data = append(enc.data, b...) 245 return 246 } 247 248 // EncodeFloat appends the XDR encoded representation of the passed 32-bit 249 // (single-precision) floating point to the Encoder's data. 250 // 251 // A MarshalError is returned if appending the data would overflow the 252 // internal data slice. 253 // 254 // Reference: 255 // RFC Section 4.6 - Floating Point 256 // 32-bit single-precision IEEE 754 floating point 257 func (enc *Encoder) EncodeFloat(v float32) (err error) { 258 ui := math.Float32bits(v) 259 return enc.EncodeUint(ui) 260 } 261 262 // EncodeDouble appends the XDR encoded representation of the passed 64-bit 263 // (double-precision) floating point to the Encoder's data. 264 // 265 // A MarshalError is returned if appending the data would overflow the 266 // internal data slice. 267 // 268 // Reference: 269 // RFC Section 4.7 - Double-Precision Floating Point 270 // 64-bit double-precision IEEE 754 floating point 271 func (enc *Encoder) EncodeDouble(v float64) (err error) { 272 ui := math.Float64bits(v) 273 return enc.EncodeUhyper(ui) 274 } 275 276 // RFC Section 4.8 - Quadruple-Precision Floating Point 277 // 128-bit quadruple-precision floating point 278 // Not Implemented 279 280 // EncodeFixedOpaque treats the passed byte slice as opaque data of a fixed 281 // size and appends the XDR encoded representation of it to the Encoder's data. 282 // 283 // A MarshalError is returned if appending the data would overflow the 284 // internal data slice. 285 // 286 // Reference: 287 // RFC Section 4.9 - Fixed-Length Opaque Data 288 // Fixed-length uninterpreted data zero-padded to a multiple of four 289 func (enc *Encoder) EncodeFixedOpaque(v []byte) (err error) { 290 l := len(v) 291 pad := (4 - (l % 4)) % 4 292 size := l + pad 293 294 if len(enc.data) > maxInt-size { 295 err = marshalError("EncodeFixedOpaque", ErrOverflow, errMaxSlice, size) 296 return 297 } 298 299 enc.data = append(enc.data, v...) 300 if pad > 0 { 301 b := make([]byte, pad, pad) 302 for i := 0; i < pad; i++ { 303 b[i] = 0 304 } 305 enc.data = append(enc.data, b...) 306 } 307 return 308 } 309 310 // EncodeOpaque treats the passed byte slice as opaque data of a variable 311 // size and appends the XDR encoded representation of it to the Encoder's data. 312 // 313 // A MarshalError is returned if appending the data would overflow the 314 // internal data slice or the data in the byte slice is larger than XDR 315 // supports. 316 // 317 // Reference: 318 // RFC Section 4.10 - Variable-Length Opaque Data 319 // Unsigned integer length followed by fixed opaque data of that length 320 func (enc *Encoder) EncodeOpaque(v []byte) (err error) { 321 dataLen := len(v) 322 if uint(dataLen) > math.MaxUint32 { 323 err = marshalError("EncodeOpaque", ErrOverflow, errMaxXdr, dataLen) 324 return 325 } 326 err = enc.EncodeUint(uint32(dataLen)) 327 if err != nil { 328 return 329 } 330 err = enc.EncodeFixedOpaque(v) 331 return 332 } 333 334 // EncodeString appends the XDR encoded representation of the passed string 335 // to the Encoder's data. Character encoding is assumed to be UTF-8 and 336 // therefore ASCII compatible. If the underlying character encoding 337 // is not compatible with this assumption, the data can instead be written as 338 // variable-length opaque data (EncodeOpaque) and manually converted as needed. 339 // 340 // A MarshalError is returned if appending the data would overflow the 341 // internal data slice or the length of the string is larger than XDR supports. 342 // 343 // Reference: 344 // RFC Section 4.11 - String 345 // Unsigned integer length followed by bytes zero-padded to a multiple of four 346 func (enc *Encoder) EncodeString(v string) (err error) { 347 dataLen := len(v) 348 if uint(dataLen) > math.MaxUint32 { 349 err = marshalError("EncodeString", ErrOverflow, errMaxXdr, dataLen) 350 return 351 } 352 err = enc.EncodeUint(uint32(dataLen)) 353 if err != nil { 354 return 355 } 356 err = enc.EncodeFixedOpaque([]byte(v)) 357 return 358 } 359 360 // encodeFixedArray appends the XDR encoded representation of each element 361 // in the passed array represented by the reflection value to the Encoder's 362 // data. The ignoreOpaque flag controls whether or not uint8 (byte) elements 363 // should be encoded individually or as a fixed sequence of opaque data. 364 // 365 // A MarshalError is returned if any issues are encountered while encoding 366 // the array elements. 367 // 368 // Reference: 369 // RFC Section 4.12 - Fixed-Length Array 370 // Individually XDR encoded array elements 371 func (enc *Encoder) encodeFixedArray(v reflect.Value, ignoreOpaque bool) (err error) { 372 // Treat [#]byte (byte is alias for uint8) as opaque data unless ignored. 373 if !ignoreOpaque && v.Type().Elem().Kind() == reflect.Uint8 { 374 // Create a slice of the underlying array for better efficiency when 375 // possible. Can't create a slice of an unaddressable value. 376 if v.CanAddr() { 377 err = enc.EncodeFixedOpaque(v.Slice(0, v.Len()).Bytes()) 378 return 379 } 380 381 // When the underlying array isn't addressable fall back to copying the 382 // array into a new slice. This is rather ugly, but the inability to 383 // create a constant slice from an unaddressable array seems to be a 384 // limitation of Go. 385 slice := make([]byte, v.Len(), v.Len()) 386 reflect.Copy(reflect.ValueOf(slice), v) 387 err = enc.EncodeFixedOpaque(slice) 388 return 389 } 390 391 // Encode each array element. 392 for i := 0; i < v.Len(); i++ { 393 err = enc.encode(v.Index(i)) 394 if err != nil { 395 return err 396 } 397 } 398 return 399 } 400 401 // encodeArray appends an XDR encoded integer representing the number of 402 // elements in the passed slice represented by the reflection value followed by 403 // the XDR encoded representation of each element in slice to the Encoder's 404 // data. The ignoreOpaque flag controls whether or not uint8 (byte) elements 405 // should be encoded individually or as a variable sequence of opaque data. 406 // 407 // A MarshalError is returned if any issues are encountered while encoding 408 // the array elements. 409 // 410 // Reference: 411 // RFC Section 4.13 - Variable-Length Array 412 // Unsigned integer length followed by individually XDR encoded array elements 413 func (enc *Encoder) encodeArray(v reflect.Value, ignoreOpaque bool) (err error) { 414 numItems := uint32(v.Len()) 415 err = enc.encode(reflect.ValueOf(numItems)) 416 if err != nil { 417 return err 418 } 419 err = enc.encodeFixedArray(v, ignoreOpaque) 420 return 421 } 422 423 // encodeStruct appends an XDR encoded representation of each value in the 424 // exported fields of the struct represented by the passed reflection value to 425 // the Encoder's data. Pointers are automatically indirected through arbitrary 426 // depth to encode the actual value pointed to. 427 // 428 // A MarshalError is returned if any issues are encountered while encoding 429 // the elements. 430 // 431 // Reference: 432 // RFC Section 4.14 - Structure 433 // XDR encoded elements in the order of their declaration in the struct 434 func (enc *Encoder) encodeStruct(v reflect.Value) (err error) { 435 vt := v.Type() 436 for i := 0; i < v.NumField(); i++ { 437 // Skip unexported fields and indirect through pointers. 438 vtf := vt.Field(i) 439 if vtf.PkgPath != "" { 440 continue 441 } 442 vf := v.Field(i) 443 vf = enc.indirect(vf) 444 445 // Handle non-opaque data to []uint8 and [#]uint8 based on struct tag. 446 tag := vtf.Tag.Get("xdropaque") 447 if tag == "false" { 448 switch vf.Kind() { 449 case reflect.Slice: 450 err = enc.encodeArray(vf, true) 451 if err != nil { 452 return 453 } 454 continue 455 456 case reflect.Array: 457 err = enc.encodeFixedArray(vf, true) 458 if err != nil { 459 return 460 } 461 continue 462 } 463 } 464 465 // Encode each struct field. 466 err = enc.encode(vf) 467 if err != nil { 468 return err 469 } 470 } 471 return 472 } 473 474 // RFC Section 4.15 - Discriminated Union 475 // RFC Section 4.16 - Void 476 // RFC Section 4.17 - Constant 477 // RFC Section 4.18 - Typedef 478 // RFC Section 4.19 - Optional data 479 // RFC Sections 4.15 though 4.19 only apply to the data specification language 480 // which is not implemented by this package. In the case of discriminated 481 // unions, struct tags are used to perform a similar function. 482 483 // encodeMap treats the map represented by the passed reflection value as a 484 // variable-length array of 2-element structures whose fields are of the same 485 // type as the map keys and elements and appends its XDR encoded representation 486 // to the Encoder's data. 487 // 488 // A MarshalError is returned if any issues are encountered while encoding 489 // the elements. 490 func (enc *Encoder) encodeMap(v reflect.Value) (err error) { 491 dataLen := v.Len() 492 if uint(dataLen) > math.MaxUint32 { 493 err = marshalError("encodeMap", ErrOverflow, errMaxXdr, dataLen) 494 return 495 } 496 err = enc.EncodeUint(uint32(dataLen)) 497 if err != nil { 498 return 499 } 500 501 // Encode each key and value according to their type. 502 for _, key := range v.MapKeys() { 503 err = enc.encode(key) 504 if err != nil { 505 return 506 } 507 508 err = enc.encode(v.MapIndex(key)) 509 if err != nil { 510 return 511 } 512 } 513 return 514 } 515 516 // encodeInterface examines the interface represented by the passed reflection 517 // value to detect whether it is an interface that can be encoded if it is, 518 // extracts the underlying value to pass back into the encode function for 519 // encoding according to its type. 520 // 521 // A MarshalError is returned if any issues are encountered while encoding 522 // the interface. 523 func (enc *Encoder) encodeInterface(v reflect.Value) (err error) { 524 if v.IsNil() || !v.CanInterface() { 525 msg := fmt.Sprintf("can't encode nil interface") 526 err = marshalError("encodeInterface", ErrNilInterface, msg, nil) 527 return err 528 } 529 530 // Extract underlying value from the interface and indirect through pointers. 531 ve := reflect.ValueOf(v.Interface()) 532 ve = enc.indirect(ve) 533 return enc.encode(ve) 534 } 535 536 // encode is the main workhorse for marshalling via reflection. It uses 537 // the passed reflection value to choose the XDR primitives to encode into 538 // the data field of the Encoder. It is a recursive function, so cyclic data 539 // structures are not supported and will result in an infinite loop. 540 func (enc *Encoder) encode(v reflect.Value) (err error) { 541 if !v.IsValid() { 542 msg := fmt.Sprintf("type '%s' is not valid", v.Kind().String()) 543 err = marshalError("encode", ErrUnsupportedType, msg, nil) 544 return 545 } 546 547 // Indirect through pointers to get at the concrete value. 548 ve := enc.indirect(v) 549 550 // Handle time.Time values by encoding them as an RFC3339 formatted 551 // string with nanosecond precision. Check the type string before 552 // doing a full blown conversion to interface and type assertion since 553 // checking a string is much quicker. 554 if ve.Type().String() == "time.Time" && ve.CanInterface() { 555 viface := ve.Interface() 556 if tv, ok := viface.(time.Time); ok { 557 err = enc.EncodeString(tv.Format(time.RFC3339Nano)) 558 return 559 } 560 } 561 562 // Handle native Go types. 563 switch ve.Kind() { 564 case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int: 565 err = enc.EncodeInt(int32(ve.Int())) 566 567 case reflect.Int64: 568 err = enc.EncodeHyper(ve.Int()) 569 570 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint: 571 err = enc.EncodeUint(uint32(ve.Uint())) 572 573 case reflect.Uint64: 574 err = enc.EncodeUhyper(ve.Uint()) 575 576 case reflect.Bool: 577 err = enc.EncodeBool(ve.Bool()) 578 579 case reflect.Float32: 580 err = enc.EncodeFloat(float32(ve.Float())) 581 582 case reflect.Float64: 583 err = enc.EncodeDouble(ve.Float()) 584 585 case reflect.String: 586 err = enc.EncodeString(ve.String()) 587 588 case reflect.Array: 589 err = enc.encodeFixedArray(ve, false) 590 591 case reflect.Slice: 592 err = enc.encodeArray(ve, false) 593 594 case reflect.Struct: 595 err = enc.encodeStruct(ve) 596 597 case reflect.Map: 598 err = enc.encodeMap(ve) 599 600 case reflect.Interface: 601 err = enc.encodeInterface(ve) 602 603 // reflect.Uintptr, reflect.UnsafePointer 604 default: 605 msg := fmt.Sprintf("unsupported Go type '%s'", ve.Kind().String()) 606 err = marshalError("encode", ErrUnsupportedType, msg, nil) 607 } 608 609 return 610 } 611 612 // indirect dereferences pointers until it reaches a non-pointer. This allows 613 // transparent encoding through arbitrary levels of indirection. 614 func (enc *Encoder) indirect(v reflect.Value) (rv reflect.Value) { 615 rv = v 616 for rv.Kind() == reflect.Ptr { 617 rv = rv.Elem() 618 } 619 return 620 } 621 622 // Data returns the XDR encoded data stored in the Encoder. 623 func (enc *Encoder) Data() (rv []byte) { 624 return enc.data[:] 625 } 626 627 // Reset clears the internal XDR encoded data so the Encoder may be reused. 628 func (enc *Encoder) Reset() { 629 enc.data = enc.data[0:0] 630 } 631 632 // NewEncoder returns an object that can be used to manually build an XDR 633 // encoded byte slice. Typically, Marshal should be used instead of manually 634 // creating an Encoder. An Encoder, along with several of its methods to encode 635 // XDR primitives, is exposed so it is possible to perform manual encoding of 636 // data without relying on reflection should it be necessary in complex 637 // scenarios where automatic reflection-based decoding won't work. 638 func NewEncoder() *Encoder { 639 return &Encoder{} 640 }