// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package binary implements simple translation between numbers and byte // sequences and encoding and decoding of varints. // // Numbers are translated by reading and writing fixed-size values. // A fixed-size value is either a fixed-size arithmetic // type (bool, int8, uint8, int16, float32, complex64, ...) // or an array or struct containing only fixed-size values. // // The varint functions encode and decode single integer values using // a variable-length encoding; smaller values require fewer bytes. // For a specification, see // https://developers.google.com/protocol-buffers/docs/encoding. // // This package favors simplicity over efficiency. Clients that require // high-performance serialization, especially for large data structures, // should look at more advanced solutions such as the [encoding/gob] // package or [google.golang.org/protobuf] for protocol buffers.
package binary import ( ) var errBufferTooSmall = errors.New("buffer too small") // A ByteOrder specifies how to convert byte slices into // 16-, 32-, or 64-bit unsigned integers. // // It is implemented by [LittleEndian], [BigEndian], and [NativeEndian]. type ByteOrder interface { Uint16([]byte) uint16 Uint32([]byte) uint32 Uint64([]byte) uint64 PutUint16([]byte, uint16) PutUint32([]byte, uint32) PutUint64([]byte, uint64) String() string } // AppendByteOrder specifies how to append 16-, 32-, or 64-bit unsigned integers // into a byte slice. // // It is implemented by [LittleEndian], [BigEndian], and [NativeEndian]. type AppendByteOrder interface { AppendUint16([]byte, uint16) []byte AppendUint32([]byte, uint32) []byte AppendUint64([]byte, uint64) []byte String() string } // LittleEndian is the little-endian implementation of [ByteOrder] and [AppendByteOrder]. var LittleEndian littleEndian // BigEndian is the big-endian implementation of [ByteOrder] and [AppendByteOrder]. var BigEndian bigEndian type littleEndian struct{} func (littleEndian) ( []byte) uint16 { _ = [1] // bounds check hint to compiler; see golang.org/issue/14808 return uint16([0]) | uint16([1])<<8 } func (littleEndian) ( []byte, uint16) { _ = [1] // early bounds check to guarantee safety of writes below [0] = byte() [1] = byte( >> 8) } func (littleEndian) ( []byte, uint16) []byte { return append(, byte(), byte(>>8), ) } func (littleEndian) ( []byte) uint32 { _ = [3] // bounds check hint to compiler; see golang.org/issue/14808 return uint32([0]) | uint32([1])<<8 | uint32([2])<<16 | uint32([3])<<24 } func (littleEndian) ( []byte, uint32) { _ = [3] // early bounds check to guarantee safety of writes below [0] = byte() [1] = byte( >> 8) [2] = byte( >> 16) [3] = byte( >> 24) } func (littleEndian) ( []byte, uint32) []byte { return append(, byte(), byte(>>8), byte(>>16), byte(>>24), ) } func (littleEndian) ( []byte) uint64 { _ = [7] // bounds check hint to compiler; see golang.org/issue/14808 return uint64([0]) | uint64([1])<<8 | uint64([2])<<16 | uint64([3])<<24 | uint64([4])<<32 | uint64([5])<<40 | uint64([6])<<48 | uint64([7])<<56 } func (littleEndian) ( []byte, uint64) { _ = [7] // early bounds check to guarantee safety of writes below [0] = byte() [1] = byte( >> 8) [2] = byte( >> 16) [3] = byte( >> 24) [4] = byte( >> 32) [5] = byte( >> 40) [6] = byte( >> 48) [7] = byte( >> 56) } func (littleEndian) ( []byte, uint64) []byte { return append(, byte(), byte(>>8), byte(>>16), byte(>>24), byte(>>32), byte(>>40), byte(>>48), byte(>>56), ) } func (littleEndian) () string { return "LittleEndian" } func (littleEndian) () string { return "binary.LittleEndian" } type bigEndian struct{} func (bigEndian) ( []byte) uint16 { _ = [1] // bounds check hint to compiler; see golang.org/issue/14808 return uint16([1]) | uint16([0])<<8 } func (bigEndian) ( []byte, uint16) { _ = [1] // early bounds check to guarantee safety of writes below [0] = byte( >> 8) [1] = byte() } func (bigEndian) ( []byte, uint16) []byte { return append(, byte(>>8), byte(), ) } func (bigEndian) ( []byte) uint32 { _ = [3] // bounds check hint to compiler; see golang.org/issue/14808 return uint32([3]) | uint32([2])<<8 | uint32([1])<<16 | uint32([0])<<24 } func (bigEndian) ( []byte, uint32) { _ = [3] // early bounds check to guarantee safety of writes below [0] = byte( >> 24) [1] = byte( >> 16) [2] = byte( >> 8) [3] = byte() } func (bigEndian) ( []byte, uint32) []byte { return append(, byte(>>24), byte(>>16), byte(>>8), byte(), ) } func (bigEndian) ( []byte) uint64 { _ = [7] // bounds check hint to compiler; see golang.org/issue/14808 return uint64([7]) | uint64([6])<<8 | uint64([5])<<16 | uint64([4])<<24 | uint64([3])<<32 | uint64([2])<<40 | uint64([1])<<48 | uint64([0])<<56 } func (bigEndian) ( []byte, uint64) { _ = [7] // early bounds check to guarantee safety of writes below [0] = byte( >> 56) [1] = byte( >> 48) [2] = byte( >> 40) [3] = byte( >> 32) [4] = byte( >> 24) [5] = byte( >> 16) [6] = byte( >> 8) [7] = byte() } func (bigEndian) ( []byte, uint64) []byte { return append(, byte(>>56), byte(>>48), byte(>>40), byte(>>32), byte(>>24), byte(>>16), byte(>>8), byte(), ) } func (bigEndian) () string { return "BigEndian" } func (bigEndian) () string { return "binary.BigEndian" } func (nativeEndian) () string { return "NativeEndian" } func (nativeEndian) () string { return "binary.NativeEndian" } // 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 [io.EOF] only if no bytes were read. // If an [io.EOF] happens after reading some but not all the bytes, // Read returns [io.ErrUnexpectedEOF]. func ( io.Reader, ByteOrder, any) error { // Fast path for basic types and slices. if , := intDataSize(); != 0 { := make([]byte, ) if , := io.ReadFull(, ); != nil { return } if decodeFast(, , ) { return nil } } // Fallback to reflect-based decoding. := reflect.ValueOf() := -1 switch .Kind() { case reflect.Pointer: = .Elem() = dataSize() case reflect.Slice: = dataSize() } if < 0 { return errors.New("binary.Read: invalid type " + reflect.TypeOf().String()) } := &decoder{order: , buf: make([]byte, )} if , := io.ReadFull(, .buf); != nil { return } .value() return nil } // Decode decodes binary data from buf into data according to // the given byte order. // It returns an error if buf is too small, otherwise the number of // bytes consumed from buf. func ( []byte, ByteOrder, any) (int, error) { if , := intDataSize(); != 0 { if len() < { return 0, errBufferTooSmall } if decodeFast(, , ) { return , nil } } // Fallback to reflect-based decoding. := reflect.ValueOf() := -1 switch .Kind() { case reflect.Pointer: = .Elem() = dataSize() case reflect.Slice: = dataSize() } if < 0 { return 0, errors.New("binary.Decode: invalid type " + reflect.TypeOf().String()) } if len() < { return 0, errBufferTooSmall } := &decoder{order: , buf: [:]} .value() return , nil } func decodeFast( []byte, ByteOrder, any) bool { switch data := .(type) { case *bool: * = [0] != 0 case *int8: * = int8([0]) case *uint8: * = [0] case *int16: * = int16(.Uint16()) case *uint16: * = .Uint16() case *int32: * = int32(.Uint32()) case *uint32: * = .Uint32() case *int64: * = int64(.Uint64()) case *uint64: * = .Uint64() case *float32: * = math.Float32frombits(.Uint32()) case *float64: * = math.Float64frombits(.Uint64()) case []bool: for , := range { // Easier to loop over the input for 8-bit values. [] = != 0 } case []int8: for , := range { [] = int8() } case []uint8: copy(, ) case []int16: for := range { [] = int16(.Uint16([2*:])) } case []uint16: for := range { [] = .Uint16([2*:]) } case []int32: for := range { [] = int32(.Uint32([4*:])) } case []uint32: for := range { [] = .Uint32([4*:]) } case []int64: for := range { [] = int64(.Uint64([8*:])) } case []uint64: for := range { [] = .Uint64([8*:]) } case []float32: for := range { [] = math.Float32frombits(.Uint32([4*:])) } case []float64: for := range { [] = math.Float64frombits(.Uint64([8*:])) } default: return false } return true } // Write writes the binary representation of data into w. // Data must be a fixed-size value or a slice of fixed-size // values, or a pointer to such data. // Boolean values encode as one byte: 1 for true, and 0 for false. // Bytes written to w are encoded using the specified byte order // and read from successive fields of the data. // When writing structs, zero values are written for fields // with blank (_) field names. func ( io.Writer, ByteOrder, any) error { // Fast path for basic types and slices. if , := intDataSize(); != 0 { if == nil { = make([]byte, ) encodeFast(, , ) } , := .Write() return } // Fallback to reflect-based encoding. := reflect.Indirect(reflect.ValueOf()) := dataSize() if < 0 { return errors.New("binary.Write: some values are not fixed-sized in type " + reflect.TypeOf().String()) } := make([]byte, ) := &encoder{order: , buf: } .value() , := .Write() return } // Encode encodes the binary representation of data into buf according to // the given byte order. // It returns an error if buf is too small, otherwise the number of // bytes written into buf. func ( []byte, ByteOrder, any) (int, error) { // Fast path for basic types and slices. if , := intDataSize(); != 0 { if len() < { return 0, errBufferTooSmall } encodeFast(, , ) return , nil } // Fallback to reflect-based encoding. := reflect.Indirect(reflect.ValueOf()) := dataSize() if < 0 { return 0, errors.New("binary.Encode: some values are not fixed-sized in type " + reflect.TypeOf().String()) } if len() < { return 0, errBufferTooSmall } := &encoder{order: , buf: } .value() return , nil } // Append appends the binary representation of data to buf. // buf may be nil, in which case a new buffer will be allocated. // See [Write] on which data are acceptable. // It returns the (possibily extended) buffer containing data or an error. func ( []byte, ByteOrder, any) ([]byte, error) { // Fast path for basic types and slices. if , := intDataSize(); != 0 { , := ensure(, ) encodeFast(, , ) return , nil } // Fallback to reflect-based encoding. := reflect.Indirect(reflect.ValueOf()) := dataSize() if < 0 { return nil, errors.New("binary.Append: some values are not fixed-sized in type " + reflect.TypeOf().String()) } , := ensure(, ) := &encoder{order: , buf: } .value() return , nil } func encodeFast( []byte, ByteOrder, any) { switch v := .(type) { case *bool: if * { [0] = 1 } else { [0] = 0 } case bool: if { [0] = 1 } else { [0] = 0 } case []bool: for , := range { if { [] = 1 } else { [] = 0 } } case *int8: [0] = byte(*) case int8: [0] = byte() case []int8: for , := range { [] = byte() } case *uint8: [0] = * case uint8: [0] = case []uint8: copy(, ) case *int16: .PutUint16(, uint16(*)) case int16: .PutUint16(, uint16()) case []int16: for , := range { .PutUint16([2*:], uint16()) } case *uint16: .PutUint16(, *) case uint16: .PutUint16(, ) case []uint16: for , := range { .PutUint16([2*:], ) } case *int32: .PutUint32(, uint32(*)) case int32: .PutUint32(, uint32()) case []int32: for , := range { .PutUint32([4*:], uint32()) } case *uint32: .PutUint32(, *) case uint32: .PutUint32(, ) case []uint32: for , := range { .PutUint32([4*:], ) } case *int64: .PutUint64(, uint64(*)) case int64: .PutUint64(, uint64()) case []int64: for , := range { .PutUint64([8*:], uint64()) } case *uint64: .PutUint64(, *) case uint64: .PutUint64(, ) case []uint64: for , := range { .PutUint64([8*:], ) } case *float32: .PutUint32(, math.Float32bits(*)) case float32: .PutUint32(, math.Float32bits()) case []float32: for , := range { .PutUint32([4*:], math.Float32bits()) } case *float64: .PutUint64(, math.Float64bits(*)) case float64: .PutUint64(, math.Float64bits()) case []float64: for , := range { .PutUint64([8*:], math.Float64bits()) } } } // Size returns how many bytes [Write] would generate to encode the value v, which // must be a fixed-size value or a slice of fixed-size values, or a pointer to such data. // If v is neither of these, Size returns -1. func ( any) int { switch data := .(type) { case bool, int8, uint8: return 1 case *bool: if == nil { return -1 } return 1 case *int8: if == nil { return -1 } return 1 case *uint8: if == nil { return -1 } return 1 case []bool: return len() case []int8: return len() case []uint8: return len() case int16, uint16: return 2 case *int16: if == nil { return -1 } return 2 case *uint16: if == nil { return -1 } return 2 case []int16: return 2 * len() case []uint16: return 2 * len() case int32, uint32: return 4 case *int32: if == nil { return -1 } return 4 case *uint32: if == nil { return -1 } return 4 case []int32: return 4 * len() case []uint32: return 4 * len() case int64, uint64: return 8 case *int64: if == nil { return -1 } return 8 case *uint64: if == nil { return -1 } return 8 case []int64: return 8 * len() case []uint64: return 8 * len() case float32: return 4 case *float32: if == nil { return -1 } return 4 case float64: return 8 case *float64: if == nil { return -1 } return 8 case []float32: return 4 * len() case []float64: return 8 * len() } return dataSize(reflect.Indirect(reflect.ValueOf())) } var structSize sync.Map // map[reflect.Type]int // dataSize returns the number of bytes the actual data represented by v occupies in memory. // For compound structures, it sums the sizes of the elements. Thus, for instance, for a slice // it returns the length of the slice times the element size and does not count the memory // occupied by the header. If the type of v is not acceptable, dataSize returns -1. func dataSize( reflect.Value) int { switch .Kind() { case reflect.Slice, reflect.Array: := .Type().Elem() if , := structSize.Load(); { return .(int) * .Len() } := sizeof() if >= 0 { if .Kind() == reflect.Struct { structSize.Store(, ) } return * .Len() } case reflect.Struct: := .Type() if , := structSize.Load(); { return .(int) } := sizeof() structSize.Store(, ) return default: if .IsValid() { return sizeof(.Type()) } } return -1 } // sizeof returns the size >= 0 of variables for the given type or -1 if the type is not acceptable. func sizeof( reflect.Type) int { switch .Kind() { case reflect.Array: if := (.Elem()); >= 0 { return * .Len() } case reflect.Struct: := 0 for , := 0, .NumField(); < ; ++ { := (.Field().Type) if < 0 { return -1 } += } return case reflect.Bool, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: return int(.Size()) } return -1 } type coder struct { order ByteOrder buf []byte offset int } type decoder coder type encoder coder func ( *decoder) () bool { := .buf[.offset] .offset++ return != 0 } func ( *encoder) ( bool) { if { .buf[.offset] = 1 } else { .buf[.offset] = 0 } .offset++ } func ( *decoder) () uint8 { := .buf[.offset] .offset++ return } func ( *encoder) ( uint8) { .buf[.offset] = .offset++ } func ( *decoder) () uint16 { := .order.Uint16(.buf[.offset : .offset+2]) .offset += 2 return } func ( *encoder) ( uint16) { .order.PutUint16(.buf[.offset:.offset+2], ) .offset += 2 } func ( *decoder) () uint32 { := .order.Uint32(.buf[.offset : .offset+4]) .offset += 4 return } func ( *encoder) ( uint32) { .order.PutUint32(.buf[.offset:.offset+4], ) .offset += 4 } func ( *decoder) () uint64 { := .order.Uint64(.buf[.offset : .offset+8]) .offset += 8 return } func ( *encoder) ( uint64) { .order.PutUint64(.buf[.offset:.offset+8], ) .offset += 8 } func ( *decoder) () int8 { return int8(.uint8()) } func ( *encoder) ( int8) { .uint8(uint8()) } func ( *decoder) () int16 { return int16(.uint16()) } func ( *encoder) ( int16) { .uint16(uint16()) } func ( *decoder) () int32 { return int32(.uint32()) } func ( *encoder) ( int32) { .uint32(uint32()) } func ( *decoder) () int64 { return int64(.uint64()) } func ( *encoder) ( int64) { .uint64(uint64()) } func ( *decoder) ( reflect.Value) { switch .Kind() { case reflect.Array: := .Len() for := 0; < ; ++ { .(.Index()) } case reflect.Struct: := .Type() := .NumField() for := 0; < ; ++ { // Note: Calling v.CanSet() below is an optimization. // It would be sufficient to check the field name, // but creating the StructField info for each field is // costly (run "go test -bench=ReadStruct" and compare // results when making changes to this code). if := .Field(); .CanSet() || .Field().Name != "_" { .() } else { .skip() } } case reflect.Slice: := .Len() for := 0; < ; ++ { .(.Index()) } case reflect.Bool: .SetBool(.bool()) case reflect.Int8: .SetInt(int64(.int8())) case reflect.Int16: .SetInt(int64(.int16())) case reflect.Int32: .SetInt(int64(.int32())) case reflect.Int64: .SetInt(.int64()) case reflect.Uint8: .SetUint(uint64(.uint8())) case reflect.Uint16: .SetUint(uint64(.uint16())) case reflect.Uint32: .SetUint(uint64(.uint32())) case reflect.Uint64: .SetUint(.uint64()) case reflect.Float32: .SetFloat(float64(math.Float32frombits(.uint32()))) case reflect.Float64: .SetFloat(math.Float64frombits(.uint64())) case reflect.Complex64: .SetComplex(complex( float64(math.Float32frombits(.uint32())), float64(math.Float32frombits(.uint32())), )) case reflect.Complex128: .SetComplex(complex( math.Float64frombits(.uint64()), math.Float64frombits(.uint64()), )) } } func ( *encoder) ( reflect.Value) { switch .Kind() { case reflect.Array: := .Len() for := 0; < ; ++ { .(.Index()) } case reflect.Struct: := .Type() := .NumField() for := 0; < ; ++ { // see comment for corresponding code in decoder.value() if := .Field(); .CanSet() || .Field().Name != "_" { .() } else { .skip() } } case reflect.Slice: := .Len() for := 0; < ; ++ { .(.Index()) } case reflect.Bool: .bool(.Bool()) case reflect.Int8: .int8(int8(.Int())) case reflect.Int16: .int16(int16(.Int())) case reflect.Int32: .int32(int32(.Int())) case reflect.Int64: .int64(.Int()) case reflect.Uint8: .uint8(uint8(.Uint())) case reflect.Uint16: .uint16(uint16(.Uint())) case reflect.Uint32: .uint32(uint32(.Uint())) case reflect.Uint64: .uint64(.Uint()) case reflect.Float32: .uint32(math.Float32bits(float32(.Float()))) case reflect.Float64: .uint64(math.Float64bits(.Float())) case reflect.Complex64: := .Complex() .uint32(math.Float32bits(float32(real()))) .uint32(math.Float32bits(float32(imag()))) case reflect.Complex128: := .Complex() .uint64(math.Float64bits(real())) .uint64(math.Float64bits(imag())) } } func ( *decoder) ( reflect.Value) { .offset += dataSize() } func ( *encoder) ( reflect.Value) { := dataSize() clear(.buf[.offset : .offset+]) .offset += } // intDataSize returns the size of the data required to represent the data when encoded, // and optionally a byte slice containing the encoded data if no conversion is necessary. // It returns zero, nil if the type cannot be implemented by the fast path in Read or Write. func intDataSize( any) (int, []byte) { switch data := .(type) { case bool, int8, uint8, *bool, *int8, *uint8: return 1, nil case []bool: return len(), nil case []int8: return len(), nil case []uint8: return len(), case int16, uint16, *int16, *uint16: return 2, nil case []int16: return 2 * len(), nil case []uint16: return 2 * len(), nil case int32, uint32, *int32, *uint32: return 4, nil case []int32: return 4 * len(), nil case []uint32: return 4 * len(), nil case int64, uint64, *int64, *uint64: return 8, nil case []int64: return 8 * len(), nil case []uint64: return 8 * len(), nil case float32, *float32: return 4, nil case float64, *float64: return 8, nil case []float32: return 4 * len(), nil case []float64: return 8 * len(), nil } return 0, nil } // ensure grows buf to length len(buf) + n and returns the grown buffer // and a slice starting at the original length of buf (that is, buf2[len(buf):]). func ensure( []byte, int) (, []byte) { := len() = slices.Grow(, )[:+] return , [:] }