| Alex Gough | 5033b85d | 2024-03-27 21:29:22 | [diff] [blame] | 1 | // Copyright 2024 The Chromium Authors |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "mojo/public/cpp/base/proto_wrapper.h" |
| 6 | |
| 7 | #include <limits> |
| 8 | |
| 9 | #include "base/check_op.h" |
| Tom Sepez | 84bfab3 | 2025-07-28 23:47:40 | [diff] [blame] | 10 | #include "base/compiler_specific.h" |
| Alex Gough | 5033b85d | 2024-03-27 21:29:22 | [diff] [blame] | 11 | #include "third_party/protobuf/src/google/protobuf/message_lite.h" |
| 12 | |
| 13 | namespace mojo_base { |
| 14 | |
| 15 | ProtoWrapper::ProtoWrapper() = default; |
| 16 | ProtoWrapper::ProtoWrapper(mojo::DefaultConstruct::Tag passkey) {} |
| 17 | ProtoWrapper::~ProtoWrapper() = default; |
| 18 | ProtoWrapper::ProtoWrapper(ProtoWrapper&& other) = default; |
| 19 | ProtoWrapper& ProtoWrapper::operator=(ProtoWrapper&& other) = default; |
| 20 | |
| 21 | ProtoWrapper::ProtoWrapper(const google::protobuf::MessageLite& message) { |
| 22 | proto_name_ = message.GetTypeName(); |
| 23 | CHECK(message.ByteSizeLong() <= std::numeric_limits<int>::max()); |
| 24 | bytes_ = BigBuffer(message.ByteSizeLong()); |
| 25 | CHECK(message.SerializeToArray(bytes_->data(), bytes_->size())); |
| 26 | } |
| 27 | |
| 28 | ProtoWrapper::ProtoWrapper(base::span<const uint8_t> data, |
| 29 | std::string type_name, |
| 30 | base::PassKey<ProtoWrapperBytes> passkey) { |
| 31 | CHECK(!type_name.empty()); |
| 32 | CHECK_GT(data.size(), 0u); |
| 33 | // Protobuf's unwrapping mechanisms take `int`. |
| 34 | CHECK_LT(data.size(), static_cast<size_t>(std::numeric_limits<int>::max())); |
| 35 | |
| 36 | bytes_ = BigBuffer(data); |
| 37 | proto_name_ = type_name; |
| 38 | } |
| 39 | |
| 40 | bool ProtoWrapper::DeserializeToMessage( |
| Joe Mason | a759465 | 2024-09-18 19:12:17 | [diff] [blame] | 41 | google::protobuf::MessageLite& message) const { |
| Alex Gough | 5033b85d | 2024-03-27 21:29:22 | [diff] [blame] | 42 | if (!bytes_.has_value()) { |
| 43 | return false; |
| 44 | } |
| 45 | // ProtoWrapper is either constructed from a message or from a mojom |
| 46 | // typemapping, so must have a typename. |
| 47 | if (message.GetTypeName() != proto_name_) { |
| 48 | return false; |
| 49 | } |
| 50 | // ParseFromArray can only take `int`. |
| 51 | if (bytes_->size() > std::numeric_limits<int>::max()) { |
| 52 | return false; |
| 53 | } |
| 54 | |
| 55 | if (bytes_->storage_type() == BigBuffer::StorageType::kBytes) { |
| 56 | return message.ParseFromArray(bytes_->data(), bytes_->size()); |
| 57 | } else { |
| 58 | // Make an in-process copy here as protobuf is not designed to |
| 59 | // safely parse data that might be changing underneath it. |
| Tom Sepez | 84bfab3 | 2025-07-28 23:47:40 | [diff] [blame] | 60 | auto as_span = UNSAFE_TODO(base::span(bytes_->data(), bytes_->size())); |
| Jose Dapena Paz | 0bed9a5 | 2024-04-16 10:59:08 | [diff] [blame] | 61 | const std::vector<uint8_t> copy(as_span.begin(), as_span.end()); |
| Alex Gough | 5033b85d | 2024-03-27 21:29:22 | [diff] [blame] | 62 | return message.ParseFromArray(copy.data(), copy.size()); |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | } // namespace mojo_base |