You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
202 lines
5.0 KiB
202 lines
5.0 KiB
//
|
|
// DISCLAIMER
|
|
//
|
|
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
|
|
//
|
|
// 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.
|
|
//
|
|
// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
|
//
|
|
// Author Ewout Prangsma
|
|
//
|
|
|
|
package velocypack
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
// vpackAssert panics if v is false.
|
|
func vpackAssert(v bool) {
|
|
if !v {
|
|
panic("VELOCYPACK_ASSERT failed")
|
|
}
|
|
}
|
|
|
|
// readBytes reads bytes from the given reader until the given slice is full.
|
|
func readBytes(dst []byte, r io.Reader) error {
|
|
offset := 0
|
|
l := len(dst)
|
|
for {
|
|
n, err := r.Read(dst[offset:])
|
|
offset += n
|
|
l -= n
|
|
if l == 0 {
|
|
// We're done
|
|
return nil
|
|
}
|
|
if err != nil {
|
|
return WithStack(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// read an unsigned little endian integer value of the
|
|
// specified length, starting at the specified byte offset
|
|
func readIntegerFixed(start []byte, length uint) uint64 {
|
|
return readIntegerNonEmpty(start, length)
|
|
}
|
|
|
|
// read an unsigned little endian integer value of the
|
|
// specified length, starting at the specified byte offset
|
|
func readIntegerFixedFromReader(r io.Reader, length uint) (uint64, []byte, error) {
|
|
buf := make([]byte, length)
|
|
if err := readBytes(buf, r); err != nil {
|
|
return 0, nil, WithStack(err)
|
|
}
|
|
return readIntegerFixed(buf, length), buf, nil
|
|
}
|
|
|
|
// read an unsigned little endian integer value of the
|
|
// specified length, starting at the specified byte offset
|
|
func readIntegerNonEmpty(s []byte, length uint) uint64 {
|
|
x := uint(0)
|
|
v := uint64(0)
|
|
for i := uint(0); i < length; i++ {
|
|
v += uint64(s[i]) << x
|
|
x += 8
|
|
}
|
|
return v
|
|
}
|
|
|
|
// read an unsigned little endian integer value of the
|
|
// specified length, starting at the specified byte offset
|
|
func readIntegerNonEmptyFromReader(r io.Reader, length uint) (uint64, []byte, error) {
|
|
buf := make([]byte, length)
|
|
if err := readBytes(buf, r); err != nil {
|
|
return 0, nil, WithStack(err)
|
|
}
|
|
return readIntegerNonEmpty(buf, length), buf, nil
|
|
}
|
|
|
|
func toInt64(v uint64) int64 {
|
|
shift2 := uint64(1) << 63
|
|
shift := int64(shift2 - 1)
|
|
if v >= shift2 {
|
|
return (int64(v-shift2) - shift) - 1
|
|
} else {
|
|
return int64(v)
|
|
}
|
|
}
|
|
|
|
func toUInt64(v int64) uint64 {
|
|
// If v is negative, we need to add 2^63 to make it positive,
|
|
// before we can cast it to an uint64_t:
|
|
if v >= 0 {
|
|
return uint64(v)
|
|
}
|
|
shift2 := uint64(1) << 63
|
|
shift := int64(shift2 - 1)
|
|
return uint64((v+shift)+1) + shift2
|
|
// return v >= 0 ? static_cast<uint64_t>(v)
|
|
// : static_cast<uint64_t>((v + shift) + 1) + shift2;
|
|
// Note that g++ and clang++ with -O3 compile this away to
|
|
// nothing. Further note that a plain cast from int64_t to
|
|
// uint64_t is not guaranteed to work for negative values!
|
|
}
|
|
|
|
// read a variable length integer in unsigned LEB128 format
|
|
func readVariableValueLength(source []byte, offset ValueLength, reverse bool) ValueLength {
|
|
length := ValueLength(0)
|
|
p := uint(0)
|
|
for {
|
|
v := ValueLength(source[offset])
|
|
length += (v & 0x7f) << p
|
|
p += 7
|
|
if reverse {
|
|
offset--
|
|
} else {
|
|
offset++
|
|
}
|
|
if v&0x80 == 0 {
|
|
break
|
|
}
|
|
}
|
|
return length
|
|
}
|
|
|
|
// read a variable length integer in unsigned LEB128 format
|
|
func readVariableValueLengthFromReader(r io.Reader, reverse bool) (ValueLength, []byte, error) {
|
|
if reverse {
|
|
return 0, nil, WithStack(fmt.Errorf("reverse is not supported"))
|
|
}
|
|
length := ValueLength(0)
|
|
p := uint(0)
|
|
buf := make([]byte, 1)
|
|
bytes := make([]byte, 0, 8)
|
|
for {
|
|
if n, err := r.Read(buf); n != 1 {
|
|
if err != nil {
|
|
return 0, nil, WithStack(err)
|
|
} else {
|
|
return 0, nil, WithStack(fmt.Errorf("failed to read 1 byte"))
|
|
}
|
|
}
|
|
bytes = append(bytes, buf[0])
|
|
v := ValueLength(buf[0])
|
|
length += (v & 0x7f) << p
|
|
p += 7
|
|
if v&0x80 == 0 {
|
|
break
|
|
}
|
|
}
|
|
return length, bytes, nil
|
|
}
|
|
|
|
// store a variable length integer in unsigned LEB128 format
|
|
func storeVariableValueLength(dst []byte, offset, value ValueLength, reverse bool) {
|
|
vpackAssert(value > 0)
|
|
|
|
idx := offset
|
|
if reverse {
|
|
for value >= 0x80 {
|
|
dst[idx] = byte(value | 0x80)
|
|
idx--
|
|
value >>= 7
|
|
}
|
|
dst[idx] = byte(value & 0x7f)
|
|
} else {
|
|
for value >= 0x80 {
|
|
dst[idx] = byte(value | 0x80)
|
|
idx++
|
|
value >>= 7
|
|
}
|
|
dst[idx] = byte(value & 0x7f)
|
|
}
|
|
}
|
|
|
|
// optionalBool returns the first arg element if available, otherwise returns defaultValue.
|
|
func optionalBool(arg []bool, defaultValue bool) bool {
|
|
if len(arg) == 0 {
|
|
return defaultValue
|
|
}
|
|
return arg[0]
|
|
}
|
|
|
|
// alignAt returns the first number >= value that is aligned at the given alignment.
|
|
// alignment must be a power of 2.
|
|
func alignAt(value, alignment uint) uint {
|
|
mask := ^(alignment - 1)
|
|
return (value + alignment - 1) & mask
|
|
}
|
|
|