blob: 813046c86dc6c9d674398c60d1bdce7c8586b7ee [file] [log] [blame]
Alexei Frolovdea46f72020-01-07 13:28:24 -08001// Copyright 2020 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/decoder.h"
16
Alexei Frolov6d9b9b42020-01-14 12:57:33 -080017#include <cstring>
18
Alexei Frolovdea46f72020-01-07 13:28:24 -080019#include "pw_varint/varint.h"
20
21namespace pw::protobuf {
22
Alexei Frolovfe9723c2020-05-11 13:20:47 -070023Status Decoder::Next() {
24 if (!previous_field_consumed_) {
25 if (Status status = SkipField(); !status.ok()) {
Alexei Frolovdea46f72020-01-07 13:28:24 -080026 return status;
27 }
Alexei Frolovfe9723c2020-05-11 13:20:47 -070028 }
29 if (proto_.empty()) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -070030 return Status::OutOfRange();
Alexei Frolovfe9723c2020-05-11 13:20:47 -070031 }
32 previous_field_consumed_ = false;
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080033 return FieldSize() == 0 ? Status::DataLoss() : OkStatus();
Alexei Frolovfe9723c2020-05-11 13:20:47 -070034}
Alexei Frolovdea46f72020-01-07 13:28:24 -080035
Alexei Frolovfe9723c2020-05-11 13:20:47 -070036Status Decoder::SkipField() {
37 if (proto_.empty()) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -070038 return Status::OutOfRange();
Alexei Frolovdea46f72020-01-07 13:28:24 -080039 }
40
Alexei Frolovfe9723c2020-05-11 13:20:47 -070041 size_t bytes_to_skip = FieldSize();
42 if (bytes_to_skip == 0) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -070043 return Status::DataLoss();
Alexei Frolovdea46f72020-01-07 13:28:24 -080044 }
45
Alexei Frolovfe9723c2020-05-11 13:20:47 -070046 proto_ = proto_.subspan(bytes_to_skip);
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080047 return proto_.empty() ? Status::OutOfRange() : OkStatus();
Alexei Frolovfe9723c2020-05-11 13:20:47 -070048}
49
50uint32_t Decoder::FieldNumber() const {
51 uint64_t key;
52 varint::Decode(proto_, &key);
53 return key >> kFieldNumberShift;
54}
55
56Status Decoder::ReadUint32(uint32_t* out) {
57 uint64_t value = 0;
58 Status status = ReadUint64(&value);
59 if (!status.ok()) {
60 return status;
61 }
62 if (value > std::numeric_limits<uint32_t>::max()) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -070063 return Status::OutOfRange();
Alexei Frolovfe9723c2020-05-11 13:20:47 -070064 }
65 *out = value;
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080066 return OkStatus();
Alexei Frolovdea46f72020-01-07 13:28:24 -080067}
68
Alexei Frolovfe9723c2020-05-11 13:20:47 -070069Status Decoder::ReadSint32(int32_t* out) {
70 int64_t value = 0;
71 Status status = ReadSint64(&value);
Alexei Frolov6d9b9b42020-01-14 12:57:33 -080072 if (!status.ok()) {
73 return status;
74 }
Alexei Frolovfe9723c2020-05-11 13:20:47 -070075 if (value > std::numeric_limits<int32_t>::max()) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -070076 return Status::OutOfRange();
Alexei Frolovfe9723c2020-05-11 13:20:47 -070077 }
78 *out = value;
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080079 return OkStatus();
Alexei Frolovfe9723c2020-05-11 13:20:47 -070080}
81
82Status Decoder::ReadSint64(int64_t* out) {
83 uint64_t value = 0;
84 Status status = ReadUint64(&value);
85 if (!status.ok()) {
86 return status;
87 }
88 *out = varint::ZigZagDecode(value);
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080089 return OkStatus();
Alexei Frolovfe9723c2020-05-11 13:20:47 -070090}
91
92Status Decoder::ReadBool(bool* out) {
93 uint64_t value = 0;
94 Status status = ReadUint64(&value);
95 if (!status.ok()) {
96 return status;
97 }
98 *out = value;
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080099 return OkStatus();
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700100}
101
102Status Decoder::ReadString(std::string_view* out) {
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700103 std::span<const std::byte> bytes;
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700104 Status status = ReadDelimited(&bytes);
105 if (!status.ok()) {
106 return status;
107 }
108 *out = std::string_view(reinterpret_cast<const char*>(bytes.data()),
109 bytes.size());
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800110 return OkStatus();
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700111}
112
113size_t Decoder::FieldSize() const {
114 uint64_t key;
115 size_t key_size = varint::Decode(proto_, &key);
116 if (key_size == 0) {
117 return 0;
118 }
119
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700120 std::span<const std::byte> remainder = proto_.subspan(key_size);
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700121 WireType wire_type = static_cast<WireType>(key & kWireTypeMask);
122 uint64_t value = 0;
123 size_t expected_size = 0;
124
125 switch (wire_type) {
126 case WireType::kVarint:
127 expected_size = varint::Decode(remainder, &value);
128 if (expected_size == 0) {
129 return 0;
130 }
131 break;
132
133 case WireType::kDelimited:
134 // Varint at cursor indicates size of the field.
135 expected_size = varint::Decode(remainder, &value);
136 if (expected_size == 0) {
137 return 0;
138 }
139 expected_size += value;
140 break;
141
142 case WireType::kFixed32:
143 expected_size = sizeof(uint32_t);
144 break;
145
146 case WireType::kFixed64:
147 expected_size = sizeof(uint64_t);
148 break;
149 }
150
151 if (remainder.size() < expected_size) {
152 return 0;
153 }
154
155 return key_size + expected_size;
156}
157
158Status Decoder::ConsumeKey(WireType expected_type) {
159 uint64_t key;
160 size_t bytes_read = varint::Decode(proto_, &key);
161 if (bytes_read == 0) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700162 return Status::FailedPrecondition();
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700163 }
164
165 WireType wire_type = static_cast<WireType>(key & kWireTypeMask);
166 if (wire_type != expected_type) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700167 return Status::FailedPrecondition();
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700168 }
169
170 // Advance past the key.
171 proto_ = proto_.subspan(bytes_read);
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800172 return OkStatus();
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700173}
174
175Status Decoder::ReadVarint(uint64_t* out) {
176 if (Status status = ConsumeKey(WireType::kVarint); !status.ok()) {
177 return status;
178 }
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800179
180 size_t bytes_read = varint::Decode(proto_, out);
181 if (bytes_read == 0) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700182 return Status::DataLoss();
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800183 }
184
185 // Advance to the next field.
186 proto_ = proto_.subspan(bytes_read);
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700187 previous_field_consumed_ = true;
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800188 return OkStatus();
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800189}
190
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700191Status Decoder::ReadFixed(std::byte* out, size_t size) {
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800192 WireType expected_wire_type =
193 size == sizeof(uint32_t) ? WireType::kFixed32 : WireType::kFixed64;
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700194 Status status = ConsumeKey(expected_wire_type);
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800195 if (!status.ok()) {
196 return status;
197 }
198
199 if (proto_.size() < size) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700200 return Status::DataLoss();
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800201 }
202
203 std::memcpy(out, proto_.data(), size);
204 proto_ = proto_.subspan(size);
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700205 previous_field_consumed_ = true;
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800206
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800207 return OkStatus();
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800208}
209
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700210Status Decoder::ReadDelimited(std::span<const std::byte>* out) {
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700211 Status status = ConsumeKey(WireType::kDelimited);
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800212 if (!status.ok()) {
213 return status;
214 }
215
216 uint64_t length;
217 size_t bytes_read = varint::Decode(proto_, &length);
218 if (bytes_read == 0) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700219 return Status::DataLoss();
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800220 }
221
222 proto_ = proto_.subspan(bytes_read);
223 if (proto_.size() < length) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700224 return Status::DataLoss();
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800225 }
226
227 *out = proto_.first(length);
228 proto_ = proto_.subspan(length);
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700229 previous_field_consumed_ = true;
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800230
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800231 return OkStatus();
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800232}
233
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700234Status CallbackDecoder::Decode(std::span<const std::byte> proto) {
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700235 if (handler_ == nullptr || state_ != kReady) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700236 return Status::FailedPrecondition();
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700237 }
238
239 state_ = kDecodeInProgress;
240 decoder_.Reset(proto);
241
242 // Iterate the proto, calling the handler with each field number.
243 while (state_ == kDecodeInProgress) {
244 if (Status status = decoder_.Next(); !status.ok()) {
Wyatt Heplerf276c6b2020-11-11 21:13:38 -0800245 if (status.IsOutOfRange()) {
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700246 // Reached the end of the proto.
247 break;
248 }
249
250 // Proto data is malformed.
251 return status;
252 }
253
254 Status status = handler_->ProcessField(*this, decoder_.FieldNumber());
255 if (!status.ok()) {
Wyatt Heplerf276c6b2020-11-11 21:13:38 -0800256 state_ = status.IsCancelled() ? kDecodeCancelled : kDecodeFailed;
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700257 return status;
258 }
259
260 // The callback function can modify the decoder's state; check that
261 // everything is still okay.
262 if (state_ == kDecodeFailed) {
263 break;
264 }
265 }
266
Alexei Frolovdea46f72020-01-07 13:28:24 -0800267 if (state_ != kDecodeInProgress) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700268 return Status::DataLoss();
Alexei Frolovdea46f72020-01-07 13:28:24 -0800269 }
270
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700271 state_ = kReady;
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800272 return OkStatus();
Alexei Frolovdea46f72020-01-07 13:28:24 -0800273}
274
Alexei Frolovdea46f72020-01-07 13:28:24 -0800275} // namespace pw::protobuf