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