// Copyright 2020 The Abseil Authors. // // 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 // // https://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 "absl/log/internal/proto.h" #include #include #include #include #include #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/types/span.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace log_internal { namespace { void EncodeRawVarint(uint64_t value, size_t size, absl::Span *buf) { for (size_t s = 0; s < size; s++) { (*buf)[s] = static_cast((value & 0x7f) | (s + 1 == size ? 0 : 0x80)); value >>= 7; } buf->remove_prefix(size); } constexpr uint64_t MakeTagType(uint64_t tag, WireType type) { return tag << 3 | static_cast(type); } } // namespace bool EncodeVarint(uint64_t tag, uint64_t value, absl::Span *buf) { const uint64_t tag_type = MakeTagType(tag, WireType::kVarint); const size_t tag_type_size = VarintSize(tag_type); const size_t value_size = VarintSize(value); if (tag_type_size + value_size > buf->size()) { buf->remove_suffix(buf->size()); return false; } EncodeRawVarint(tag_type, tag_type_size, buf); EncodeRawVarint(value, value_size, buf); return true; } bool Encode64Bit(uint64_t tag, uint64_t value, absl::Span *buf) { const uint64_t tag_type = MakeTagType(tag, WireType::k64Bit); const size_t tag_type_size = VarintSize(tag_type); if (tag_type_size + sizeof(value) > buf->size()) { buf->remove_suffix(buf->size()); return false; } EncodeRawVarint(tag_type, tag_type_size, buf); for (size_t s = 0; s < sizeof(value); s++) { (*buf)[s] = static_cast(value & 0xff); value >>= 8; } buf->remove_prefix(sizeof(value)); return true; } bool Encode32Bit(uint64_t tag, uint32_t value, absl::Span *buf) { const uint64_t tag_type = MakeTagType(tag, WireType::k32Bit); const size_t tag_type_size = VarintSize(tag_type); if (tag_type_size + sizeof(value) > buf->size()) { buf->remove_suffix(buf->size()); return false; } EncodeRawVarint(tag_type, tag_type_size, buf); for (size_t s = 0; s < sizeof(value); s++) { (*buf)[s] = static_cast(value & 0xff); value >>= 8; } buf->remove_prefix(sizeof(value)); return true; } bool EncodeBytes(uint64_t tag, absl::Span value, absl::Span *buf) { const uint64_t tag_type = MakeTagType(tag, WireType::kLengthDelimited); const size_t tag_type_size = VarintSize(tag_type); uint64_t length = value.size(); const size_t length_size = VarintSize(length); if (tag_type_size + length_size + value.size() > buf->size()) { buf->remove_suffix(buf->size()); return false; } EncodeRawVarint(tag_type, tag_type_size, buf); EncodeRawVarint(length, length_size, buf); memcpy(buf->data(), value.data(), value.size()); buf->remove_prefix(value.size()); return true; } bool EncodeBytesTruncate(uint64_t tag, absl::Span value, absl::Span *buf) { const uint64_t tag_type = MakeTagType(tag, WireType::kLengthDelimited); const size_t tag_type_size = VarintSize(tag_type); uint64_t length = value.size(); const size_t length_size = VarintSize(std::min(length, buf->size())); if (tag_type_size + length_size <= buf->size() && tag_type_size + length_size + value.size() > buf->size()) { value.remove_suffix(tag_type_size + length_size + value.size() - buf->size()); length = value.size(); } if (tag_type_size + length_size + value.size() > buf->size()) { buf->remove_suffix(buf->size()); return false; } EncodeRawVarint(tag_type, tag_type_size, buf); EncodeRawVarint(length, length_size, buf); memcpy(buf->data(), value.data(), value.size()); buf->remove_prefix(value.size()); return true; } ABSL_MUST_USE_RESULT absl::Span EncodeMessageStart( uint64_t tag, uint64_t max_size, absl::Span *buf) { const uint64_t tag_type = MakeTagType(tag, WireType::kLengthDelimited); const size_t tag_type_size = VarintSize(tag_type); max_size = std::min(max_size, buf->size()); const size_t length_size = VarintSize(max_size); if (tag_type_size + length_size > buf->size()) { buf->remove_suffix(buf->size()); return absl::Span(); } EncodeRawVarint(tag_type, tag_type_size, buf); const absl::Span ret = buf->subspan(0, length_size); EncodeRawVarint(0, length_size, buf); return ret; } void EncodeMessageLength(absl::Span msg, const absl::Span *buf) { if (!msg.data()) return; assert(buf->data() >= msg.data()); if (buf->data() < msg.data()) return; EncodeRawVarint( static_cast(buf->data() - (msg.data() + msg.size())), msg.size(), &msg); } namespace { uint64_t DecodeVarint(absl::Span *buf) { uint64_t value = 0; size_t s = 0; while (s < buf->size()) { value |= static_cast(static_cast((*buf)[s]) & 0x7f) << 7 * s; if (!((*buf)[s++] & 0x80)) break; } buf->remove_prefix(s); return value; } uint64_t Decode64Bit(absl::Span *buf) { uint64_t value = 0; size_t s = 0; while (s < buf->size()) { value |= static_cast(static_cast((*buf)[s])) << 8 * s; if (++s == sizeof(value)) break; } buf->remove_prefix(s); return value; } uint32_t Decode32Bit(absl::Span *buf) { uint32_t value = 0; size_t s = 0; while (s < buf->size()) { value |= static_cast(static_cast((*buf)[s])) << 8 * s; if (++s == sizeof(value)) break; } buf->remove_prefix(s); return value; } } // namespace bool ProtoField::DecodeFrom(absl::Span *data) { if (data->empty()) return false; const uint64_t tag_type = DecodeVarint(data); tag_ = tag_type >> 3; type_ = static_cast(tag_type & 0x07); switch (type_) { case WireType::kVarint: value_ = DecodeVarint(data); break; case WireType::k64Bit: value_ = Decode64Bit(data); break; case WireType::kLengthDelimited: { value_ = DecodeVarint(data); data_ = data->subspan( 0, static_cast(std::min(value_, data->size()))); data->remove_prefix(data_.size()); break; } case WireType::k32Bit: value_ = Decode32Bit(data); break; } return true; } } // namespace log_internal ABSL_NAMESPACE_END } // namespace absl