cstruct.go 3.9 KB

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