1 /* 2 * Copyright (C) 2017 The Android Open Source Project 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 17 #include "src/tracing/core/sliced_protobuf_input_stream.h" 18 19 #include <algorithm> 20 21 #include "perfetto/base/logging.h" 22 23 namespace perfetto { 24 SlicedProtobufInputStream(const Slices * slices)25SlicedProtobufInputStream::SlicedProtobufInputStream(const Slices* slices) 26 : slices_(slices), cur_slice_(slices_->begin()) {} 27 28 SlicedProtobufInputStream::~SlicedProtobufInputStream() = default; 29 Next(const void ** data,int * size)30bool SlicedProtobufInputStream::Next(const void** data, int* size) { 31 if (cur_slice_ == slices_->end()) 32 return false; 33 34 PERFETTO_DCHECK(Validate()); 35 *data = reinterpret_cast<const void*>( 36 reinterpret_cast<uintptr_t>(cur_slice_->start) + pos_in_cur_slice_); 37 *size = static_cast<int>(cur_slice_->size - pos_in_cur_slice_); 38 cur_slice_++; 39 pos_in_cur_slice_ = 0; 40 PERFETTO_DCHECK(Validate()); 41 42 return true; 43 } 44 BackUp(int count)45void SlicedProtobufInputStream::BackUp(int count) { 46 size_t n = static_cast<size_t>(count); 47 PERFETTO_DCHECK(Validate()); 48 while (n) { 49 if (cur_slice_ == slices_->end() || pos_in_cur_slice_ == 0) { 50 if (cur_slice_ == slices_->begin()) { 51 // The protobuf library is violating its contract and backing up more 52 // bytes than available. 53 PERFETTO_DFATAL("Protobuf library backed up too many bytes."); 54 return; 55 } 56 cur_slice_--; 57 pos_in_cur_slice_ = cur_slice_->size; 58 continue; 59 } 60 61 const size_t decrement = std::min(n, pos_in_cur_slice_); 62 pos_in_cur_slice_ -= decrement; 63 n -= decrement; 64 } 65 PERFETTO_DCHECK(Validate()); 66 } 67 Skip(int count)68bool SlicedProtobufInputStream::Skip(int count) { 69 PERFETTO_DCHECK(Validate()); 70 size_t n = static_cast<size_t>(count); 71 while (n) { 72 PERFETTO_DCHECK(Validate()); 73 if (cur_slice_ == slices_->end()) 74 return false; 75 76 const size_t increment = std::min(n, cur_slice_->size - pos_in_cur_slice_); 77 pos_in_cur_slice_ += increment; 78 n -= increment; 79 80 if (pos_in_cur_slice_ >= cur_slice_->size) { 81 cur_slice_++; 82 pos_in_cur_slice_ = 0; 83 } 84 } 85 PERFETTO_DCHECK(Validate()); 86 return true; 87 } 88 ByteCount() const89google::protobuf::int64 SlicedProtobufInputStream::ByteCount() const { 90 PERFETTO_DCHECK(Validate()); 91 google::protobuf::int64 count = 0; 92 for (auto it = slices_->begin(); it != slices_->end(); it++) { 93 if (it == cur_slice_) { 94 count += static_cast<google::protobuf::int64>(pos_in_cur_slice_); 95 break; 96 } 97 count += static_cast<google::protobuf::int64>(it->size); 98 } 99 return count; 100 } 101 Validate() const102bool SlicedProtobufInputStream::Validate() const { 103 return ((cur_slice_ == slices_->end() && pos_in_cur_slice_ == 0) || 104 pos_in_cur_slice_ < cur_slice_->size || 105 (pos_in_cur_slice_ == 0 && cur_slice_->size == 0)); 106 } 107 108 } // namespace perfetto 109