1*61c4878aSAndroid Build Coastguard Worker // Copyright 2020 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/decoder.h"
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker #include <cstring>
18*61c4878aSAndroid Build Coastguard Worker
19*61c4878aSAndroid Build Coastguard Worker #include "pw_assert/check.h"
20*61c4878aSAndroid Build Coastguard Worker #include "pw_varint/varint.h"
21*61c4878aSAndroid Build Coastguard Worker
22*61c4878aSAndroid Build Coastguard Worker namespace pw::protobuf {
23*61c4878aSAndroid Build Coastguard Worker
Next()24*61c4878aSAndroid Build Coastguard Worker Status Decoder::Next() {
25*61c4878aSAndroid Build Coastguard Worker if (!previous_field_consumed_) {
26*61c4878aSAndroid Build Coastguard Worker if (Status status = SkipField(); !status.ok()) {
27*61c4878aSAndroid Build Coastguard Worker return status;
28*61c4878aSAndroid Build Coastguard Worker }
29*61c4878aSAndroid Build Coastguard Worker }
30*61c4878aSAndroid Build Coastguard Worker if (proto_.empty()) {
31*61c4878aSAndroid Build Coastguard Worker return Status::OutOfRange();
32*61c4878aSAndroid Build Coastguard Worker }
33*61c4878aSAndroid Build Coastguard Worker previous_field_consumed_ = false;
34*61c4878aSAndroid Build Coastguard Worker return GetFieldSize().ok() ? OkStatus() : Status::DataLoss();
35*61c4878aSAndroid Build Coastguard Worker }
36*61c4878aSAndroid Build Coastguard Worker
SkipField()37*61c4878aSAndroid Build Coastguard Worker Status Decoder::SkipField() {
38*61c4878aSAndroid Build Coastguard Worker if (proto_.empty()) {
39*61c4878aSAndroid Build Coastguard Worker return Status::OutOfRange();
40*61c4878aSAndroid Build Coastguard Worker }
41*61c4878aSAndroid Build Coastguard Worker
42*61c4878aSAndroid Build Coastguard Worker size_t bytes_to_skip = GetFieldSize().total();
43*61c4878aSAndroid Build Coastguard Worker if (bytes_to_skip == 0) {
44*61c4878aSAndroid Build Coastguard Worker return Status::DataLoss();
45*61c4878aSAndroid Build Coastguard Worker }
46*61c4878aSAndroid Build Coastguard Worker
47*61c4878aSAndroid Build Coastguard Worker proto_ = proto_.subspan(bytes_to_skip);
48*61c4878aSAndroid Build Coastguard Worker return proto_.empty() ? Status::OutOfRange() : OkStatus();
49*61c4878aSAndroid Build Coastguard Worker }
50*61c4878aSAndroid Build Coastguard Worker
FieldNumber() const51*61c4878aSAndroid Build Coastguard Worker uint32_t Decoder::FieldNumber() const {
52*61c4878aSAndroid Build Coastguard Worker uint64_t key;
53*61c4878aSAndroid Build Coastguard Worker varint::Decode(proto_, &key);
54*61c4878aSAndroid Build Coastguard Worker if (!FieldKey::IsValidKey(key)) {
55*61c4878aSAndroid Build Coastguard Worker return 0;
56*61c4878aSAndroid Build Coastguard Worker }
57*61c4878aSAndroid Build Coastguard Worker PW_DCHECK(key <= std::numeric_limits<uint32_t>::max());
58*61c4878aSAndroid Build Coastguard Worker return FieldKey(static_cast<uint32_t>(key)).field_number();
59*61c4878aSAndroid Build Coastguard Worker }
60*61c4878aSAndroid Build Coastguard Worker
ReadUint32(uint32_t * out)61*61c4878aSAndroid Build Coastguard Worker Status Decoder::ReadUint32(uint32_t* out) {
62*61c4878aSAndroid Build Coastguard Worker uint64_t value = 0;
63*61c4878aSAndroid Build Coastguard Worker Status status = ReadUint64(&value);
64*61c4878aSAndroid Build Coastguard Worker if (!status.ok()) {
65*61c4878aSAndroid Build Coastguard Worker return status;
66*61c4878aSAndroid Build Coastguard Worker }
67*61c4878aSAndroid Build Coastguard Worker if (value > std::numeric_limits<uint32_t>::max()) {
68*61c4878aSAndroid Build Coastguard Worker return Status::OutOfRange();
69*61c4878aSAndroid Build Coastguard Worker }
70*61c4878aSAndroid Build Coastguard Worker *out = static_cast<uint32_t>(value);
71*61c4878aSAndroid Build Coastguard Worker return OkStatus();
72*61c4878aSAndroid Build Coastguard Worker }
73*61c4878aSAndroid Build Coastguard Worker
ReadSint32(int32_t * out)74*61c4878aSAndroid Build Coastguard Worker Status Decoder::ReadSint32(int32_t* out) {
75*61c4878aSAndroid Build Coastguard Worker int64_t value = 0;
76*61c4878aSAndroid Build Coastguard Worker Status status = ReadSint64(&value);
77*61c4878aSAndroid Build Coastguard Worker if (!status.ok()) {
78*61c4878aSAndroid Build Coastguard Worker return status;
79*61c4878aSAndroid Build Coastguard Worker }
80*61c4878aSAndroid Build Coastguard Worker if (value > std::numeric_limits<int32_t>::max()) {
81*61c4878aSAndroid Build Coastguard Worker return Status::OutOfRange();
82*61c4878aSAndroid Build Coastguard Worker }
83*61c4878aSAndroid Build Coastguard Worker *out = static_cast<uint32_t>(value);
84*61c4878aSAndroid Build Coastguard Worker return OkStatus();
85*61c4878aSAndroid Build Coastguard Worker }
86*61c4878aSAndroid Build Coastguard Worker
ReadSint64(int64_t * out)87*61c4878aSAndroid Build Coastguard Worker Status Decoder::ReadSint64(int64_t* out) {
88*61c4878aSAndroid Build Coastguard Worker uint64_t value = 0;
89*61c4878aSAndroid Build Coastguard Worker Status status = ReadUint64(&value);
90*61c4878aSAndroid Build Coastguard Worker if (!status.ok()) {
91*61c4878aSAndroid Build Coastguard Worker return status;
92*61c4878aSAndroid Build Coastguard Worker }
93*61c4878aSAndroid Build Coastguard Worker *out = varint::ZigZagDecode(value);
94*61c4878aSAndroid Build Coastguard Worker return OkStatus();
95*61c4878aSAndroid Build Coastguard Worker }
96*61c4878aSAndroid Build Coastguard Worker
ReadBool(bool * out)97*61c4878aSAndroid Build Coastguard Worker Status Decoder::ReadBool(bool* out) {
98*61c4878aSAndroid Build Coastguard Worker uint64_t value = 0;
99*61c4878aSAndroid Build Coastguard Worker Status status = ReadUint64(&value);
100*61c4878aSAndroid Build Coastguard Worker if (!status.ok()) {
101*61c4878aSAndroid Build Coastguard Worker return status;
102*61c4878aSAndroid Build Coastguard Worker }
103*61c4878aSAndroid Build Coastguard Worker *out = value;
104*61c4878aSAndroid Build Coastguard Worker return OkStatus();
105*61c4878aSAndroid Build Coastguard Worker }
106*61c4878aSAndroid Build Coastguard Worker
ReadString(std::string_view * out)107*61c4878aSAndroid Build Coastguard Worker Status Decoder::ReadString(std::string_view* out) {
108*61c4878aSAndroid Build Coastguard Worker span<const std::byte> bytes;
109*61c4878aSAndroid Build Coastguard Worker Status status = ReadDelimited(&bytes);
110*61c4878aSAndroid Build Coastguard Worker if (!status.ok()) {
111*61c4878aSAndroid Build Coastguard Worker return status;
112*61c4878aSAndroid Build Coastguard Worker }
113*61c4878aSAndroid Build Coastguard Worker *out = std::string_view(reinterpret_cast<const char*>(bytes.data()),
114*61c4878aSAndroid Build Coastguard Worker bytes.size());
115*61c4878aSAndroid Build Coastguard Worker return OkStatus();
116*61c4878aSAndroid Build Coastguard Worker }
117*61c4878aSAndroid Build Coastguard Worker
GetFieldSize() const118*61c4878aSAndroid Build Coastguard Worker Decoder::FieldSize Decoder::GetFieldSize() const {
119*61c4878aSAndroid Build Coastguard Worker uint64_t key;
120*61c4878aSAndroid Build Coastguard Worker size_t key_size = varint::Decode(proto_, &key);
121*61c4878aSAndroid Build Coastguard Worker if (key_size == 0 || !FieldKey::IsValidKey(key)) {
122*61c4878aSAndroid Build Coastguard Worker return FieldSize::Invalid();
123*61c4878aSAndroid Build Coastguard Worker }
124*61c4878aSAndroid Build Coastguard Worker
125*61c4878aSAndroid Build Coastguard Worker span<const std::byte> remainder = proto_.subspan(key_size);
126*61c4878aSAndroid Build Coastguard Worker uint64_t value = 0;
127*61c4878aSAndroid Build Coastguard Worker size_t expected_size = 0;
128*61c4878aSAndroid Build Coastguard Worker
129*61c4878aSAndroid Build Coastguard Worker PW_DCHECK(key <= std::numeric_limits<uint32_t>::max());
130*61c4878aSAndroid Build Coastguard Worker switch (FieldKey(static_cast<uint32_t>(key)).wire_type()) {
131*61c4878aSAndroid Build Coastguard Worker case WireType::kVarint:
132*61c4878aSAndroid Build Coastguard Worker expected_size = varint::Decode(remainder, &value);
133*61c4878aSAndroid Build Coastguard Worker if (expected_size == 0) {
134*61c4878aSAndroid Build Coastguard Worker return FieldSize::Invalid();
135*61c4878aSAndroid Build Coastguard Worker }
136*61c4878aSAndroid Build Coastguard Worker break;
137*61c4878aSAndroid Build Coastguard Worker
138*61c4878aSAndroid Build Coastguard Worker case WireType::kDelimited: {
139*61c4878aSAndroid Build Coastguard Worker // Varint at cursor indicates size of the field.
140*61c4878aSAndroid Build Coastguard Worker const size_t delimited_size = varint::Decode(remainder, &value);
141*61c4878aSAndroid Build Coastguard Worker if (delimited_size == 0) {
142*61c4878aSAndroid Build Coastguard Worker return FieldSize::Invalid();
143*61c4878aSAndroid Build Coastguard Worker }
144*61c4878aSAndroid Build Coastguard Worker key_size += delimited_size;
145*61c4878aSAndroid Build Coastguard Worker expected_size += value;
146*61c4878aSAndroid Build Coastguard Worker break;
147*61c4878aSAndroid Build Coastguard Worker }
148*61c4878aSAndroid Build Coastguard Worker case WireType::kFixed32:
149*61c4878aSAndroid Build Coastguard Worker expected_size = sizeof(uint32_t);
150*61c4878aSAndroid Build Coastguard Worker break;
151*61c4878aSAndroid Build Coastguard Worker
152*61c4878aSAndroid Build Coastguard Worker case WireType::kFixed64:
153*61c4878aSAndroid Build Coastguard Worker expected_size = sizeof(uint64_t);
154*61c4878aSAndroid Build Coastguard Worker break;
155*61c4878aSAndroid Build Coastguard Worker }
156*61c4878aSAndroid Build Coastguard Worker
157*61c4878aSAndroid Build Coastguard Worker if (remainder.size() < expected_size) {
158*61c4878aSAndroid Build Coastguard Worker return FieldSize::Invalid();
159*61c4878aSAndroid Build Coastguard Worker }
160*61c4878aSAndroid Build Coastguard Worker
161*61c4878aSAndroid Build Coastguard Worker return FieldSize{key_size, expected_size};
162*61c4878aSAndroid Build Coastguard Worker }
163*61c4878aSAndroid Build Coastguard Worker
ConsumeKey(WireType expected_type)164*61c4878aSAndroid Build Coastguard Worker Status Decoder::ConsumeKey(WireType expected_type) {
165*61c4878aSAndroid Build Coastguard Worker uint64_t key;
166*61c4878aSAndroid Build Coastguard Worker size_t bytes_read = varint::Decode(proto_, &key);
167*61c4878aSAndroid Build Coastguard Worker if (bytes_read == 0) {
168*61c4878aSAndroid Build Coastguard Worker return Status::FailedPrecondition();
169*61c4878aSAndroid Build Coastguard Worker }
170*61c4878aSAndroid Build Coastguard Worker
171*61c4878aSAndroid Build Coastguard Worker if (!FieldKey::IsValidKey(key)) {
172*61c4878aSAndroid Build Coastguard Worker return Status::DataLoss();
173*61c4878aSAndroid Build Coastguard Worker }
174*61c4878aSAndroid Build Coastguard Worker
175*61c4878aSAndroid Build Coastguard Worker PW_DCHECK(key <= std::numeric_limits<uint32_t>::max());
176*61c4878aSAndroid Build Coastguard Worker if (FieldKey(static_cast<uint32_t>(key)).wire_type() != expected_type) {
177*61c4878aSAndroid Build Coastguard Worker return Status::FailedPrecondition();
178*61c4878aSAndroid Build Coastguard Worker }
179*61c4878aSAndroid Build Coastguard Worker
180*61c4878aSAndroid Build Coastguard Worker // Advance past the key.
181*61c4878aSAndroid Build Coastguard Worker proto_ = proto_.subspan(bytes_read);
182*61c4878aSAndroid Build Coastguard Worker return OkStatus();
183*61c4878aSAndroid Build Coastguard Worker }
184*61c4878aSAndroid Build Coastguard Worker
ReadVarint(uint64_t * out)185*61c4878aSAndroid Build Coastguard Worker Status Decoder::ReadVarint(uint64_t* out) {
186*61c4878aSAndroid Build Coastguard Worker if (Status status = ConsumeKey(WireType::kVarint); !status.ok()) {
187*61c4878aSAndroid Build Coastguard Worker return status;
188*61c4878aSAndroid Build Coastguard Worker }
189*61c4878aSAndroid Build Coastguard Worker
190*61c4878aSAndroid Build Coastguard Worker size_t bytes_read = varint::Decode(proto_, out);
191*61c4878aSAndroid Build Coastguard Worker if (bytes_read == 0) {
192*61c4878aSAndroid Build Coastguard Worker return Status::DataLoss();
193*61c4878aSAndroid Build Coastguard Worker }
194*61c4878aSAndroid Build Coastguard Worker
195*61c4878aSAndroid Build Coastguard Worker // Advance to the next field.
196*61c4878aSAndroid Build Coastguard Worker proto_ = proto_.subspan(bytes_read);
197*61c4878aSAndroid Build Coastguard Worker previous_field_consumed_ = true;
198*61c4878aSAndroid Build Coastguard Worker return OkStatus();
199*61c4878aSAndroid Build Coastguard Worker }
200*61c4878aSAndroid Build Coastguard Worker
ReadFixed(std::byte * out,size_t size)201*61c4878aSAndroid Build Coastguard Worker Status Decoder::ReadFixed(std::byte* out, size_t size) {
202*61c4878aSAndroid Build Coastguard Worker WireType expected_wire_type =
203*61c4878aSAndroid Build Coastguard Worker size == sizeof(uint32_t) ? WireType::kFixed32 : WireType::kFixed64;
204*61c4878aSAndroid Build Coastguard Worker Status status = ConsumeKey(expected_wire_type);
205*61c4878aSAndroid Build Coastguard Worker if (!status.ok()) {
206*61c4878aSAndroid Build Coastguard Worker return status;
207*61c4878aSAndroid Build Coastguard Worker }
208*61c4878aSAndroid Build Coastguard Worker
209*61c4878aSAndroid Build Coastguard Worker if (proto_.size() < size) {
210*61c4878aSAndroid Build Coastguard Worker return Status::DataLoss();
211*61c4878aSAndroid Build Coastguard Worker }
212*61c4878aSAndroid Build Coastguard Worker
213*61c4878aSAndroid Build Coastguard Worker std::memcpy(out, proto_.data(), size);
214*61c4878aSAndroid Build Coastguard Worker proto_ = proto_.subspan(size);
215*61c4878aSAndroid Build Coastguard Worker previous_field_consumed_ = true;
216*61c4878aSAndroid Build Coastguard Worker
217*61c4878aSAndroid Build Coastguard Worker return OkStatus();
218*61c4878aSAndroid Build Coastguard Worker }
219*61c4878aSAndroid Build Coastguard Worker
ReadDelimited(span<const std::byte> * out)220*61c4878aSAndroid Build Coastguard Worker Status Decoder::ReadDelimited(span<const std::byte>* out) {
221*61c4878aSAndroid Build Coastguard Worker Status status = ConsumeKey(WireType::kDelimited);
222*61c4878aSAndroid Build Coastguard Worker if (!status.ok()) {
223*61c4878aSAndroid Build Coastguard Worker return status;
224*61c4878aSAndroid Build Coastguard Worker }
225*61c4878aSAndroid Build Coastguard Worker
226*61c4878aSAndroid Build Coastguard Worker uint64_t length;
227*61c4878aSAndroid Build Coastguard Worker size_t bytes_read = varint::Decode(proto_, &length);
228*61c4878aSAndroid Build Coastguard Worker if (bytes_read == 0) {
229*61c4878aSAndroid Build Coastguard Worker return Status::DataLoss();
230*61c4878aSAndroid Build Coastguard Worker }
231*61c4878aSAndroid Build Coastguard Worker
232*61c4878aSAndroid Build Coastguard Worker proto_ = proto_.subspan(bytes_read);
233*61c4878aSAndroid Build Coastguard Worker if (proto_.size() < length) {
234*61c4878aSAndroid Build Coastguard Worker return Status::DataLoss();
235*61c4878aSAndroid Build Coastguard Worker }
236*61c4878aSAndroid Build Coastguard Worker
237*61c4878aSAndroid Build Coastguard Worker *out = proto_.first(length);
238*61c4878aSAndroid Build Coastguard Worker proto_ = proto_.subspan(length);
239*61c4878aSAndroid Build Coastguard Worker previous_field_consumed_ = true;
240*61c4878aSAndroid Build Coastguard Worker
241*61c4878aSAndroid Build Coastguard Worker return OkStatus();
242*61c4878aSAndroid Build Coastguard Worker }
243*61c4878aSAndroid Build Coastguard Worker
Decode(span<const std::byte> proto)244*61c4878aSAndroid Build Coastguard Worker Status CallbackDecoder::Decode(span<const std::byte> proto) {
245*61c4878aSAndroid Build Coastguard Worker if (handler_ == nullptr || state_ != kReady) {
246*61c4878aSAndroid Build Coastguard Worker return Status::FailedPrecondition();
247*61c4878aSAndroid Build Coastguard Worker }
248*61c4878aSAndroid Build Coastguard Worker
249*61c4878aSAndroid Build Coastguard Worker state_ = kDecodeInProgress;
250*61c4878aSAndroid Build Coastguard Worker decoder_.Reset(proto);
251*61c4878aSAndroid Build Coastguard Worker
252*61c4878aSAndroid Build Coastguard Worker // Iterate the proto, calling the handler with each field number.
253*61c4878aSAndroid Build Coastguard Worker while (state_ == kDecodeInProgress) {
254*61c4878aSAndroid Build Coastguard Worker if (Status status = decoder_.Next(); !status.ok()) {
255*61c4878aSAndroid Build Coastguard Worker if (status.IsOutOfRange()) {
256*61c4878aSAndroid Build Coastguard Worker // Reached the end of the proto.
257*61c4878aSAndroid Build Coastguard Worker break;
258*61c4878aSAndroid Build Coastguard Worker }
259*61c4878aSAndroid Build Coastguard Worker
260*61c4878aSAndroid Build Coastguard Worker // Proto data is malformed.
261*61c4878aSAndroid Build Coastguard Worker return status;
262*61c4878aSAndroid Build Coastguard Worker }
263*61c4878aSAndroid Build Coastguard Worker
264*61c4878aSAndroid Build Coastguard Worker Status status = handler_->ProcessField(*this, decoder_.FieldNumber());
265*61c4878aSAndroid Build Coastguard Worker if (!status.ok()) {
266*61c4878aSAndroid Build Coastguard Worker state_ = status.IsCancelled() ? kDecodeCancelled : kDecodeFailed;
267*61c4878aSAndroid Build Coastguard Worker return status;
268*61c4878aSAndroid Build Coastguard Worker }
269*61c4878aSAndroid Build Coastguard Worker
270*61c4878aSAndroid Build Coastguard Worker // The callback function can modify the decoder's state; check that
271*61c4878aSAndroid Build Coastguard Worker // everything is still okay.
272*61c4878aSAndroid Build Coastguard Worker if (state_ == kDecodeFailed) {
273*61c4878aSAndroid Build Coastguard Worker break;
274*61c4878aSAndroid Build Coastguard Worker }
275*61c4878aSAndroid Build Coastguard Worker }
276*61c4878aSAndroid Build Coastguard Worker
277*61c4878aSAndroid Build Coastguard Worker if (state_ != kDecodeInProgress) {
278*61c4878aSAndroid Build Coastguard Worker return Status::DataLoss();
279*61c4878aSAndroid Build Coastguard Worker }
280*61c4878aSAndroid Build Coastguard Worker
281*61c4878aSAndroid Build Coastguard Worker state_ = kReady;
282*61c4878aSAndroid Build Coastguard Worker return OkStatus();
283*61c4878aSAndroid Build Coastguard Worker }
284*61c4878aSAndroid Build Coastguard Worker
285*61c4878aSAndroid Build Coastguard Worker } // namespace pw::protobuf
286