Created
January 30, 2022 16:46
-
-
Save carterpeel/a6bdb3e7294753e3ac8bcc99f6d2e723 to your computer and use it in GitHub Desktop.
binary.Read()
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Read reads structured binary data from r into data. | |
// Data must be a pointer to a fixed-size value or a slice | |
// of fixed-size values. | |
// Bytes read from r are decoded using the specified byte order | |
// and written to successive fields of the data. | |
// When decoding boolean values, a zero byte is decoded as false, and | |
// any other non-zero byte is decoded as true. | |
// When reading into structs, the field data for fields with | |
// blank (_) field names is skipped; i.e., blank field names | |
// may be used for padding. | |
// When reading into a struct, all non-blank fields must be exported | |
// or Read may panic. | |
// | |
// The error is EOF only if no bytes were read. | |
// If an EOF happens after reading some but not all the bytes, | |
// Read returns ErrUnexpectedEOF. | |
func Read(r io.Reader, order ByteOrder, data interface{}) error { | |
// Fast path for basic types and slices. | |
if n := intDataSize(data); n != 0 { | |
bs := make([]byte, n) | |
if _, err := io.ReadFull(r, bs); err != nil { | |
return err | |
} | |
switch data := data.(type) { | |
case *bool: | |
*data = bs[0] != 0 | |
case *int8: | |
*data = int8(bs[0]) | |
case *uint8: | |
*data = bs[0] | |
case *int16: | |
*data = int16(order.Uint16(bs)) | |
case *uint16: | |
*data = order.Uint16(bs) | |
case *int32: | |
*data = int32(order.Uint32(bs)) | |
case *uint32: | |
*data = order.Uint32(bs) | |
case *int64: | |
*data = int64(order.Uint64(bs)) | |
case *uint64: | |
*data = order.Uint64(bs) | |
case *float32: | |
*data = math.Float32frombits(order.Uint32(bs)) | |
case *float64: | |
*data = math.Float64frombits(order.Uint64(bs)) | |
case []bool: | |
for i, x := range bs { // Easier to loop over the input for 8-bit values. | |
data[i] = x != 0 | |
} | |
case []int8: | |
for i, x := range bs { | |
data[i] = int8(x) | |
} | |
case []uint8: | |
copy(data, bs) | |
case []int16: | |
for i := range data { | |
data[i] = int16(order.Uint16(bs[2*i:])) | |
} | |
case []uint16: | |
for i := range data { | |
data[i] = order.Uint16(bs[2*i:]) | |
} | |
case []int32: | |
for i := range data { | |
data[i] = int32(order.Uint32(bs[4*i:])) | |
} | |
case []uint32: | |
for i := range data { | |
data[i] = order.Uint32(bs[4*i:]) | |
} | |
case []int64: | |
for i := range data { | |
data[i] = int64(order.Uint64(bs[8*i:])) | |
} | |
case []uint64: | |
for i := range data { | |
data[i] = order.Uint64(bs[8*i:]) | |
} | |
case []float32: | |
for i := range data { | |
data[i] = math.Float32frombits(order.Uint32(bs[4*i:])) | |
} | |
case []float64: | |
for i := range data { | |
data[i] = math.Float64frombits(order.Uint64(bs[8*i:])) | |
} | |
default: | |
n = 0 // fast path doesn't apply | |
} | |
if n != 0 { | |
return nil | |
} | |
} | |
// Fallback to reflect-based decoding. | |
v := reflect.ValueOf(data) | |
size := -1 | |
switch v.Kind() { | |
case reflect.Ptr: | |
v = v.Elem() | |
size = dataSize(v) | |
case reflect.Slice: | |
size = dataSize(v) | |
} | |
if size < 0 { | |
return errors.New("binary.Read: invalid type " + reflect.TypeOf(data).String()) | |
} | |
d := &decoder{order: order, buf: make([]byte, size)} | |
if _, err := io.ReadFull(r, d.buf); err != nil { | |
return err | |
} | |
d.value(v) | |
return nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment