1// Copyright 2008 Google Inc. 2// Author: Lincoln Smith 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15 16#include <config.h> 17#include "varint_bigendian.h" 18#include <stdint.h> // int32_t, int64_t 19#include <string.h> // memcpy 20#include <string> 21#include "logging.h" 22#include "google/output_string.h" 23 24namespace open_vcdiff { 25 26template<> const int32_t VarintBE<int32_t>::kMaxVal = 0x7FFFFFFF; 27template<> const int64_t VarintBE<int64_t>::kMaxVal = 0x7FFFFFFFFFFFFFFFULL; 28 29// Reads a variable-length integer from **varint_ptr 30// and returns it in a fixed-length representation. Increments 31// *varint_ptr by the number of bytes read. Will not read 32// past limit. Returns RESULT_ERROR if the value parsed 33// does not fit in a non-negative signed integer, or if limit is NULL. 34// Returns RESULT_END_OF_DATA if address_stream_end is reached 35// before the whole integer can be decoded. 36// 37template <typename SignedIntegerType> 38SignedIntegerType VarintBE<SignedIntegerType>::Parse(const char* limit, 39 const char** varint_ptr) { 40 if (!limit) { 41 return RESULT_ERROR; 42 } 43 SignedIntegerType result = 0; 44 for (const char* parse_ptr = *varint_ptr; parse_ptr < limit; ++parse_ptr) { 45 result += *parse_ptr & 0x7F; 46 if (!(*parse_ptr & 0x80)) { 47 *varint_ptr = parse_ptr + 1; 48 return result; 49 } 50 if (result > (kMaxVal >> 7)) { 51 // Shifting result by 7 bits would produce a number too large 52 // to be stored in a non-negative SignedIntegerType (an overflow.) 53 return RESULT_ERROR; 54 } 55 result = result << 7; 56 } 57 return RESULT_END_OF_DATA; 58} 59 60template <typename SignedIntegerType> 61int VarintBE<SignedIntegerType>::EncodeInternal(SignedIntegerType v, 62 char* varint_buf) { 63 if (v < 0) { 64 LOG(DFATAL) << "Negative value " << v 65 << " passed to VarintBE::EncodeInternal," 66 " which requires non-negative argument" << LOG_ENDL; 67 return 0; 68 } 69 int length = 1; 70 char* buf_ptr = &varint_buf[kMaxBytes - 1]; 71 *buf_ptr = static_cast<char>(v & 0x7F); 72 --buf_ptr; 73 v >>= 7; 74 while (v) { 75 *buf_ptr = static_cast<char>((v & 0x7F) | 0x80); // add continuation bit 76 --buf_ptr; 77 ++length; 78 v >>= 7; 79 } 80 return length; 81} 82 83template <typename SignedIntegerType> 84int VarintBE<SignedIntegerType>::Encode(SignedIntegerType v, char* ptr) { 85 char varint_buf[kMaxBytes]; 86 const int length = EncodeInternal(v, varint_buf); 87 memcpy(ptr, &varint_buf[kMaxBytes - length], length); 88 return length; 89} 90 91template <typename SignedIntegerType> 92void VarintBE<SignedIntegerType>::AppendToString(SignedIntegerType value, 93 string* s) { 94 char varint_buf[kMaxBytes]; 95 const int length = EncodeInternal(value, varint_buf); 96 s->append(&varint_buf[kMaxBytes - length], length); 97} 98 99template <typename SignedIntegerType> 100void VarintBE<SignedIntegerType>::AppendToOutputString( 101 SignedIntegerType value, 102 OutputStringInterface* output_string) { 103 char varint_buf[kMaxBytes]; 104 const int length = EncodeInternal(value, varint_buf); 105 output_string->append(&varint_buf[kMaxBytes - length], length); 106} 107 108// Returns the encoding length of the specified value. 109template <typename SignedIntegerType> 110int VarintBE<SignedIntegerType>::Length(SignedIntegerType v) { 111 if (v < 0) { 112 LOG(DFATAL) << "Negative value " << v 113 << " passed to VarintBE::Length," 114 " which requires non-negative argument" << LOG_ENDL; 115 return 0; 116 } 117 int length = 0; 118 do { 119 v >>= 7; 120 ++length; 121 } while (v); 122 return length; 123} 124 125template class VarintBE<int32_t>; 126template class VarintBE<int64_t>; 127 128} // namespace open_vcdiff 129