pw_protobuf: Extended decoder type support
This change adds decoder support for protobuf bool, fixed32,
fixed64, float, double, bytes, and string value.
Change-Id: Ie8369f5802d07290c0d6c12b5049c6bd8cc7a5da
diff --git a/pw_protobuf/decoder.cc b/pw_protobuf/decoder.cc
index 0e803e6..220c608 100644
--- a/pw_protobuf/decoder.cc
+++ b/pw_protobuf/decoder.cc
@@ -14,6 +14,8 @@
#include "pw_protobuf/decoder.h"
+#include <cstring>
+
#include "pw_varint/varint.h"
namespace pw::protobuf {
@@ -66,6 +68,67 @@
}
Status Decoder::ReadVarint(uint32_t field_number, uint64_t* out) {
+ Status status = ConsumeKey(field_number, WireType::kVarint);
+ if (!status.ok()) {
+ return status;
+ }
+
+ size_t bytes_read = varint::Decode(proto_, out);
+ if (bytes_read == 0) {
+ state_ = kDecodeFailed;
+ return Status::DATA_LOSS;
+ }
+
+ // Advance to the next field.
+ proto_ = proto_.subspan(bytes_read);
+ return Status::OK;
+}
+
+Status Decoder::ReadFixed(uint32_t field_number, std::byte* out, size_t size) {
+ WireType expected_wire_type =
+ size == sizeof(uint32_t) ? WireType::kFixed32 : WireType::kFixed64;
+ Status status = ConsumeKey(field_number, expected_wire_type);
+ if (!status.ok()) {
+ return status;
+ }
+
+ if (proto_.size() < size) {
+ return Status::DATA_LOSS;
+ }
+
+ std::memcpy(out, proto_.data(), size);
+ proto_ = proto_.subspan(size);
+
+ return Status::OK;
+}
+
+Status Decoder::ReadDelimited(uint32_t field_number,
+ span<const std::byte>* out) {
+ Status status = ConsumeKey(field_number, WireType::kDelimited);
+ if (!status.ok()) {
+ return status;
+ }
+
+ uint64_t length;
+ size_t bytes_read = varint::Decode(proto_, &length);
+ if (bytes_read == 0) {
+ state_ = kDecodeFailed;
+ return Status::DATA_LOSS;
+ }
+
+ proto_ = proto_.subspan(bytes_read);
+ if (proto_.size() < length) {
+ state_ = kDecodeFailed;
+ return Status::DATA_LOSS;
+ }
+
+ *out = proto_.first(length);
+ proto_ = proto_.subspan(length);
+
+ return Status::OK;
+}
+
+Status Decoder::ConsumeKey(uint32_t field_number, WireType expected_type) {
if (state_ != kDecodeInProgress) {
return Status::FAILED_PRECONDITION;
}
@@ -80,21 +143,12 @@
uint32_t field = key >> kFieldNumberShift;
WireType wire_type = static_cast<WireType>(key & kWireTypeMask);
- if (field != field_number || wire_type != WireType::kVarint) {
+ if (field != field_number || wire_type != expected_type) {
state_ = kDecodeFailed;
return Status::FAILED_PRECONDITION;
}
- // Advance to the varint value.
- proto_ = proto_.subspan(bytes_read);
-
- bytes_read = varint::Decode(proto_, out);
- if (bytes_read == 0) {
- state_ = kDecodeFailed;
- return Status::DATA_LOSS;
- }
-
- // Advance to the next field.
+ // Advance past the key.
proto_ = proto_.subspan(bytes_read);
return Status::OK;
}