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