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