Coverage Report

Created: 2023-12-29 07:19

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