xref: /aosp_15_r20/external/pigweed/pw_protobuf/stream_decoder.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker // Copyright 2021 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker 
15*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/stream_decoder.h"
16*61c4878aSAndroid Build Coastguard Worker 
17*61c4878aSAndroid Build Coastguard Worker #include <algorithm>
18*61c4878aSAndroid Build Coastguard Worker #include <cstdint>
19*61c4878aSAndroid Build Coastguard Worker #include <cstring>
20*61c4878aSAndroid Build Coastguard Worker #include <limits>
21*61c4878aSAndroid Build Coastguard Worker #include <optional>
22*61c4878aSAndroid Build Coastguard Worker 
23*61c4878aSAndroid Build Coastguard Worker #include "pw_assert/assert.h"
24*61c4878aSAndroid Build Coastguard Worker #include "pw_assert/check.h"
25*61c4878aSAndroid Build Coastguard Worker #include "pw_bytes/bit.h"
26*61c4878aSAndroid Build Coastguard Worker #include "pw_containers/vector.h"
27*61c4878aSAndroid Build Coastguard Worker #include "pw_function/function.h"
28*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/encoder.h"
29*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/internal/codegen.h"
30*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/wire_format.h"
31*61c4878aSAndroid Build Coastguard Worker #include "pw_span/span.h"
32*61c4878aSAndroid Build Coastguard Worker #include "pw_status/status.h"
33*61c4878aSAndroid Build Coastguard Worker #include "pw_status/status_with_size.h"
34*61c4878aSAndroid Build Coastguard Worker #include "pw_status/try.h"
35*61c4878aSAndroid Build Coastguard Worker #include "pw_string/string.h"
36*61c4878aSAndroid Build Coastguard Worker #include "pw_varint/stream.h"
37*61c4878aSAndroid Build Coastguard Worker #include "pw_varint/varint.h"
38*61c4878aSAndroid Build Coastguard Worker 
39*61c4878aSAndroid Build Coastguard Worker namespace pw::protobuf {
40*61c4878aSAndroid Build Coastguard Worker 
41*61c4878aSAndroid Build Coastguard Worker using internal::VarintType;
42*61c4878aSAndroid Build Coastguard Worker 
DoSeek(ptrdiff_t offset,Whence origin)43*61c4878aSAndroid Build Coastguard Worker Status StreamDecoder::BytesReader::DoSeek(ptrdiff_t offset, Whence origin) {
44*61c4878aSAndroid Build Coastguard Worker   PW_TRY(status_);
45*61c4878aSAndroid Build Coastguard Worker   if (!decoder_.reader_.seekable()) {
46*61c4878aSAndroid Build Coastguard Worker     return Status::Unimplemented();
47*61c4878aSAndroid Build Coastguard Worker   }
48*61c4878aSAndroid Build Coastguard Worker 
49*61c4878aSAndroid Build Coastguard Worker   ptrdiff_t absolute_position = std::numeric_limits<ptrdiff_t>::min();
50*61c4878aSAndroid Build Coastguard Worker 
51*61c4878aSAndroid Build Coastguard Worker   // Convert from the position within the bytes field to the position within the
52*61c4878aSAndroid Build Coastguard Worker   // proto stream.
53*61c4878aSAndroid Build Coastguard Worker   switch (origin) {
54*61c4878aSAndroid Build Coastguard Worker     case Whence::kBeginning:
55*61c4878aSAndroid Build Coastguard Worker       absolute_position = start_offset_ + offset;
56*61c4878aSAndroid Build Coastguard Worker       break;
57*61c4878aSAndroid Build Coastguard Worker 
58*61c4878aSAndroid Build Coastguard Worker     case Whence::kCurrent:
59*61c4878aSAndroid Build Coastguard Worker       absolute_position = decoder_.position_ + offset;
60*61c4878aSAndroid Build Coastguard Worker       break;
61*61c4878aSAndroid Build Coastguard Worker 
62*61c4878aSAndroid Build Coastguard Worker     case Whence::kEnd:
63*61c4878aSAndroid Build Coastguard Worker       absolute_position = end_offset_ + offset;
64*61c4878aSAndroid Build Coastguard Worker       break;
65*61c4878aSAndroid Build Coastguard Worker   }
66*61c4878aSAndroid Build Coastguard Worker 
67*61c4878aSAndroid Build Coastguard Worker   if (absolute_position < 0) {
68*61c4878aSAndroid Build Coastguard Worker     return Status::InvalidArgument();
69*61c4878aSAndroid Build Coastguard Worker   }
70*61c4878aSAndroid Build Coastguard Worker 
71*61c4878aSAndroid Build Coastguard Worker   if (static_cast<size_t>(absolute_position) < start_offset_ ||
72*61c4878aSAndroid Build Coastguard Worker       static_cast<size_t>(absolute_position) > end_offset_) {
73*61c4878aSAndroid Build Coastguard Worker     return Status::OutOfRange();
74*61c4878aSAndroid Build Coastguard Worker   }
75*61c4878aSAndroid Build Coastguard Worker 
76*61c4878aSAndroid Build Coastguard Worker   PW_TRY(decoder_.reader_.Seek(absolute_position, Whence::kBeginning));
77*61c4878aSAndroid Build Coastguard Worker   decoder_.position_ = absolute_position;
78*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
79*61c4878aSAndroid Build Coastguard Worker }
80*61c4878aSAndroid Build Coastguard Worker 
DoRead(ByteSpan destination)81*61c4878aSAndroid Build Coastguard Worker StatusWithSize StreamDecoder::BytesReader::DoRead(ByteSpan destination) {
82*61c4878aSAndroid Build Coastguard Worker   if (!status_.ok()) {
83*61c4878aSAndroid Build Coastguard Worker     return StatusWithSize(status_, 0);
84*61c4878aSAndroid Build Coastguard Worker   }
85*61c4878aSAndroid Build Coastguard Worker 
86*61c4878aSAndroid Build Coastguard Worker   if (decoder_.position_ >= end_offset_ || decoder_.position_ < start_offset_) {
87*61c4878aSAndroid Build Coastguard Worker     return StatusWithSize::OutOfRange();
88*61c4878aSAndroid Build Coastguard Worker   }
89*61c4878aSAndroid Build Coastguard Worker 
90*61c4878aSAndroid Build Coastguard Worker   // Bound the read buffer to the size of the bytes field.
91*61c4878aSAndroid Build Coastguard Worker   size_t max_length = end_offset_ - decoder_.position_;
92*61c4878aSAndroid Build Coastguard Worker   if (destination.size() > max_length) {
93*61c4878aSAndroid Build Coastguard Worker     destination = destination.first(max_length);
94*61c4878aSAndroid Build Coastguard Worker   }
95*61c4878aSAndroid Build Coastguard Worker 
96*61c4878aSAndroid Build Coastguard Worker   Result<ByteSpan> result = decoder_.reader_.Read(destination);
97*61c4878aSAndroid Build Coastguard Worker   if (!result.ok()) {
98*61c4878aSAndroid Build Coastguard Worker     return StatusWithSize(result.status(), 0);
99*61c4878aSAndroid Build Coastguard Worker   }
100*61c4878aSAndroid Build Coastguard Worker 
101*61c4878aSAndroid Build Coastguard Worker   decoder_.position_ += result.value().size();
102*61c4878aSAndroid Build Coastguard Worker   return StatusWithSize(result.value().size());
103*61c4878aSAndroid Build Coastguard Worker }
104*61c4878aSAndroid Build Coastguard Worker 
~StreamDecoder()105*61c4878aSAndroid Build Coastguard Worker StreamDecoder::~StreamDecoder() {
106*61c4878aSAndroid Build Coastguard Worker   if (parent_ != nullptr) {
107*61c4878aSAndroid Build Coastguard Worker     parent_->CloseNestedDecoder(*this);
108*61c4878aSAndroid Build Coastguard Worker   } else if (stream_bounds_.high < std::numeric_limits<size_t>::max()) {
109*61c4878aSAndroid Build Coastguard Worker     if (status_.ok()) {
110*61c4878aSAndroid Build Coastguard Worker       // Advance the stream to the end of the bounds.
111*61c4878aSAndroid Build Coastguard Worker       PW_CHECK(Advance(stream_bounds_.high).ok());
112*61c4878aSAndroid Build Coastguard Worker     }
113*61c4878aSAndroid Build Coastguard Worker   }
114*61c4878aSAndroid Build Coastguard Worker }
115*61c4878aSAndroid Build Coastguard Worker 
Next()116*61c4878aSAndroid Build Coastguard Worker Status StreamDecoder::Next() {
117*61c4878aSAndroid Build Coastguard Worker   PW_CHECK(!nested_reader_open_,
118*61c4878aSAndroid Build Coastguard Worker            "Cannot use parent decoder while a nested one is open");
119*61c4878aSAndroid Build Coastguard Worker 
120*61c4878aSAndroid Build Coastguard Worker   PW_TRY(status_);
121*61c4878aSAndroid Build Coastguard Worker 
122*61c4878aSAndroid Build Coastguard Worker   if (!field_consumed_) {
123*61c4878aSAndroid Build Coastguard Worker     PW_TRY(SkipField());
124*61c4878aSAndroid Build Coastguard Worker   }
125*61c4878aSAndroid Build Coastguard Worker 
126*61c4878aSAndroid Build Coastguard Worker   if (position_ >= stream_bounds_.high) {
127*61c4878aSAndroid Build Coastguard Worker     return Status::OutOfRange();
128*61c4878aSAndroid Build Coastguard Worker   }
129*61c4878aSAndroid Build Coastguard Worker 
130*61c4878aSAndroid Build Coastguard Worker   status_ = ReadFieldKey();
131*61c4878aSAndroid Build Coastguard Worker   return status_;
132*61c4878aSAndroid Build Coastguard Worker }
133*61c4878aSAndroid Build Coastguard Worker 
GetBytesReader()134*61c4878aSAndroid Build Coastguard Worker StreamDecoder::BytesReader StreamDecoder::GetBytesReader() {
135*61c4878aSAndroid Build Coastguard Worker   Status status = CheckOkToRead(WireType::kDelimited);
136*61c4878aSAndroid Build Coastguard Worker 
137*61c4878aSAndroid Build Coastguard Worker   if (reader_.ConservativeReadLimit() < delimited_field_size_) {
138*61c4878aSAndroid Build Coastguard Worker     status.Update(Status::DataLoss());
139*61c4878aSAndroid Build Coastguard Worker   }
140*61c4878aSAndroid Build Coastguard Worker 
141*61c4878aSAndroid Build Coastguard Worker   nested_reader_open_ = true;
142*61c4878aSAndroid Build Coastguard Worker 
143*61c4878aSAndroid Build Coastguard Worker   if (!status.ok()) {
144*61c4878aSAndroid Build Coastguard Worker     return BytesReader(*this, status);
145*61c4878aSAndroid Build Coastguard Worker   }
146*61c4878aSAndroid Build Coastguard Worker 
147*61c4878aSAndroid Build Coastguard Worker   size_t low = position_;
148*61c4878aSAndroid Build Coastguard Worker   size_t high = low + delimited_field_size_;
149*61c4878aSAndroid Build Coastguard Worker 
150*61c4878aSAndroid Build Coastguard Worker   return BytesReader(*this, low, high);
151*61c4878aSAndroid Build Coastguard Worker }
152*61c4878aSAndroid Build Coastguard Worker 
GetNestedDecoder()153*61c4878aSAndroid Build Coastguard Worker StreamDecoder StreamDecoder::GetNestedDecoder() {
154*61c4878aSAndroid Build Coastguard Worker   Status status = CheckOkToRead(WireType::kDelimited);
155*61c4878aSAndroid Build Coastguard Worker 
156*61c4878aSAndroid Build Coastguard Worker   if (reader_.ConservativeReadLimit() < delimited_field_size_) {
157*61c4878aSAndroid Build Coastguard Worker     status.Update(Status::DataLoss());
158*61c4878aSAndroid Build Coastguard Worker   }
159*61c4878aSAndroid Build Coastguard Worker 
160*61c4878aSAndroid Build Coastguard Worker   nested_reader_open_ = true;
161*61c4878aSAndroid Build Coastguard Worker 
162*61c4878aSAndroid Build Coastguard Worker   if (!status.ok()) {
163*61c4878aSAndroid Build Coastguard Worker     return StreamDecoder(reader_, this, status);
164*61c4878aSAndroid Build Coastguard Worker   }
165*61c4878aSAndroid Build Coastguard Worker 
166*61c4878aSAndroid Build Coastguard Worker   size_t low = position_;
167*61c4878aSAndroid Build Coastguard Worker   size_t high = low + delimited_field_size_;
168*61c4878aSAndroid Build Coastguard Worker 
169*61c4878aSAndroid Build Coastguard Worker   return StreamDecoder(reader_, this, low, high);
170*61c4878aSAndroid Build Coastguard Worker }
171*61c4878aSAndroid Build Coastguard Worker 
Advance(size_t end_position)172*61c4878aSAndroid Build Coastguard Worker Status StreamDecoder::Advance(size_t end_position) {
173*61c4878aSAndroid Build Coastguard Worker   if (reader_.seekable()) {
174*61c4878aSAndroid Build Coastguard Worker     PW_TRY(reader_.Seek(end_position - position_, stream::Stream::kCurrent));
175*61c4878aSAndroid Build Coastguard Worker     position_ = end_position;
176*61c4878aSAndroid Build Coastguard Worker     return OkStatus();
177*61c4878aSAndroid Build Coastguard Worker   }
178*61c4878aSAndroid Build Coastguard Worker 
179*61c4878aSAndroid Build Coastguard Worker   while (position_ < end_position) {
180*61c4878aSAndroid Build Coastguard Worker     std::byte b;
181*61c4878aSAndroid Build Coastguard Worker     PW_TRY(reader_.Read(span(&b, 1)));
182*61c4878aSAndroid Build Coastguard Worker     position_++;
183*61c4878aSAndroid Build Coastguard Worker   }
184*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
185*61c4878aSAndroid Build Coastguard Worker }
186*61c4878aSAndroid Build Coastguard Worker 
CloseBytesReader(BytesReader & reader)187*61c4878aSAndroid Build Coastguard Worker void StreamDecoder::CloseBytesReader(BytesReader& reader) {
188*61c4878aSAndroid Build Coastguard Worker   status_ = reader.status_;
189*61c4878aSAndroid Build Coastguard Worker   if (status_.ok()) {
190*61c4878aSAndroid Build Coastguard Worker     // Advance the stream to the end of the bytes field.
191*61c4878aSAndroid Build Coastguard Worker     // The BytesReader already updated our position_ field as bytes were read.
192*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(Advance(reader.end_offset_).ok());
193*61c4878aSAndroid Build Coastguard Worker   }
194*61c4878aSAndroid Build Coastguard Worker 
195*61c4878aSAndroid Build Coastguard Worker   field_consumed_ = true;
196*61c4878aSAndroid Build Coastguard Worker   nested_reader_open_ = false;
197*61c4878aSAndroid Build Coastguard Worker }
198*61c4878aSAndroid Build Coastguard Worker 
CloseNestedDecoder(StreamDecoder & nested)199*61c4878aSAndroid Build Coastguard Worker void StreamDecoder::CloseNestedDecoder(StreamDecoder& nested) {
200*61c4878aSAndroid Build Coastguard Worker   PW_CHECK_PTR_EQ(nested.parent_, this);
201*61c4878aSAndroid Build Coastguard Worker 
202*61c4878aSAndroid Build Coastguard Worker   nested.nested_reader_open_ = true;
203*61c4878aSAndroid Build Coastguard Worker   nested.parent_ = nullptr;
204*61c4878aSAndroid Build Coastguard Worker 
205*61c4878aSAndroid Build Coastguard Worker   status_ = nested.status_;
206*61c4878aSAndroid Build Coastguard Worker   position_ = nested.position_;
207*61c4878aSAndroid Build Coastguard Worker   if (status_.ok()) {
208*61c4878aSAndroid Build Coastguard Worker     // Advance the stream to the end of the nested message field.
209*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(Advance(nested.stream_bounds_.high).ok());
210*61c4878aSAndroid Build Coastguard Worker   }
211*61c4878aSAndroid Build Coastguard Worker 
212*61c4878aSAndroid Build Coastguard Worker   field_consumed_ = true;
213*61c4878aSAndroid Build Coastguard Worker   nested_reader_open_ = false;
214*61c4878aSAndroid Build Coastguard Worker }
215*61c4878aSAndroid Build Coastguard Worker 
ReadFieldKey()216*61c4878aSAndroid Build Coastguard Worker Status StreamDecoder::ReadFieldKey() {
217*61c4878aSAndroid Build Coastguard Worker   PW_DCHECK(field_consumed_);
218*61c4878aSAndroid Build Coastguard Worker 
219*61c4878aSAndroid Build Coastguard Worker   uint64_t varint = 0;
220*61c4878aSAndroid Build Coastguard Worker   PW_TRY_ASSIGN(size_t bytes_read,
221*61c4878aSAndroid Build Coastguard Worker                 varint::Read(reader_, &varint, RemainingBytes()));
222*61c4878aSAndroid Build Coastguard Worker   position_ += bytes_read;
223*61c4878aSAndroid Build Coastguard Worker 
224*61c4878aSAndroid Build Coastguard Worker   if (!FieldKey::IsValidKey(varint)) {
225*61c4878aSAndroid Build Coastguard Worker     return Status::DataLoss();
226*61c4878aSAndroid Build Coastguard Worker   }
227*61c4878aSAndroid Build Coastguard Worker 
228*61c4878aSAndroid Build Coastguard Worker   PW_DCHECK(varint <= std::numeric_limits<uint32_t>::max());
229*61c4878aSAndroid Build Coastguard Worker   current_field_ = FieldKey(static_cast<uint32_t>(varint));
230*61c4878aSAndroid Build Coastguard Worker 
231*61c4878aSAndroid Build Coastguard Worker   if (current_field_.wire_type() == WireType::kDelimited) {
232*61c4878aSAndroid Build Coastguard Worker     // Read the length varint of length-delimited fields immediately to simplify
233*61c4878aSAndroid Build Coastguard Worker     // later processing of the field.
234*61c4878aSAndroid Build Coastguard Worker     StatusWithSize sws = varint::Read(reader_, &varint, RemainingBytes());
235*61c4878aSAndroid Build Coastguard Worker     position_ += sws.size();
236*61c4878aSAndroid Build Coastguard Worker     if (sws.IsOutOfRange()) {
237*61c4878aSAndroid Build Coastguard Worker       // Out of range indicates the end of the stream. As a value is expected
238*61c4878aSAndroid Build Coastguard Worker       // here, report it as a data loss and terminate the decode operation.
239*61c4878aSAndroid Build Coastguard Worker       return Status::DataLoss();
240*61c4878aSAndroid Build Coastguard Worker     }
241*61c4878aSAndroid Build Coastguard Worker     if (!sws.ok()) {
242*61c4878aSAndroid Build Coastguard Worker       return sws.status();
243*61c4878aSAndroid Build Coastguard Worker     }
244*61c4878aSAndroid Build Coastguard Worker 
245*61c4878aSAndroid Build Coastguard Worker     if (varint > std::numeric_limits<uint32_t>::max()) {
246*61c4878aSAndroid Build Coastguard Worker       return Status::DataLoss();
247*61c4878aSAndroid Build Coastguard Worker     }
248*61c4878aSAndroid Build Coastguard Worker 
249*61c4878aSAndroid Build Coastguard Worker     delimited_field_size_ = varint;
250*61c4878aSAndroid Build Coastguard Worker     delimited_field_offset_ = position_;
251*61c4878aSAndroid Build Coastguard Worker   }
252*61c4878aSAndroid Build Coastguard Worker 
253*61c4878aSAndroid Build Coastguard Worker   field_consumed_ = false;
254*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
255*61c4878aSAndroid Build Coastguard Worker }
256*61c4878aSAndroid Build Coastguard Worker 
GetLengthDelimitedPayloadBounds()257*61c4878aSAndroid Build Coastguard Worker Result<StreamDecoder::Bounds> StreamDecoder::GetLengthDelimitedPayloadBounds() {
258*61c4878aSAndroid Build Coastguard Worker   PW_TRY(CheckOkToRead(WireType::kDelimited));
259*61c4878aSAndroid Build Coastguard Worker   return StreamDecoder::Bounds{delimited_field_offset_,
260*61c4878aSAndroid Build Coastguard Worker                                delimited_field_size_ + delimited_field_offset_};
261*61c4878aSAndroid Build Coastguard Worker }
262*61c4878aSAndroid Build Coastguard Worker 
263*61c4878aSAndroid Build Coastguard Worker // Consumes the current protobuf field, advancing the stream to the key of the
264*61c4878aSAndroid Build Coastguard Worker // next field (if one exists).
SkipField()265*61c4878aSAndroid Build Coastguard Worker Status StreamDecoder::SkipField() {
266*61c4878aSAndroid Build Coastguard Worker   PW_DCHECK(!field_consumed_);
267*61c4878aSAndroid Build Coastguard Worker 
268*61c4878aSAndroid Build Coastguard Worker   size_t bytes_to_skip = 0;
269*61c4878aSAndroid Build Coastguard Worker   uint64_t value = 0;
270*61c4878aSAndroid Build Coastguard Worker 
271*61c4878aSAndroid Build Coastguard Worker   switch (current_field_.wire_type()) {
272*61c4878aSAndroid Build Coastguard Worker     case WireType::kVarint: {
273*61c4878aSAndroid Build Coastguard Worker       // Consume the varint field; nothing more to skip afterward.
274*61c4878aSAndroid Build Coastguard Worker       PW_TRY_ASSIGN(size_t bytes_read,
275*61c4878aSAndroid Build Coastguard Worker                     varint::Read(reader_, &value, RemainingBytes()));
276*61c4878aSAndroid Build Coastguard Worker       position_ += bytes_read;
277*61c4878aSAndroid Build Coastguard Worker       break;
278*61c4878aSAndroid Build Coastguard Worker     }
279*61c4878aSAndroid Build Coastguard Worker     case WireType::kDelimited:
280*61c4878aSAndroid Build Coastguard Worker       bytes_to_skip = delimited_field_size_;
281*61c4878aSAndroid Build Coastguard Worker       break;
282*61c4878aSAndroid Build Coastguard Worker 
283*61c4878aSAndroid Build Coastguard Worker     case WireType::kFixed32:
284*61c4878aSAndroid Build Coastguard Worker       bytes_to_skip = sizeof(uint32_t);
285*61c4878aSAndroid Build Coastguard Worker       break;
286*61c4878aSAndroid Build Coastguard Worker 
287*61c4878aSAndroid Build Coastguard Worker     case WireType::kFixed64:
288*61c4878aSAndroid Build Coastguard Worker       bytes_to_skip = sizeof(uint64_t);
289*61c4878aSAndroid Build Coastguard Worker       break;
290*61c4878aSAndroid Build Coastguard Worker   }
291*61c4878aSAndroid Build Coastguard Worker 
292*61c4878aSAndroid Build Coastguard Worker   if (bytes_to_skip > 0) {
293*61c4878aSAndroid Build Coastguard Worker     // Check if the stream has the field available. If not, report it as a
294*61c4878aSAndroid Build Coastguard Worker     // DATA_LOSS since the proto is invalid (as opposed to OUT_OF_BOUNDS if we
295*61c4878aSAndroid Build Coastguard Worker     // just tried to seek beyond the end).
296*61c4878aSAndroid Build Coastguard Worker     if (reader_.ConservativeReadLimit() < bytes_to_skip) {
297*61c4878aSAndroid Build Coastguard Worker       status_ = Status::DataLoss();
298*61c4878aSAndroid Build Coastguard Worker       return status_;
299*61c4878aSAndroid Build Coastguard Worker     }
300*61c4878aSAndroid Build Coastguard Worker 
301*61c4878aSAndroid Build Coastguard Worker     if (RemainingBytes() < bytes_to_skip) {
302*61c4878aSAndroid Build Coastguard Worker       status_ = Status::DataLoss();
303*61c4878aSAndroid Build Coastguard Worker       return status_;
304*61c4878aSAndroid Build Coastguard Worker     }
305*61c4878aSAndroid Build Coastguard Worker 
306*61c4878aSAndroid Build Coastguard Worker     PW_TRY(Advance(position_ + bytes_to_skip));
307*61c4878aSAndroid Build Coastguard Worker   }
308*61c4878aSAndroid Build Coastguard Worker 
309*61c4878aSAndroid Build Coastguard Worker   field_consumed_ = true;
310*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
311*61c4878aSAndroid Build Coastguard Worker }
312*61c4878aSAndroid Build Coastguard Worker 
ReadVarintField(span<std::byte> out,VarintType decode_type)313*61c4878aSAndroid Build Coastguard Worker Status StreamDecoder::ReadVarintField(span<std::byte> out,
314*61c4878aSAndroid Build Coastguard Worker                                       VarintType decode_type) {
315*61c4878aSAndroid Build Coastguard Worker   PW_CHECK(out.size() == sizeof(bool) || out.size() == sizeof(uint32_t) ||
316*61c4878aSAndroid Build Coastguard Worker                out.size() == sizeof(uint64_t),
317*61c4878aSAndroid Build Coastguard Worker            "Protobuf varints must only be used with bool, int32_t, uint32_t, "
318*61c4878aSAndroid Build Coastguard Worker            "int64_t, or uint64_t");
319*61c4878aSAndroid Build Coastguard Worker   PW_TRY(CheckOkToRead(WireType::kVarint));
320*61c4878aSAndroid Build Coastguard Worker 
321*61c4878aSAndroid Build Coastguard Worker   const StatusWithSize sws = ReadOneVarint(out, decode_type);
322*61c4878aSAndroid Build Coastguard Worker   if (sws.status() != Status::DataLoss())
323*61c4878aSAndroid Build Coastguard Worker     field_consumed_ = true;
324*61c4878aSAndroid Build Coastguard Worker   return sws.status();
325*61c4878aSAndroid Build Coastguard Worker }
326*61c4878aSAndroid Build Coastguard Worker 
ReadOneVarint(span<std::byte> out,VarintType decode_type)327*61c4878aSAndroid Build Coastguard Worker StatusWithSize StreamDecoder::ReadOneVarint(span<std::byte> out,
328*61c4878aSAndroid Build Coastguard Worker                                             VarintType decode_type) {
329*61c4878aSAndroid Build Coastguard Worker   uint64_t value;
330*61c4878aSAndroid Build Coastguard Worker   StatusWithSize sws = varint::Read(reader_, &value, RemainingBytes());
331*61c4878aSAndroid Build Coastguard Worker   position_ += sws.size();
332*61c4878aSAndroid Build Coastguard Worker   if (sws.IsOutOfRange()) {
333*61c4878aSAndroid Build Coastguard Worker     // Out of range indicates the end of the stream. As a value is expected
334*61c4878aSAndroid Build Coastguard Worker     // here, report it as a data loss and terminate the decode operation.
335*61c4878aSAndroid Build Coastguard Worker     status_ = Status::DataLoss();
336*61c4878aSAndroid Build Coastguard Worker     return StatusWithSize(status_, sws.size());
337*61c4878aSAndroid Build Coastguard Worker   }
338*61c4878aSAndroid Build Coastguard Worker   if (!sws.ok()) {
339*61c4878aSAndroid Build Coastguard Worker     return sws;
340*61c4878aSAndroid Build Coastguard Worker   }
341*61c4878aSAndroid Build Coastguard Worker 
342*61c4878aSAndroid Build Coastguard Worker   if (out.size() == sizeof(uint64_t)) {
343*61c4878aSAndroid Build Coastguard Worker     if (decode_type == VarintType::kUnsigned) {
344*61c4878aSAndroid Build Coastguard Worker       std::memcpy(out.data(), &value, out.size());
345*61c4878aSAndroid Build Coastguard Worker     } else {
346*61c4878aSAndroid Build Coastguard Worker       const int64_t signed_value = decode_type == VarintType::kZigZag
347*61c4878aSAndroid Build Coastguard Worker                                        ? varint::ZigZagDecode(value)
348*61c4878aSAndroid Build Coastguard Worker                                        : static_cast<int64_t>(value);
349*61c4878aSAndroid Build Coastguard Worker       std::memcpy(out.data(), &signed_value, out.size());
350*61c4878aSAndroid Build Coastguard Worker     }
351*61c4878aSAndroid Build Coastguard Worker   } else if (out.size() == sizeof(uint32_t)) {
352*61c4878aSAndroid Build Coastguard Worker     if (decode_type == VarintType::kUnsigned) {
353*61c4878aSAndroid Build Coastguard Worker       if (value > std::numeric_limits<uint32_t>::max()) {
354*61c4878aSAndroid Build Coastguard Worker         return StatusWithSize(Status::FailedPrecondition(), sws.size());
355*61c4878aSAndroid Build Coastguard Worker       }
356*61c4878aSAndroid Build Coastguard Worker       std::memcpy(out.data(), &value, out.size());
357*61c4878aSAndroid Build Coastguard Worker     } else {
358*61c4878aSAndroid Build Coastguard Worker       const int64_t signed_value = decode_type == VarintType::kZigZag
359*61c4878aSAndroid Build Coastguard Worker                                        ? varint::ZigZagDecode(value)
360*61c4878aSAndroid Build Coastguard Worker                                        : static_cast<int64_t>(value);
361*61c4878aSAndroid Build Coastguard Worker       if (signed_value > std::numeric_limits<int32_t>::max() ||
362*61c4878aSAndroid Build Coastguard Worker           signed_value < std::numeric_limits<int32_t>::min()) {
363*61c4878aSAndroid Build Coastguard Worker         return StatusWithSize(Status::FailedPrecondition(), sws.size());
364*61c4878aSAndroid Build Coastguard Worker       }
365*61c4878aSAndroid Build Coastguard Worker       std::memcpy(out.data(), &signed_value, out.size());
366*61c4878aSAndroid Build Coastguard Worker     }
367*61c4878aSAndroid Build Coastguard Worker   } else if (out.size() == sizeof(bool)) {
368*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(decode_type == VarintType::kUnsigned,
369*61c4878aSAndroid Build Coastguard Worker              "Protobuf bool can never be signed");
370*61c4878aSAndroid Build Coastguard Worker     std::memcpy(out.data(), &value, out.size());
371*61c4878aSAndroid Build Coastguard Worker   }
372*61c4878aSAndroid Build Coastguard Worker 
373*61c4878aSAndroid Build Coastguard Worker   return sws;
374*61c4878aSAndroid Build Coastguard Worker }
375*61c4878aSAndroid Build Coastguard Worker 
ReadFixedField(span<std::byte> out)376*61c4878aSAndroid Build Coastguard Worker Status StreamDecoder::ReadFixedField(span<std::byte> out) {
377*61c4878aSAndroid Build Coastguard Worker   WireType expected_wire_type =
378*61c4878aSAndroid Build Coastguard Worker       out.size() == sizeof(uint32_t) ? WireType::kFixed32 : WireType::kFixed64;
379*61c4878aSAndroid Build Coastguard Worker   PW_TRY(CheckOkToRead(expected_wire_type));
380*61c4878aSAndroid Build Coastguard Worker 
381*61c4878aSAndroid Build Coastguard Worker   if (reader_.ConservativeReadLimit() < out.size()) {
382*61c4878aSAndroid Build Coastguard Worker     status_ = Status::DataLoss();
383*61c4878aSAndroid Build Coastguard Worker     return status_;
384*61c4878aSAndroid Build Coastguard Worker   }
385*61c4878aSAndroid Build Coastguard Worker 
386*61c4878aSAndroid Build Coastguard Worker   if (RemainingBytes() < out.size()) {
387*61c4878aSAndroid Build Coastguard Worker     status_ = Status::DataLoss();
388*61c4878aSAndroid Build Coastguard Worker     return status_;
389*61c4878aSAndroid Build Coastguard Worker   }
390*61c4878aSAndroid Build Coastguard Worker 
391*61c4878aSAndroid Build Coastguard Worker   PW_TRY(reader_.Read(out));
392*61c4878aSAndroid Build Coastguard Worker   position_ += out.size();
393*61c4878aSAndroid Build Coastguard Worker   field_consumed_ = true;
394*61c4878aSAndroid Build Coastguard Worker 
395*61c4878aSAndroid Build Coastguard Worker   if (endian::native != endian::little) {
396*61c4878aSAndroid Build Coastguard Worker     std::reverse(out.begin(), out.end());
397*61c4878aSAndroid Build Coastguard Worker   }
398*61c4878aSAndroid Build Coastguard Worker 
399*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
400*61c4878aSAndroid Build Coastguard Worker }
401*61c4878aSAndroid Build Coastguard Worker 
ReadDelimitedField(span<std::byte> out)402*61c4878aSAndroid Build Coastguard Worker StatusWithSize StreamDecoder::ReadDelimitedField(span<std::byte> out) {
403*61c4878aSAndroid Build Coastguard Worker   if (Status status = CheckOkToRead(WireType::kDelimited); !status.ok()) {
404*61c4878aSAndroid Build Coastguard Worker     return StatusWithSize(status, 0);
405*61c4878aSAndroid Build Coastguard Worker   }
406*61c4878aSAndroid Build Coastguard Worker 
407*61c4878aSAndroid Build Coastguard Worker   if (reader_.ConservativeReadLimit() < delimited_field_size_) {
408*61c4878aSAndroid Build Coastguard Worker     status_ = Status::DataLoss();
409*61c4878aSAndroid Build Coastguard Worker     return StatusWithSize(status_, 0);
410*61c4878aSAndroid Build Coastguard Worker   }
411*61c4878aSAndroid Build Coastguard Worker 
412*61c4878aSAndroid Build Coastguard Worker   if (out.size() < delimited_field_size_) {
413*61c4878aSAndroid Build Coastguard Worker     // Value can't fit into the provided buffer. Don't advance the cursor so
414*61c4878aSAndroid Build Coastguard Worker     // that the field can be re-read with a larger buffer or through the stream
415*61c4878aSAndroid Build Coastguard Worker     // API.
416*61c4878aSAndroid Build Coastguard Worker     return StatusWithSize::ResourceExhausted();
417*61c4878aSAndroid Build Coastguard Worker   }
418*61c4878aSAndroid Build Coastguard Worker 
419*61c4878aSAndroid Build Coastguard Worker   Result<ByteSpan> result = reader_.Read(out.first(delimited_field_size_));
420*61c4878aSAndroid Build Coastguard Worker   if (!result.ok()) {
421*61c4878aSAndroid Build Coastguard Worker     return StatusWithSize(result.status(), 0);
422*61c4878aSAndroid Build Coastguard Worker   }
423*61c4878aSAndroid Build Coastguard Worker 
424*61c4878aSAndroid Build Coastguard Worker   position_ += result.value().size();
425*61c4878aSAndroid Build Coastguard Worker   field_consumed_ = true;
426*61c4878aSAndroid Build Coastguard Worker   return StatusWithSize(result.value().size());
427*61c4878aSAndroid Build Coastguard Worker }
428*61c4878aSAndroid Build Coastguard Worker 
ReadPackedFixedField(span<std::byte> out,size_t elem_size)429*61c4878aSAndroid Build Coastguard Worker StatusWithSize StreamDecoder::ReadPackedFixedField(span<std::byte> out,
430*61c4878aSAndroid Build Coastguard Worker                                                    size_t elem_size) {
431*61c4878aSAndroid Build Coastguard Worker   if (Status status = CheckOkToRead(WireType::kDelimited); !status.ok()) {
432*61c4878aSAndroid Build Coastguard Worker     return StatusWithSize(status, 0);
433*61c4878aSAndroid Build Coastguard Worker   }
434*61c4878aSAndroid Build Coastguard Worker 
435*61c4878aSAndroid Build Coastguard Worker   if (reader_.ConservativeReadLimit() < delimited_field_size_) {
436*61c4878aSAndroid Build Coastguard Worker     status_ = Status::DataLoss();
437*61c4878aSAndroid Build Coastguard Worker     return StatusWithSize(status_, 0);
438*61c4878aSAndroid Build Coastguard Worker   }
439*61c4878aSAndroid Build Coastguard Worker 
440*61c4878aSAndroid Build Coastguard Worker   if (out.size() < delimited_field_size_) {
441*61c4878aSAndroid Build Coastguard Worker     // Value can't fit into the provided buffer. Don't advance the cursor so
442*61c4878aSAndroid Build Coastguard Worker     // that the field can be re-read with a larger buffer or through the stream
443*61c4878aSAndroid Build Coastguard Worker     // API.
444*61c4878aSAndroid Build Coastguard Worker     return StatusWithSize::ResourceExhausted();
445*61c4878aSAndroid Build Coastguard Worker   }
446*61c4878aSAndroid Build Coastguard Worker 
447*61c4878aSAndroid Build Coastguard Worker   Result<ByteSpan> result = reader_.Read(out.first(delimited_field_size_));
448*61c4878aSAndroid Build Coastguard Worker   if (!result.ok()) {
449*61c4878aSAndroid Build Coastguard Worker     return StatusWithSize(result.status(), 0);
450*61c4878aSAndroid Build Coastguard Worker   }
451*61c4878aSAndroid Build Coastguard Worker 
452*61c4878aSAndroid Build Coastguard Worker   position_ += result.value().size();
453*61c4878aSAndroid Build Coastguard Worker   field_consumed_ = true;
454*61c4878aSAndroid Build Coastguard Worker 
455*61c4878aSAndroid Build Coastguard Worker   // Decode little-endian serialized packed fields.
456*61c4878aSAndroid Build Coastguard Worker   if (endian::native != endian::little) {
457*61c4878aSAndroid Build Coastguard Worker     for (auto out_start = out.begin(); out_start != out.end();
458*61c4878aSAndroid Build Coastguard Worker          out_start += elem_size) {
459*61c4878aSAndroid Build Coastguard Worker       std::reverse(out_start, out_start + elem_size);
460*61c4878aSAndroid Build Coastguard Worker     }
461*61c4878aSAndroid Build Coastguard Worker   }
462*61c4878aSAndroid Build Coastguard Worker 
463*61c4878aSAndroid Build Coastguard Worker   return StatusWithSize(result.value().size() / elem_size);
464*61c4878aSAndroid Build Coastguard Worker }
465*61c4878aSAndroid Build Coastguard Worker 
ReadPackedVarintField(span<std::byte> out,size_t elem_size,VarintType decode_type)466*61c4878aSAndroid Build Coastguard Worker StatusWithSize StreamDecoder::ReadPackedVarintField(span<std::byte> out,
467*61c4878aSAndroid Build Coastguard Worker                                                     size_t elem_size,
468*61c4878aSAndroid Build Coastguard Worker                                                     VarintType decode_type) {
469*61c4878aSAndroid Build Coastguard Worker   PW_CHECK(elem_size == sizeof(bool) || elem_size == sizeof(uint32_t) ||
470*61c4878aSAndroid Build Coastguard Worker                elem_size == sizeof(uint64_t),
471*61c4878aSAndroid Build Coastguard Worker            "Protobuf varints must only be used with bool, int32_t, uint32_t, "
472*61c4878aSAndroid Build Coastguard Worker            "int64_t, or uint64_t");
473*61c4878aSAndroid Build Coastguard Worker 
474*61c4878aSAndroid Build Coastguard Worker   if (Status status = CheckOkToRead(WireType::kDelimited); !status.ok()) {
475*61c4878aSAndroid Build Coastguard Worker     return StatusWithSize(status, 0);
476*61c4878aSAndroid Build Coastguard Worker   }
477*61c4878aSAndroid Build Coastguard Worker 
478*61c4878aSAndroid Build Coastguard Worker   if (reader_.ConservativeReadLimit() < delimited_field_size_) {
479*61c4878aSAndroid Build Coastguard Worker     status_ = Status::DataLoss();
480*61c4878aSAndroid Build Coastguard Worker     return StatusWithSize(status_, 0);
481*61c4878aSAndroid Build Coastguard Worker   }
482*61c4878aSAndroid Build Coastguard Worker 
483*61c4878aSAndroid Build Coastguard Worker   size_t bytes_read = 0;
484*61c4878aSAndroid Build Coastguard Worker   size_t number_out = 0;
485*61c4878aSAndroid Build Coastguard Worker   while (bytes_read < delimited_field_size_ && !out.empty()) {
486*61c4878aSAndroid Build Coastguard Worker     const StatusWithSize sws = ReadOneVarint(out.first(elem_size), decode_type);
487*61c4878aSAndroid Build Coastguard Worker     if (!sws.ok()) {
488*61c4878aSAndroid Build Coastguard Worker       return StatusWithSize(sws.status(), number_out);
489*61c4878aSAndroid Build Coastguard Worker     }
490*61c4878aSAndroid Build Coastguard Worker 
491*61c4878aSAndroid Build Coastguard Worker     bytes_read += sws.size();
492*61c4878aSAndroid Build Coastguard Worker     out = out.subspan(elem_size);
493*61c4878aSAndroid Build Coastguard Worker     ++number_out;
494*61c4878aSAndroid Build Coastguard Worker   }
495*61c4878aSAndroid Build Coastguard Worker 
496*61c4878aSAndroid Build Coastguard Worker   if (bytes_read < delimited_field_size_) {
497*61c4878aSAndroid Build Coastguard Worker     return StatusWithSize(Status::ResourceExhausted(), number_out);
498*61c4878aSAndroid Build Coastguard Worker   }
499*61c4878aSAndroid Build Coastguard Worker 
500*61c4878aSAndroid Build Coastguard Worker   field_consumed_ = true;
501*61c4878aSAndroid Build Coastguard Worker   return StatusWithSize(OkStatus(), number_out);
502*61c4878aSAndroid Build Coastguard Worker }
503*61c4878aSAndroid Build Coastguard Worker 
CheckOkToRead(WireType type)504*61c4878aSAndroid Build Coastguard Worker Status StreamDecoder::CheckOkToRead(WireType type) {
505*61c4878aSAndroid Build Coastguard Worker   PW_CHECK(!nested_reader_open_,
506*61c4878aSAndroid Build Coastguard Worker            "Cannot read from a decoder while a nested decoder is open");
507*61c4878aSAndroid Build Coastguard Worker   PW_CHECK(!field_consumed_,
508*61c4878aSAndroid Build Coastguard Worker            "Attempting to read from protobuf decoder without first calling "
509*61c4878aSAndroid Build Coastguard Worker            "Next()");
510*61c4878aSAndroid Build Coastguard Worker 
511*61c4878aSAndroid Build Coastguard Worker   // Attempting to read the wrong type is typically a programmer error;
512*61c4878aSAndroid Build Coastguard Worker   // however, it could also occur due to data corruption. As we don't want to
513*61c4878aSAndroid Build Coastguard Worker   // crash on bad data, return NOT_FOUND here to distinguish it from other
514*61c4878aSAndroid Build Coastguard Worker   // corruption cases.
515*61c4878aSAndroid Build Coastguard Worker   if (current_field_.wire_type() != type) {
516*61c4878aSAndroid Build Coastguard Worker     status_ = Status::NotFound();
517*61c4878aSAndroid Build Coastguard Worker   }
518*61c4878aSAndroid Build Coastguard Worker 
519*61c4878aSAndroid Build Coastguard Worker   return status_;
520*61c4878aSAndroid Build Coastguard Worker }
521*61c4878aSAndroid Build Coastguard Worker 
Read(span<std::byte> message,span<const internal::MessageField> table)522*61c4878aSAndroid Build Coastguard Worker Status StreamDecoder::Read(span<std::byte> message,
523*61c4878aSAndroid Build Coastguard Worker                            span<const internal::MessageField> table) {
524*61c4878aSAndroid Build Coastguard Worker   PW_TRY(status_);
525*61c4878aSAndroid Build Coastguard Worker 
526*61c4878aSAndroid Build Coastguard Worker   while (Next().ok()) {
527*61c4878aSAndroid Build Coastguard Worker     // Find the field in the table,
528*61c4878aSAndroid Build Coastguard Worker     // TODO: b/234876102 - Finding the field can be made more efficient.
529*61c4878aSAndroid Build Coastguard Worker     const auto field =
530*61c4878aSAndroid Build Coastguard Worker         std::find(table.begin(), table.end(), current_field_.field_number());
531*61c4878aSAndroid Build Coastguard Worker     if (field == table.end()) {
532*61c4878aSAndroid Build Coastguard Worker       // If the field is not found, skip to the next one.
533*61c4878aSAndroid Build Coastguard Worker       // TODO: b/234873295 - Provide a way to allow the caller to inspect
534*61c4878aSAndroid Build Coastguard Worker       // unknown fields, and serialize them back out later.
535*61c4878aSAndroid Build Coastguard Worker       continue;
536*61c4878aSAndroid Build Coastguard Worker     }
537*61c4878aSAndroid Build Coastguard Worker 
538*61c4878aSAndroid Build Coastguard Worker     // Calculate the span of bytes corresponding to the structure field to
539*61c4878aSAndroid Build Coastguard Worker     // output into.
540*61c4878aSAndroid Build Coastguard Worker     const auto out =
541*61c4878aSAndroid Build Coastguard Worker         message.subspan(field->field_offset(), field->field_size());
542*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(out.begin() >= message.begin() && out.end() <= message.end());
543*61c4878aSAndroid Build Coastguard Worker 
544*61c4878aSAndroid Build Coastguard Worker     // If the field is using callbacks, interpret the output field accordingly
545*61c4878aSAndroid Build Coastguard Worker     // and allow the caller to provide custom handling.
546*61c4878aSAndroid Build Coastguard Worker     if (field->callback_type() == internal::CallbackType::kSingleField) {
547*61c4878aSAndroid Build Coastguard Worker       const Callback<StreamEncoder, StreamDecoder>* callback =
548*61c4878aSAndroid Build Coastguard Worker           reinterpret_cast<const Callback<StreamEncoder, StreamDecoder>*>(
549*61c4878aSAndroid Build Coastguard Worker               out.data());
550*61c4878aSAndroid Build Coastguard Worker       PW_TRY(callback->Decode(*this));
551*61c4878aSAndroid Build Coastguard Worker       continue;
552*61c4878aSAndroid Build Coastguard Worker     }
553*61c4878aSAndroid Build Coastguard Worker     if (field->callback_type() == internal::CallbackType::kOneOfGroup) {
554*61c4878aSAndroid Build Coastguard Worker       const OneOf<StreamEncoder, StreamDecoder>* callback =
555*61c4878aSAndroid Build Coastguard Worker           reinterpret_cast<const OneOf<StreamEncoder, StreamDecoder>*>(
556*61c4878aSAndroid Build Coastguard Worker               out.data());
557*61c4878aSAndroid Build Coastguard Worker       PW_TRY(callback->Decode(
558*61c4878aSAndroid Build Coastguard Worker           static_cast<NullFields>(current_field_.field_number()), *this));
559*61c4878aSAndroid Build Coastguard Worker       continue;
560*61c4878aSAndroid Build Coastguard Worker     }
561*61c4878aSAndroid Build Coastguard Worker 
562*61c4878aSAndroid Build Coastguard Worker     // Switch on the expected wire type of the field, not the actual, to ensure
563*61c4878aSAndroid Build Coastguard Worker     // the remote encoder doesn't influence our decoding unexpectedly.
564*61c4878aSAndroid Build Coastguard Worker     switch (field->wire_type()) {
565*61c4878aSAndroid Build Coastguard Worker       case WireType::kFixed64:
566*61c4878aSAndroid Build Coastguard Worker       case WireType::kFixed32: {
567*61c4878aSAndroid Build Coastguard Worker         // Fixed fields call ReadFixedField() for singular case, and either
568*61c4878aSAndroid Build Coastguard Worker         // ReadPackedFixedField() or ReadRepeatedFixedField() for repeated
569*61c4878aSAndroid Build Coastguard Worker         // fields.
570*61c4878aSAndroid Build Coastguard Worker         PW_CHECK(field->elem_size() == (field->wire_type() == WireType::kFixed32
571*61c4878aSAndroid Build Coastguard Worker                                             ? sizeof(uint32_t)
572*61c4878aSAndroid Build Coastguard Worker                                             : sizeof(uint64_t)),
573*61c4878aSAndroid Build Coastguard Worker                  "Mismatched message field type and size");
574*61c4878aSAndroid Build Coastguard Worker         if (field->is_fixed_size()) {
575*61c4878aSAndroid Build Coastguard Worker           PW_CHECK(field->is_repeated(), "Non-repeated fixed size field");
576*61c4878aSAndroid Build Coastguard Worker           PW_TRY(ReadPackedFixedField(out, field->elem_size()));
577*61c4878aSAndroid Build Coastguard Worker         } else if (field->is_repeated()) {
578*61c4878aSAndroid Build Coastguard Worker           // The struct member for this field is a vector of a type
579*61c4878aSAndroid Build Coastguard Worker           // corresponding to the field element size. Cast to the correct
580*61c4878aSAndroid Build Coastguard Worker           // vector type so we're not performing type aliasing (except for
581*61c4878aSAndroid Build Coastguard Worker           // unsigned vs signed which is explicitly allowed).
582*61c4878aSAndroid Build Coastguard Worker           if (field->elem_size() == sizeof(uint64_t)) {
583*61c4878aSAndroid Build Coastguard Worker             auto* vector = reinterpret_cast<pw::Vector<uint64_t>*>(out.data());
584*61c4878aSAndroid Build Coastguard Worker             PW_TRY(ReadRepeatedFixedField(*vector));
585*61c4878aSAndroid Build Coastguard Worker           } else if (field->elem_size() == sizeof(uint32_t)) {
586*61c4878aSAndroid Build Coastguard Worker             auto* vector = reinterpret_cast<pw::Vector<uint32_t>*>(out.data());
587*61c4878aSAndroid Build Coastguard Worker             PW_TRY(ReadRepeatedFixedField(*vector));
588*61c4878aSAndroid Build Coastguard Worker           }
589*61c4878aSAndroid Build Coastguard Worker         } else if (field->is_optional()) {
590*61c4878aSAndroid Build Coastguard Worker           // The struct member for this field is a std::optional of a type
591*61c4878aSAndroid Build Coastguard Worker           // corresponding to the field element size. Cast to the correct
592*61c4878aSAndroid Build Coastguard Worker           // optional type so we're not performing type aliasing (except for
593*61c4878aSAndroid Build Coastguard Worker           // unsigned vs signed which is explicitly allowed), and assign through
594*61c4878aSAndroid Build Coastguard Worker           // a temporary.
595*61c4878aSAndroid Build Coastguard Worker           if (field->elem_size() == sizeof(uint64_t)) {
596*61c4878aSAndroid Build Coastguard Worker             uint64_t value = 0;
597*61c4878aSAndroid Build Coastguard Worker             PW_TRY(ReadFixedField(as_writable_bytes(span(&value, 1))));
598*61c4878aSAndroid Build Coastguard Worker             auto* optional =
599*61c4878aSAndroid Build Coastguard Worker                 reinterpret_cast<std::optional<uint64_t>*>(out.data());
600*61c4878aSAndroid Build Coastguard Worker             *optional = value;
601*61c4878aSAndroid Build Coastguard Worker           } else if (field->elem_size() == sizeof(uint32_t)) {
602*61c4878aSAndroid Build Coastguard Worker             uint32_t value = 0;
603*61c4878aSAndroid Build Coastguard Worker             PW_TRY(ReadFixedField(as_writable_bytes(span(&value, 1))));
604*61c4878aSAndroid Build Coastguard Worker             auto* optional =
605*61c4878aSAndroid Build Coastguard Worker                 reinterpret_cast<std::optional<uint32_t>*>(out.data());
606*61c4878aSAndroid Build Coastguard Worker             *optional = value;
607*61c4878aSAndroid Build Coastguard Worker           }
608*61c4878aSAndroid Build Coastguard Worker         } else {
609*61c4878aSAndroid Build Coastguard Worker           PW_CHECK(out.size() == field->elem_size(),
610*61c4878aSAndroid Build Coastguard Worker                    "Mismatched message field type and size");
611*61c4878aSAndroid Build Coastguard Worker           PW_TRY(ReadFixedField(out));
612*61c4878aSAndroid Build Coastguard Worker         }
613*61c4878aSAndroid Build Coastguard Worker         break;
614*61c4878aSAndroid Build Coastguard Worker       }
615*61c4878aSAndroid Build Coastguard Worker       case WireType::kVarint: {
616*61c4878aSAndroid Build Coastguard Worker         // Varint fields call ReadVarintField() for singular case, and either
617*61c4878aSAndroid Build Coastguard Worker         // ReadPackedVarintField() or ReadRepeatedVarintField() for repeated
618*61c4878aSAndroid Build Coastguard Worker         // fields.
619*61c4878aSAndroid Build Coastguard Worker         PW_CHECK(field->elem_size() == sizeof(uint64_t) ||
620*61c4878aSAndroid Build Coastguard Worker                      field->elem_size() == sizeof(uint32_t) ||
621*61c4878aSAndroid Build Coastguard Worker                      field->elem_size() == sizeof(bool),
622*61c4878aSAndroid Build Coastguard Worker                  "Mismatched message field type and size");
623*61c4878aSAndroid Build Coastguard Worker         if (field->is_fixed_size()) {
624*61c4878aSAndroid Build Coastguard Worker           PW_CHECK(field->is_repeated(), "Non-repeated fixed size field");
625*61c4878aSAndroid Build Coastguard Worker           PW_TRY(ReadPackedVarintField(
626*61c4878aSAndroid Build Coastguard Worker               out, field->elem_size(), field->varint_type()));
627*61c4878aSAndroid Build Coastguard Worker         } else if (field->is_repeated()) {
628*61c4878aSAndroid Build Coastguard Worker           // The struct member for this field is a vector of a type
629*61c4878aSAndroid Build Coastguard Worker           // corresponding to the field element size. Cast to the correct
630*61c4878aSAndroid Build Coastguard Worker           // vector type so we're not performing type aliasing (except for
631*61c4878aSAndroid Build Coastguard Worker           // unsigned vs signed which is explicitly allowed).
632*61c4878aSAndroid Build Coastguard Worker           if (field->elem_size() == sizeof(uint64_t)) {
633*61c4878aSAndroid Build Coastguard Worker             auto* vector = reinterpret_cast<pw::Vector<uint64_t>*>(out.data());
634*61c4878aSAndroid Build Coastguard Worker             PW_TRY(ReadRepeatedVarintField(*vector, field->varint_type()));
635*61c4878aSAndroid Build Coastguard Worker           } else if (field->elem_size() == sizeof(uint32_t)) {
636*61c4878aSAndroid Build Coastguard Worker             auto* vector = reinterpret_cast<pw::Vector<uint32_t>*>(out.data());
637*61c4878aSAndroid Build Coastguard Worker             PW_TRY(ReadRepeatedVarintField(*vector, field->varint_type()));
638*61c4878aSAndroid Build Coastguard Worker           } else if (field->elem_size() == sizeof(bool)) {
639*61c4878aSAndroid Build Coastguard Worker             auto* vector = reinterpret_cast<pw::Vector<bool>*>(out.data());
640*61c4878aSAndroid Build Coastguard Worker             PW_TRY(ReadRepeatedVarintField(*vector, field->varint_type()));
641*61c4878aSAndroid Build Coastguard Worker           }
642*61c4878aSAndroid Build Coastguard Worker         } else if (field->is_optional()) {
643*61c4878aSAndroid Build Coastguard Worker           // The struct member for this field is a std::optional of a type
644*61c4878aSAndroid Build Coastguard Worker           // corresponding to the field element size. Cast to the correct
645*61c4878aSAndroid Build Coastguard Worker           // optional type so we're not performing type aliasing (except for
646*61c4878aSAndroid Build Coastguard Worker           // unsigned vs signed which is explicitly allowed), and assign through
647*61c4878aSAndroid Build Coastguard Worker           // a temporary.
648*61c4878aSAndroid Build Coastguard Worker           if (field->elem_size() == sizeof(uint64_t)) {
649*61c4878aSAndroid Build Coastguard Worker             uint64_t value = 0;
650*61c4878aSAndroid Build Coastguard Worker             PW_TRY(ReadVarintField(as_writable_bytes(span(&value, 1)),
651*61c4878aSAndroid Build Coastguard Worker                                    field->varint_type()));
652*61c4878aSAndroid Build Coastguard Worker             auto* optional =
653*61c4878aSAndroid Build Coastguard Worker                 reinterpret_cast<std::optional<uint64_t>*>(out.data());
654*61c4878aSAndroid Build Coastguard Worker             *optional = value;
655*61c4878aSAndroid Build Coastguard Worker           } else if (field->elem_size() == sizeof(uint32_t)) {
656*61c4878aSAndroid Build Coastguard Worker             uint32_t value = 0;
657*61c4878aSAndroid Build Coastguard Worker             PW_TRY(ReadVarintField(as_writable_bytes(span(&value, 1)),
658*61c4878aSAndroid Build Coastguard Worker                                    field->varint_type()));
659*61c4878aSAndroid Build Coastguard Worker             auto* optional =
660*61c4878aSAndroid Build Coastguard Worker                 reinterpret_cast<std::optional<uint32_t>*>(out.data());
661*61c4878aSAndroid Build Coastguard Worker             *optional = value;
662*61c4878aSAndroid Build Coastguard Worker           } else if (field->elem_size() == sizeof(bool)) {
663*61c4878aSAndroid Build Coastguard Worker             bool value = false;
664*61c4878aSAndroid Build Coastguard Worker             PW_TRY(ReadVarintField(as_writable_bytes(span(&value, 1)),
665*61c4878aSAndroid Build Coastguard Worker                                    field->varint_type()));
666*61c4878aSAndroid Build Coastguard Worker             auto* optional = reinterpret_cast<std::optional<bool>*>(out.data());
667*61c4878aSAndroid Build Coastguard Worker             *optional = value;
668*61c4878aSAndroid Build Coastguard Worker           }
669*61c4878aSAndroid Build Coastguard Worker         } else {
670*61c4878aSAndroid Build Coastguard Worker           PW_CHECK(out.size() == field->elem_size(),
671*61c4878aSAndroid Build Coastguard Worker                    "Mismatched message field type and size");
672*61c4878aSAndroid Build Coastguard Worker           PW_TRY(ReadVarintField(out, field->varint_type()));
673*61c4878aSAndroid Build Coastguard Worker         }
674*61c4878aSAndroid Build Coastguard Worker         break;
675*61c4878aSAndroid Build Coastguard Worker       }
676*61c4878aSAndroid Build Coastguard Worker       case WireType::kDelimited: {
677*61c4878aSAndroid Build Coastguard Worker         // Delimited fields are always a singular case because of the inability
678*61c4878aSAndroid Build Coastguard Worker         // to cast to a generic vector with an element of a certain size (we
679*61c4878aSAndroid Build Coastguard Worker         // always need a type).
680*61c4878aSAndroid Build Coastguard Worker         PW_CHECK(!field->is_repeated(),
681*61c4878aSAndroid Build Coastguard Worker                  "Repeated delimited messages always require a callback");
682*61c4878aSAndroid Build Coastguard Worker         if (field->nested_message_fields()) {
683*61c4878aSAndroid Build Coastguard Worker           // Nested Message. Struct member is an embedded struct for the
684*61c4878aSAndroid Build Coastguard Worker           // nested field. Obtain a nested decoder and recursively call Read()
685*61c4878aSAndroid Build Coastguard Worker           // using the fields table pointer from this field.
686*61c4878aSAndroid Build Coastguard Worker           auto nested_decoder = GetNestedDecoder();
687*61c4878aSAndroid Build Coastguard Worker           PW_TRY(nested_decoder.Read(out, *field->nested_message_fields()));
688*61c4878aSAndroid Build Coastguard Worker         } else if (field->is_fixed_size()) {
689*61c4878aSAndroid Build Coastguard Worker           // Fixed-length bytes field. Struct member is a std::array<std::byte>.
690*61c4878aSAndroid Build Coastguard Worker           // Call ReadDelimitedField() to populate it from the stream.
691*61c4878aSAndroid Build Coastguard Worker           PW_CHECK(field->elem_size() == sizeof(std::byte),
692*61c4878aSAndroid Build Coastguard Worker                    "Mismatched message field type and size");
693*61c4878aSAndroid Build Coastguard Worker           PW_TRY(ReadDelimitedField(out));
694*61c4878aSAndroid Build Coastguard Worker         } else {
695*61c4878aSAndroid Build Coastguard Worker           // bytes or string field with a maximum size. The struct member is
696*61c4878aSAndroid Build Coastguard Worker           // pw::Vector<std::byte> for bytes or pw::InlineString<> for string.
697*61c4878aSAndroid Build Coastguard Worker           PW_CHECK(field->elem_size() == sizeof(std::byte),
698*61c4878aSAndroid Build Coastguard Worker                    "Mismatched message field type and size");
699*61c4878aSAndroid Build Coastguard Worker           if (field->is_string()) {
700*61c4878aSAndroid Build Coastguard Worker             PW_TRY(ReadStringOrBytesField<pw::InlineString<>>(out.data()));
701*61c4878aSAndroid Build Coastguard Worker           } else {
702*61c4878aSAndroid Build Coastguard Worker             PW_TRY(ReadStringOrBytesField<pw::Vector<std::byte>>(out.data()));
703*61c4878aSAndroid Build Coastguard Worker           }
704*61c4878aSAndroid Build Coastguard Worker         }
705*61c4878aSAndroid Build Coastguard Worker         break;
706*61c4878aSAndroid Build Coastguard Worker       }
707*61c4878aSAndroid Build Coastguard Worker     }
708*61c4878aSAndroid Build Coastguard Worker   }
709*61c4878aSAndroid Build Coastguard Worker 
710*61c4878aSAndroid Build Coastguard Worker   // Reaching the end of the encoded protobuf is not an error.
711*61c4878aSAndroid Build Coastguard Worker   if (status_ == Status::OutOfRange()) {
712*61c4878aSAndroid Build Coastguard Worker     return OkStatus();
713*61c4878aSAndroid Build Coastguard Worker   }
714*61c4878aSAndroid Build Coastguard Worker 
715*61c4878aSAndroid Build Coastguard Worker   return status_;
716*61c4878aSAndroid Build Coastguard Worker }
717*61c4878aSAndroid Build Coastguard Worker 
718*61c4878aSAndroid Build Coastguard Worker }  // namespace pw::protobuf
719