| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * 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 "src/tracing/core/sliced_protobuf_input_stream.h" |
| |
| #include <algorithm> |
| |
| #include "perfetto/base/logging.h" |
| |
| namespace perfetto { |
| |
| SlicedProtobufInputStream::SlicedProtobufInputStream(const Slices* slices) |
| : slices_(slices), cur_slice_(slices_->begin()) {} |
| |
| SlicedProtobufInputStream::~SlicedProtobufInputStream() = default; |
| |
| bool SlicedProtobufInputStream::Next(const void** data, int* size) { |
| if (cur_slice_ == slices_->end()) |
| return false; |
| |
| PERFETTO_DCHECK(Validate()); |
| *data = reinterpret_cast<const void*>( |
| reinterpret_cast<uintptr_t>(cur_slice_->start) + pos_in_cur_slice_); |
| *size = static_cast<int>(cur_slice_->size - pos_in_cur_slice_); |
| cur_slice_++; |
| pos_in_cur_slice_ = 0; |
| PERFETTO_DCHECK(Validate()); |
| |
| return true; |
| } |
| |
| void SlicedProtobufInputStream::BackUp(int count) { |
| size_t n = static_cast<size_t>(count); |
| PERFETTO_DCHECK(Validate()); |
| while (n) { |
| if (cur_slice_ == slices_->end() || pos_in_cur_slice_ == 0) { |
| if (cur_slice_ == slices_->begin()) { |
| // The protobuf library is violating its contract and backing up more |
| // bytes than available. |
| PERFETTO_DFATAL("Protobuf library backed up too many bytes."); |
| return; |
| } |
| cur_slice_--; |
| pos_in_cur_slice_ = cur_slice_->size; |
| continue; |
| } |
| |
| const size_t decrement = std::min(n, pos_in_cur_slice_); |
| pos_in_cur_slice_ -= decrement; |
| n -= decrement; |
| } |
| PERFETTO_DCHECK(Validate()); |
| } |
| |
| bool SlicedProtobufInputStream::Skip(int count) { |
| PERFETTO_DCHECK(Validate()); |
| size_t n = static_cast<size_t>(count); |
| while (n) { |
| PERFETTO_DCHECK(Validate()); |
| if (cur_slice_ == slices_->end()) |
| return false; |
| |
| const size_t increment = std::min(n, cur_slice_->size - pos_in_cur_slice_); |
| pos_in_cur_slice_ += increment; |
| n -= increment; |
| |
| if (pos_in_cur_slice_ >= cur_slice_->size) { |
| cur_slice_++; |
| pos_in_cur_slice_ = 0; |
| } |
| } |
| PERFETTO_DCHECK(Validate()); |
| return true; |
| } |
| |
| google::protobuf::int64 SlicedProtobufInputStream::ByteCount() const { |
| PERFETTO_DCHECK(Validate()); |
| google::protobuf::int64 count = 0; |
| for (auto it = slices_->begin(); it != slices_->end(); it++) { |
| if (it == cur_slice_) { |
| count += static_cast<google::protobuf::int64>(pos_in_cur_slice_); |
| break; |
| } |
| count += static_cast<google::protobuf::int64>(it->size); |
| } |
| return count; |
| } |
| |
| bool SlicedProtobufInputStream::Validate() const { |
| return ((cur_slice_ == slices_->end() && pos_in_cur_slice_ == 0) || |
| pos_in_cur_slice_ < cur_slice_->size || |
| (pos_in_cur_slice_ == 0 && cur_slice_->size == 0)); |
| } |
| |
| } // namespace perfetto |