diff options
Diffstat (limited to 'sdch/open-vcdiff/src/varint_bigendian.cc')
-rw-r--r-- | sdch/open-vcdiff/src/varint_bigendian.cc | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/sdch/open-vcdiff/src/varint_bigendian.cc b/sdch/open-vcdiff/src/varint_bigendian.cc new file mode 100644 index 0000000..9166012 --- /dev/null +++ b/sdch/open-vcdiff/src/varint_bigendian.cc @@ -0,0 +1,128 @@ +// Copyright 2008 Google Inc. +// Author: Lincoln Smith +// +// 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. + +#include <config.h> +#include "varint_bigendian.h" +#include <stdint.h> // int32_t, int64_t +#include <string.h> // memcpy +#include <string> +#include "logging.h" +#include "google/output_string.h" + +namespace open_vcdiff { + +template<> const int32_t VarintBE<int32_t>::kMaxVal = 0x7FFFFFFF; +template<> const int64_t VarintBE<int64_t>::kMaxVal = 0x7FFFFFFFFFFFFFFFULL; + +// Reads a variable-length integer from **varint_ptr +// and returns it in a fixed-length representation. Increments +// *varint_ptr by the number of bytes read. Will not read +// past limit. Returns RESULT_ERROR if the value parsed +// does not fit in a non-negative signed integer, or if limit is NULL. +// Returns RESULT_END_OF_DATA if address_stream_end is reached +// before the whole integer can be decoded. +// +template <typename SignedIntegerType> +SignedIntegerType VarintBE<SignedIntegerType>::Parse(const char* limit, + const char** varint_ptr) { + if (!limit) { + return RESULT_ERROR; + } + SignedIntegerType result = 0; + for (const char* parse_ptr = *varint_ptr; parse_ptr < limit; ++parse_ptr) { + result += *parse_ptr & 0x7F; + if (!(*parse_ptr & 0x80)) { + *varint_ptr = parse_ptr + 1; + return result; + } + if (result > (kMaxVal >> 7)) { + // Shifting result by 7 bits would produce a number too large + // to be stored in a non-negative SignedIntegerType (an overflow.) + return RESULT_ERROR; + } + result = result << 7; + } + return RESULT_END_OF_DATA; +} + +template <typename SignedIntegerType> +int VarintBE<SignedIntegerType>::EncodeInternal(SignedIntegerType v, + char* varint_buf) { + if (v < 0) { + LOG(DFATAL) << "Negative value " << v + << " passed to VarintBE::EncodeInternal," + " which requires non-negative argument" << LOG_ENDL; + return 0; + } + int length = 1; + char* buf_ptr = &varint_buf[kMaxBytes - 1]; + *buf_ptr = static_cast<char>(v & 0x7F); + --buf_ptr; + v >>= 7; + while (v) { + *buf_ptr = static_cast<char>((v & 0x7F) | 0x80); // add continuation bit + --buf_ptr; + ++length; + v >>= 7; + } + return length; +} + +template <typename SignedIntegerType> +int VarintBE<SignedIntegerType>::Encode(SignedIntegerType v, char* ptr) { + char varint_buf[kMaxBytes]; + const int length = EncodeInternal(v, varint_buf); + memcpy(ptr, &varint_buf[kMaxBytes - length], length); + return length; +} + +template <typename SignedIntegerType> +void VarintBE<SignedIntegerType>::AppendToString(SignedIntegerType value, + string* s) { + char varint_buf[kMaxBytes]; + const int length = EncodeInternal(value, varint_buf); + s->append(&varint_buf[kMaxBytes - length], length); +} + +template <typename SignedIntegerType> +void VarintBE<SignedIntegerType>::AppendToOutputString( + SignedIntegerType value, + OutputStringInterface* output_string) { + char varint_buf[kMaxBytes]; + const int length = EncodeInternal(value, varint_buf); + output_string->append(&varint_buf[kMaxBytes - length], length); +} + +// Returns the encoding length of the specified value. +template <typename SignedIntegerType> +int VarintBE<SignedIntegerType>::Length(SignedIntegerType v) { + if (v < 0) { + LOG(DFATAL) << "Negative value " << v + << " passed to VarintBE::Length," + " which requires non-negative argument" << LOG_ENDL; + return 0; + } + int length = 0; + do { + v >>= 7; + ++length; + } while (v); + return length; +} + +template class VarintBE<int32_t>; +template class VarintBE<int64_t>; + +} // namespace open_vcdiff |