| // Copyright 2014 Google Inc. All Rights Reserved. |
| // |
| // 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. |
| |
| // This file is a simple protocol buffer encoder and decoder. |
| // The format is described at |
| // https://developers.google.com/protocol-buffers/docs/encoding |
| // |
| // A protocol message must implement the message interface: |
| // decoder() []decoder |
| // encode(*buffer) |
| // |
| // The decode method returns a slice indexed by field number that gives the |
| // function to decode that field. |
| // The encode method encodes its receiver into the given buffer. |
| // |
| // The two methods are simple enough to be implemented by hand rather than |
| // by using a protocol compiler. |
| // |
| // See profile.go for examples of messages implementing this interface. |
| // |
| // There is no support for groups, message sets, or "has" bits. |
| |
| package profile |
| |
| import "errors" |
| |
| type buffer struct { |
| field int // field tag |
| typ int // proto wire type code for field |
| u64 uint64 |
| data []byte |
| tmp [16]byte |
| } |
| |
| type decoder func(*buffer, message) error |
| |
| type message interface { |
| decoder() []decoder |
| encode(*buffer) |
| } |
| |
| func marshal(m message) []byte { |
| var b buffer |
| m.encode(&b) |
| return b.data |
| } |
| |
| func encodeVarint(b *buffer, x uint64) { |
| for x >= 128 { |
| b.data = append(b.data, byte(x)|0x80) |
| x >>= 7 |
| } |
| b.data = append(b.data, byte(x)) |
| } |
| |
| func encodeLength(b *buffer, tag int, len int) { |
| encodeVarint(b, uint64(tag)<<3|2) |
| encodeVarint(b, uint64(len)) |
| } |
| |
| func encodeUint64(b *buffer, tag int, x uint64) { |
| // append varint to b.data |
| encodeVarint(b, uint64(tag)<<3) |
| encodeVarint(b, x) |
| } |
| |
| func encodeUint64s(b *buffer, tag int, x []uint64) { |
| if len(x) > 2 { |
| // Use packed encoding |
| n1 := len(b.data) |
| for _, u := range x { |
| encodeVarint(b, u) |
| } |
| n2 := len(b.data) |
| encodeLength(b, tag, n2-n1) |
| n3 := len(b.data) |
| copy(b.tmp[:], b.data[n2:n3]) |
| copy(b.data[n1+(n3-n2):], b.data[n1:n2]) |
| copy(b.data[n1:], b.tmp[:n3-n2]) |
| return |
| } |
| for _, u := range x { |
| encodeUint64(b, tag, u) |
| } |
| } |
| |
| func encodeUint64Opt(b *buffer, tag int, x uint64) { |
| if x == 0 { |
| return |
| } |
| encodeUint64(b, tag, x) |
| } |
| |
| func encodeInt64(b *buffer, tag int, x int64) { |
| u := uint64(x) |
| encodeUint64(b, tag, u) |
| } |
| |
| func encodeInt64s(b *buffer, tag int, x []int64) { |
| if len(x) > 2 { |
| // Use packed encoding |
| n1 := len(b.data) |
| for _, u := range x { |
| encodeVarint(b, uint64(u)) |
| } |
| n2 := len(b.data) |
| encodeLength(b, tag, n2-n1) |
| n3 := len(b.data) |
| copy(b.tmp[:], b.data[n2:n3]) |
| copy(b.data[n1+(n3-n2):], b.data[n1:n2]) |
| copy(b.data[n1:], b.tmp[:n3-n2]) |
| return |
| } |
| for _, u := range x { |
| encodeInt64(b, tag, u) |
| } |
| } |
| |
| func encodeInt64Opt(b *buffer, tag int, x int64) { |
| if x == 0 { |
| return |
| } |
| encodeInt64(b, tag, x) |
| } |
| |
| func encodeString(b *buffer, tag int, x string) { |
| encodeLength(b, tag, len(x)) |
| b.data = append(b.data, x...) |
| } |
| |
| func encodeStrings(b *buffer, tag int, x []string) { |
| for _, s := range x { |
| encodeString(b, tag, s) |
| } |
| } |
| |
| func encodeBool(b *buffer, tag int, x bool) { |
| if x { |
| encodeUint64(b, tag, 1) |
| } else { |
| encodeUint64(b, tag, 0) |
| } |
| } |
| |
| func encodeBoolOpt(b *buffer, tag int, x bool) { |
| if x { |
| encodeBool(b, tag, x) |
| } |
| } |
| |
| func encodeMessage(b *buffer, tag int, m message) { |
| n1 := len(b.data) |
| m.encode(b) |
| n2 := len(b.data) |
| encodeLength(b, tag, n2-n1) |
| n3 := len(b.data) |
| copy(b.tmp[:], b.data[n2:n3]) |
| copy(b.data[n1+(n3-n2):], b.data[n1:n2]) |
| copy(b.data[n1:], b.tmp[:n3-n2]) |
| } |
| |
| func unmarshal(data []byte, m message) (err error) { |
| b := buffer{data: data, typ: 2} |
| return decodeMessage(&b, m) |
| } |
| |
| func le64(p []byte) uint64 { |
| return uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 | uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56 |
| } |
| |
| func le32(p []byte) uint32 { |
| return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24 |
| } |
| |
| func decodeVarint(data []byte) (uint64, []byte, error) { |
| var u uint64 |
| for i := 0; ; i++ { |
| if i >= 10 || i >= len(data) { |
| return 0, nil, errors.New("bad varint") |
| } |
| u |= uint64(data[i]&0x7F) << uint(7*i) |
| if data[i]&0x80 == 0 { |
| return u, data[i+1:], nil |
| } |
| } |
| } |
| |
| func decodeField(b *buffer, data []byte) ([]byte, error) { |
| x, data, err := decodeVarint(data) |
| if err != nil { |
| return nil, err |
| } |
| b.field = int(x >> 3) |
| b.typ = int(x & 7) |
| b.data = nil |
| b.u64 = 0 |
| switch b.typ { |
| case 0: |
| b.u64, data, err = decodeVarint(data) |
| if err != nil { |
| return nil, err |
| } |
| case 1: |
| if len(data) < 8 { |
| return nil, errors.New("not enough data") |
| } |
| b.u64 = le64(data[:8]) |
| data = data[8:] |
| case 2: |
| var n uint64 |
| n, data, err = decodeVarint(data) |
| if err != nil { |
| return nil, err |
| } |
| if n > uint64(len(data)) { |
| return nil, errors.New("too much data") |
| } |
| b.data = data[:n] |
| data = data[n:] |
| case 5: |
| if len(data) < 4 { |
| return nil, errors.New("not enough data") |
| } |
| b.u64 = uint64(le32(data[:4])) |
| data = data[4:] |
| default: |
| return nil, errors.New("unknown wire type: " + string(b.typ)) |
| } |
| |
| return data, nil |
| } |
| |
| func checkType(b *buffer, typ int) error { |
| if b.typ != typ { |
| return errors.New("type mismatch") |
| } |
| return nil |
| } |
| |
| func decodeMessage(b *buffer, m message) error { |
| if err := checkType(b, 2); err != nil { |
| return err |
| } |
| dec := m.decoder() |
| data := b.data |
| for len(data) > 0 { |
| // pull varint field# + type |
| var err error |
| data, err = decodeField(b, data) |
| if err != nil { |
| return err |
| } |
| if b.field >= len(dec) || dec[b.field] == nil { |
| continue |
| } |
| if err := dec[b.field](b, m); err != nil { |
| return err |
| } |
| } |
| return nil |
| } |
| |
| func decodeInt64(b *buffer, x *int64) error { |
| if err := checkType(b, 0); err != nil { |
| return err |
| } |
| *x = int64(b.u64) |
| return nil |
| } |
| |
| func decodeInt64s(b *buffer, x *[]int64) error { |
| if b.typ == 2 { |
| // Packed encoding |
| data := b.data |
| tmp := make([]int64, 0, len(data)) // Maximally sized |
| for len(data) > 0 { |
| var u uint64 |
| var err error |
| |
| if u, data, err = decodeVarint(data); err != nil { |
| return err |
| } |
| tmp = append(tmp, int64(u)) |
| } |
| *x = append(*x, tmp...) |
| return nil |
| } |
| var i int64 |
| if err := decodeInt64(b, &i); err != nil { |
| return err |
| } |
| *x = append(*x, i) |
| return nil |
| } |
| |
| func decodeUint64(b *buffer, x *uint64) error { |
| if err := checkType(b, 0); err != nil { |
| return err |
| } |
| *x = b.u64 |
| return nil |
| } |
| |
| func decodeUint64s(b *buffer, x *[]uint64) error { |
| if b.typ == 2 { |
| data := b.data |
| // Packed encoding |
| tmp := make([]uint64, 0, len(data)) // Maximally sized |
| for len(data) > 0 { |
| var u uint64 |
| var err error |
| |
| if u, data, err = decodeVarint(data); err != nil { |
| return err |
| } |
| tmp = append(tmp, u) |
| } |
| *x = append(*x, tmp...) |
| return nil |
| } |
| var u uint64 |
| if err := decodeUint64(b, &u); err != nil { |
| return err |
| } |
| *x = append(*x, u) |
| return nil |
| } |
| |
| func decodeString(b *buffer, x *string) error { |
| if err := checkType(b, 2); err != nil { |
| return err |
| } |
| *x = string(b.data) |
| return nil |
| } |
| |
| func decodeStrings(b *buffer, x *[]string) error { |
| var s string |
| if err := decodeString(b, &s); err != nil { |
| return err |
| } |
| *x = append(*x, s) |
| return nil |
| } |
| |
| func decodeBool(b *buffer, x *bool) error { |
| if err := checkType(b, 0); err != nil { |
| return err |
| } |
| if int64(b.u64) == 0 { |
| *x = false |
| } else { |
| *x = true |
| } |
| return nil |
| } |