// // 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(v) // : static_cast((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 }