• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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