diff options
author | Googler <noreply@google.com> | 2018-04-27 10:37:02 -0700 |
---|---|---|
committer | Adin Scannell <ascannell@google.com> | 2018-04-28 01:44:26 -0400 |
commit | d02b74a5dcfed4bfc8f2f8e545bca4d2afabb296 (patch) | |
tree | 54f95eef73aee6bacbfc736fffc631be2605ed53 /pkg/binary/binary.go | |
parent | f70210e742919f40aa2f0934a22f1c9ba6dada62 (diff) |
Check in gVisor.
PiperOrigin-RevId: 194583126
Change-Id: Ica1d8821a90f74e7e745962d71801c598c652463
Diffstat (limited to 'pkg/binary/binary.go')
-rw-r--r-- | pkg/binary/binary.go | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/pkg/binary/binary.go b/pkg/binary/binary.go new file mode 100644 index 000000000..df421bdb6 --- /dev/null +++ b/pkg/binary/binary.go @@ -0,0 +1,263 @@ +// Copyright 2018 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package binary translates between select fixed-sized types and a binary +// representation. +package binary + +import ( + "encoding/binary" + "fmt" + "io" + "reflect" +) + +// LittleEndian is the same as encoding/binary.LittleEndian. +// +// It is included here as a convenience. +var LittleEndian = binary.LittleEndian + +// BigEndian is the same as encoding/binary.BigEndian. +// +// It is included here as a convenience. +var BigEndian = binary.BigEndian + +// AppendUint16 appends the binary representation of a uint16 to buf. +func AppendUint16(buf []byte, order binary.ByteOrder, num uint16) []byte { + buf = extendZero(2, buf) + order.PutUint16(buf[len(buf)-2:], num) + return buf +} + +// AppendUint32 appends the binary representation of a uint32 to buf. +func AppendUint32(buf []byte, order binary.ByteOrder, num uint32) []byte { + buf = extendZero(4, buf) + order.PutUint32(buf[len(buf)-4:], num) + return buf +} + +// AppendUint64 appends the binary representation of a uint64 to buf. +func AppendUint64(buf []byte, order binary.ByteOrder, num uint64) []byte { + buf = extendZero(8, buf) + order.PutUint64(buf[len(buf)-8:], num) + return buf +} + +// Marshal appends a binary representation of data to buf. +// +// data must only contain fixed-length signed and unsigned ints, arrays, +// slices, structs and compositions of said types. data may be a pointer, +// but cannot contain pointers. +func Marshal(buf []byte, order binary.ByteOrder, data interface{}) []byte { + return marshal(buf, order, reflect.Indirect(reflect.ValueOf(data))) +} + +func marshal(buf []byte, order binary.ByteOrder, data reflect.Value) []byte { + switch data.Kind() { + case reflect.Int8: + buf = append(buf, byte(int8(data.Int()))) + case reflect.Int16: + buf = AppendUint16(buf, order, uint16(int16(data.Int()))) + case reflect.Int32: + buf = AppendUint32(buf, order, uint32(int32(data.Int()))) + case reflect.Int64: + buf = AppendUint64(buf, order, uint64(data.Int())) + + case reflect.Uint8: + buf = append(buf, byte(data.Uint())) + case reflect.Uint16: + buf = AppendUint16(buf, order, uint16(data.Uint())) + case reflect.Uint32: + buf = AppendUint32(buf, order, uint32(data.Uint())) + case reflect.Uint64: + buf = AppendUint64(buf, order, data.Uint()) + + case reflect.Array, reflect.Slice: + for i, l := 0, data.Len(); i < l; i++ { + buf = marshal(buf, order, data.Index(i)) + } + + case reflect.Struct: + for i, l := 0, data.NumField(); i < l; i++ { + buf = marshal(buf, order, data.Field(i)) + } + + default: + panic("invalid type: " + data.Type().String()) + } + return buf +} + +// Unmarshal unpacks buf into data. +// +// data must be a slice or a pointer and buf must have a length of exactly +// Size(data). data must only contain fixed-length signed and unsigned ints, +// arrays, slices, structs and compositions of said types. +func Unmarshal(buf []byte, order binary.ByteOrder, data interface{}) { + value := reflect.ValueOf(data) + switch value.Kind() { + case reflect.Ptr: + value = value.Elem() + case reflect.Slice: + default: + panic("invalid type: " + value.Type().String()) + } + buf = unmarshal(buf, order, value) + if len(buf) != 0 { + panic(fmt.Sprintf("buffer too long by %d bytes", len(buf))) + } +} + +func unmarshal(buf []byte, order binary.ByteOrder, data reflect.Value) []byte { + switch data.Kind() { + case reflect.Int8: + data.SetInt(int64(int8(buf[0]))) + buf = buf[1:] + case reflect.Int16: + data.SetInt(int64(int16(order.Uint16(buf)))) + buf = buf[2:] + case reflect.Int32: + data.SetInt(int64(int32(order.Uint32(buf)))) + buf = buf[4:] + case reflect.Int64: + data.SetInt(int64(order.Uint64(buf))) + buf = buf[8:] + + case reflect.Uint8: + data.SetUint(uint64(buf[0])) + buf = buf[1:] + case reflect.Uint16: + data.SetUint(uint64(order.Uint16(buf))) + buf = buf[2:] + case reflect.Uint32: + data.SetUint(uint64(order.Uint32(buf))) + buf = buf[4:] + case reflect.Uint64: + data.SetUint(order.Uint64(buf)) + buf = buf[8:] + + case reflect.Array, reflect.Slice: + for i, l := 0, data.Len(); i < l; i++ { + buf = unmarshal(buf, order, data.Index(i)) + } + + case reflect.Struct: + for i, l := 0, data.NumField(); i < l; i++ { + if field := data.Field(i); field.CanSet() { + buf = unmarshal(buf, order, field) + } else { + buf = buf[sizeof(field):] + } + } + + default: + panic("invalid type: " + data.Type().String()) + } + return buf +} + +// Size calculates the buffer sized needed by Marshal or Unmarshal. +// +// Size only support the types supported by Marshal. +func Size(v interface{}) uintptr { + return sizeof(reflect.Indirect(reflect.ValueOf(v))) +} + +func sizeof(data reflect.Value) uintptr { + switch data.Kind() { + case reflect.Int8, reflect.Uint8: + return 1 + case reflect.Int16, reflect.Uint16: + return 2 + case reflect.Int32, reflect.Uint32: + return 4 + case reflect.Int64, reflect.Uint64: + return 8 + + case reflect.Array, reflect.Slice: + var size uintptr + for i, l := 0, data.Len(); i < l; i++ { + size += sizeof(data.Index(i)) + } + return size + + case reflect.Struct: + var size uintptr + for i, l := 0, data.NumField(); i < l; i++ { + size += sizeof(data.Field(i)) + } + return size + + default: + panic("invalid type: " + data.Type().String()) + } +} + +func extendZero(amount uintptr, buf []byte) []byte { + for i := uintptr(0); i < amount; i++ { + buf = append(buf, 0) + } + return buf +} + +// ReadUint16 reads a uint16 from r. +func ReadUint16(r io.Reader, order binary.ByteOrder) (uint16, error) { + buf := make([]byte, 2) + if _, err := io.ReadFull(r, buf); err != nil { + return 0, err + } + return order.Uint16(buf), nil +} + +// ReadUint32 reads a uint32 from r. +func ReadUint32(r io.Reader, order binary.ByteOrder) (uint32, error) { + buf := make([]byte, 4) + if _, err := io.ReadFull(r, buf); err != nil { + return 0, err + } + return order.Uint32(buf), nil +} + +// ReadUint64 reads a uint64 from r. +func ReadUint64(r io.Reader, order binary.ByteOrder) (uint64, error) { + buf := make([]byte, 8) + if _, err := io.ReadFull(r, buf); err != nil { + return 0, err + } + return order.Uint64(buf), nil +} + +// WriteUint16 writes a uint16 to w. +func WriteUint16(w io.Writer, order binary.ByteOrder, num uint16) error { + buf := make([]byte, 2) + order.PutUint16(buf, num) + _, err := w.Write(buf) + return err +} + +// WriteUint32 writes a uint32 to w. +func WriteUint32(w io.Writer, order binary.ByteOrder, num uint32) error { + buf := make([]byte, 4) + order.PutUint32(buf, num) + _, err := w.Write(buf) + return err +} + +// WriteUint64 writes a uint64 to w. +func WriteUint64(w io.Writer, order binary.ByteOrder, num uint64) error { + buf := make([]byte, 8) + order.PutUint64(buf, num) + _, err := w.Write(buf) + return err +} |