cstruct.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // Copyright (c) Tailscale Inc & contributors
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. // Package cstruct provides a helper for decoding binary data that is in the
  4. // form of a padded C structure.
  5. package cstruct
  6. import (
  7. "encoding/binary"
  8. "errors"
  9. "io"
  10. )
  11. // Size of a pointer-typed value, in bits
  12. const pointerSize = 32 << (^uintptr(0) >> 63)
  13. // We assume that non-64-bit platforms are 32-bit; we don't expect Go to run on
  14. // a 16- or 8-bit architecture any time soon.
  15. const is64Bit = pointerSize == 64
  16. // Decoder reads and decodes padded fields from a slice of bytes. All fields
  17. // are decoded with native endianness.
  18. //
  19. // Methods of a Decoder do not return errors, but rather store any error within
  20. // the Decoder. The first error can be obtained via the Err method; after the
  21. // first error, methods will return the zero value for their type.
  22. type Decoder struct {
  23. b []byte
  24. off int
  25. err error
  26. dbuf [8]byte // for decoding
  27. }
  28. // NewDecoder creates a Decoder from a byte slice.
  29. func NewDecoder(b []byte) *Decoder {
  30. return &Decoder{b: b}
  31. }
  32. var errUnsupportedSize = errors.New("unsupported size")
  33. func padBytes(offset, size int) int {
  34. if offset == 0 || size == 1 {
  35. return 0
  36. }
  37. remainder := offset % size
  38. return size - remainder
  39. }
  40. func (d *Decoder) getField(b []byte) error {
  41. size := len(b)
  42. // We only support fields that are multiples of 2 (or 1-sized)
  43. if size != 1 && size&1 == 1 {
  44. return errUnsupportedSize
  45. }
  46. // Fields are aligned to their size
  47. padBytes := padBytes(d.off, size)
  48. if d.off+size+padBytes > len(d.b) {
  49. return io.EOF
  50. }
  51. d.off += padBytes
  52. copy(b, d.b[d.off:d.off+size])
  53. d.off += size
  54. return nil
  55. }
  56. // Err returns the first error that was encountered by this Decoder.
  57. func (d *Decoder) Err() error {
  58. return d.err
  59. }
  60. // Offset returns the current read offset for data in the buffer.
  61. func (d *Decoder) Offset() int {
  62. return d.off
  63. }
  64. // Byte returns a single byte from the buffer.
  65. func (d *Decoder) Byte() byte {
  66. if d.err != nil {
  67. return 0
  68. }
  69. if err := d.getField(d.dbuf[0:1]); err != nil {
  70. d.err = err
  71. return 0
  72. }
  73. return d.dbuf[0]
  74. }
  75. // Byte returns a number of bytes from the buffer based on the size of the
  76. // input slice. No padding is applied.
  77. //
  78. // If an error is encountered or this Decoder has previously encountered an
  79. // error, no changes are made to the provided buffer.
  80. func (d *Decoder) Bytes(b []byte) {
  81. if d.err != nil {
  82. return
  83. }
  84. // No padding for byte slices
  85. size := len(b)
  86. if d.off+size >= len(d.b) {
  87. d.err = io.EOF
  88. return
  89. }
  90. copy(b, d.b[d.off:d.off+size])
  91. d.off += size
  92. }
  93. // Uint16 returns a uint16 decoded from the buffer.
  94. func (d *Decoder) Uint16() uint16 {
  95. if d.err != nil {
  96. return 0
  97. }
  98. if err := d.getField(d.dbuf[0:2]); err != nil {
  99. d.err = err
  100. return 0
  101. }
  102. return binary.NativeEndian.Uint16(d.dbuf[0:2])
  103. }
  104. // Uint32 returns a uint32 decoded from the buffer.
  105. func (d *Decoder) Uint32() uint32 {
  106. if d.err != nil {
  107. return 0
  108. }
  109. if err := d.getField(d.dbuf[0:4]); err != nil {
  110. d.err = err
  111. return 0
  112. }
  113. return binary.NativeEndian.Uint32(d.dbuf[0:4])
  114. }
  115. // Uint64 returns a uint64 decoded from the buffer.
  116. func (d *Decoder) Uint64() uint64 {
  117. if d.err != nil {
  118. return 0
  119. }
  120. if err := d.getField(d.dbuf[0:8]); err != nil {
  121. d.err = err
  122. return 0
  123. }
  124. return binary.NativeEndian.Uint64(d.dbuf[0:8])
  125. }
  126. // Uintptr returns a uintptr decoded from the buffer.
  127. func (d *Decoder) Uintptr() uintptr {
  128. if d.err != nil {
  129. return 0
  130. }
  131. if is64Bit {
  132. return uintptr(d.Uint64())
  133. } else {
  134. return uintptr(d.Uint32())
  135. }
  136. }
  137. // Int16 returns a int16 decoded from the buffer.
  138. func (d *Decoder) Int16() int16 {
  139. return int16(d.Uint16())
  140. }
  141. // Int32 returns a int32 decoded from the buffer.
  142. func (d *Decoder) Int32() int32 {
  143. return int32(d.Uint32())
  144. }
  145. // Int64 returns a int64 decoded from the buffer.
  146. func (d *Decoder) Int64() int64 {
  147. return int64(d.Uint64())
  148. }