blob: f35aa344f13b38e84e4f3bf1f65d44798d1967d9 [file] [log] [blame]
// Copyright 2015 The Vanadium 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 lib
import (
"v.io/v23/verror"
)
const pkgPath = "v.io/x/ref/services/wspr/internal/lib"
const uint64Size = 8
var (
errInvalid = verror.Register(pkgPath+".errInvalid", verror.NoRetry, "{1:}{2:} wspr: invalid encoding{:_}")
errEOF = verror.Register(pkgPath+".errEOF", verror.NoRetry, "{1:}{2:} wspr: eof{:_}")
errUintOverflow = verror.Register(pkgPath+".errUintOverflow", verror.NoRetry, "{1:}{2:} wspr: scalar larger than 8 bytes{:_}")
)
// The logic of the two functions here are copied from the vom implementations and
// should be kept in sync.
// Unsigned integers are the basis for all other primitive values. This is a
// two-state encoding. If the number is less than 128 (0 through 0x7f), its
// value is written directly. Otherwise the value is written in big-endian byte
// order preceded by the negated byte length.
func BinaryEncodeUint(v uint64) []byte {
switch {
case v <= 0x7f:
return []byte{byte(v)}
case v <= 0xff:
return []byte{0xff, byte(v)}
case v <= 0xffff:
return []byte{0xfe, byte(v >> 8), byte(v)}
case v <= 0xffffff:
return []byte{0xfd, byte(v >> 16), byte(v >> 8), byte(v)}
case v <= 0xffffffff:
return []byte{0xfc, byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)}
case v <= 0xffffffffff:
return []byte{0xfb, byte(v >> 32), byte(v >> 24),
byte(v >> 16), byte(v >> 8), byte(v)}
case v <= 0xffffffffffff:
return []byte{0xfa, byte(v >> 40), byte(v >> 32), byte(v >> 24),
byte(v >> 16), byte(v >> 8), byte(v)}
case v <= 0xffffffffffffff:
return []byte{0xf9, byte(v >> 48), byte(v >> 40), byte(v >> 32),
byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)}
default:
return []byte{0xf9, byte(v >> 56), byte(v >> 48), byte(v >> 40),
byte(v >> 32), byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)}
}
}
func BinaryDecodeUint(input []byte) (v uint64, byteLen int, err error) {
if len(input) == 0 {
return 0, 0, verror.New(errEOF, nil)
}
firstByte := input[0]
if firstByte <= 0x7f {
return uint64(firstByte), 1, nil
}
if firstByte <= 0xdf {
return 0, 0, verror.New(errInvalid, nil)
}
byteLen = int(-int8(firstByte))
if byteLen < 1 || byteLen > uint64Size {
return 0, 0, verror.New(errUintOverflow, nil)
}
if len(input) < byteLen {
return 0, 0, verror.New(errEOF, nil)
}
for i := 1; i < byteLen; i++ {
v = v<<8 | uint64(input[i])
}
return
}