blob: 7f8c8cf391a4b3eaba35d306be1f2fe6e6b065c5 [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);
Alexei Frolov5ebf8ad2021-09-02 16:55:15 -070053 if (!FieldKey::IsValidKey(key)) {
54 return 0;
55 }
56 return FieldKey(key).field_number();
Alexei Frolovfe9723c2020-05-11 13:20:47 -070057}
58
59Status Decoder::ReadUint32(uint32_t* out) {
60 uint64_t value = 0;
61 Status status = ReadUint64(&value);
62 if (!status.ok()) {
63 return status;
64 }
65 if (value > std::numeric_limits<uint32_t>::max()) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -070066 return Status::OutOfRange();
Alexei Frolovfe9723c2020-05-11 13:20:47 -070067 }
68 *out = value;
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080069 return OkStatus();
Alexei Frolovdea46f72020-01-07 13:28:24 -080070}
71
Alexei Frolovfe9723c2020-05-11 13:20:47 -070072Status Decoder::ReadSint32(int32_t* out) {
73 int64_t value = 0;
74 Status status = ReadSint64(&value);
Alexei Frolov6d9b9b42020-01-14 12:57:33 -080075 if (!status.ok()) {
76 return status;
77 }
Alexei Frolovfe9723c2020-05-11 13:20:47 -070078 if (value > std::numeric_limits<int32_t>::max()) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -070079 return Status::OutOfRange();
Alexei Frolovfe9723c2020-05-11 13:20:47 -070080 }
81 *out = value;
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080082 return OkStatus();
Alexei Frolovfe9723c2020-05-11 13:20:47 -070083}
84
85Status Decoder::ReadSint64(int64_t* out) {
86 uint64_t value = 0;
87 Status status = ReadUint64(&value);
88 if (!status.ok()) {
89 return status;
90 }
91 *out = varint::ZigZagDecode(value);
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080092 return OkStatus();
Alexei Frolovfe9723c2020-05-11 13:20:47 -070093}
94
95Status Decoder::ReadBool(bool* out) {
96 uint64_t value = 0;
97 Status status = ReadUint64(&value);
98 if (!status.ok()) {
99 return status;
100 }
101 *out = value;
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800102 return OkStatus();
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700103}
104
105Status Decoder::ReadString(std::string_view* out) {
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700106 std::span<const std::byte> bytes;
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700107 Status status = ReadDelimited(&bytes);
108 if (!status.ok()) {
109 return status;
110 }
111 *out = std::string_view(reinterpret_cast<const char*>(bytes.data()),
112 bytes.size());
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800113 return OkStatus();
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700114}
115
116size_t Decoder::FieldSize() const {
117 uint64_t key;
118 size_t key_size = varint::Decode(proto_, &key);
Alexei Frolov5ebf8ad2021-09-02 16:55:15 -0700119 if (key_size == 0 || !FieldKey::IsValidKey(key)) {
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700120 return 0;
121 }
122
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700123 std::span<const std::byte> remainder = proto_.subspan(key_size);
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700124 uint64_t value = 0;
125 size_t expected_size = 0;
126
Alexei Frolov5ebf8ad2021-09-02 16:55:15 -0700127 switch (FieldKey(key).wire_type()) {
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700128 case WireType::kVarint:
129 expected_size = varint::Decode(remainder, &value);
130 if (expected_size == 0) {
131 return 0;
132 }
133 break;
134
135 case WireType::kDelimited:
136 // Varint at cursor indicates size of the field.
137 expected_size = varint::Decode(remainder, &value);
138 if (expected_size == 0) {
139 return 0;
140 }
141 expected_size += value;
142 break;
143
144 case WireType::kFixed32:
145 expected_size = sizeof(uint32_t);
146 break;
147
148 case WireType::kFixed64:
149 expected_size = sizeof(uint64_t);
150 break;
151 }
152
153 if (remainder.size() < expected_size) {
154 return 0;
155 }
156
157 return key_size + expected_size;
158}
159
160Status Decoder::ConsumeKey(WireType expected_type) {
161 uint64_t key;
162 size_t bytes_read = varint::Decode(proto_, &key);
163 if (bytes_read == 0) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700164 return Status::FailedPrecondition();
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700165 }
166
Alexei Frolov5ebf8ad2021-09-02 16:55:15 -0700167 if (!FieldKey::IsValidKey(key)) {
168 return Status::DataLoss();
169 }
170
171 if (FieldKey(key).wire_type() != expected_type) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700172 return Status::FailedPrecondition();
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700173 }
174
175 // Advance past the key.
176 proto_ = proto_.subspan(bytes_read);
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800177 return OkStatus();
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700178}
179
180Status Decoder::ReadVarint(uint64_t* out) {
181 if (Status status = ConsumeKey(WireType::kVarint); !status.ok()) {
182 return status;
183 }
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800184
185 size_t bytes_read = varint::Decode(proto_, out);
186 if (bytes_read == 0) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700187 return Status::DataLoss();
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800188 }
189
190 // Advance to the next field.
191 proto_ = proto_.subspan(bytes_read);
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700192 previous_field_consumed_ = true;
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800193 return OkStatus();
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800194}
195
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700196Status Decoder::ReadFixed(std::byte* out, size_t size) {
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800197 WireType expected_wire_type =
198 size == sizeof(uint32_t) ? WireType::kFixed32 : WireType::kFixed64;
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700199 Status status = ConsumeKey(expected_wire_type);
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800200 if (!status.ok()) {
201 return status;
202 }
203
204 if (proto_.size() < size) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700205 return Status::DataLoss();
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800206 }
207
208 std::memcpy(out, proto_.data(), size);
209 proto_ = proto_.subspan(size);
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700210 previous_field_consumed_ = true;
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800211
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800212 return OkStatus();
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800213}
214
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700215Status Decoder::ReadDelimited(std::span<const std::byte>* out) {
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700216 Status status = ConsumeKey(WireType::kDelimited);
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800217 if (!status.ok()) {
218 return status;
219 }
220
221 uint64_t length;
222 size_t bytes_read = varint::Decode(proto_, &length);
223 if (bytes_read == 0) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700224 return Status::DataLoss();
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800225 }
226
227 proto_ = proto_.subspan(bytes_read);
228 if (proto_.size() < length) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700229 return Status::DataLoss();
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800230 }
231
232 *out = proto_.first(length);
233 proto_ = proto_.subspan(length);
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700234 previous_field_consumed_ = true;
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800235
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800236 return OkStatus();
Alexei Frolov6d9b9b42020-01-14 12:57:33 -0800237}
238
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700239Status CallbackDecoder::Decode(std::span<const std::byte> proto) {
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700240 if (handler_ == nullptr || state_ != kReady) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700241 return Status::FailedPrecondition();
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700242 }
243
244 state_ = kDecodeInProgress;
245 decoder_.Reset(proto);
246
247 // Iterate the proto, calling the handler with each field number.
248 while (state_ == kDecodeInProgress) {
249 if (Status status = decoder_.Next(); !status.ok()) {
Wyatt Heplerf276c6b2020-11-11 21:13:38 -0800250 if (status.IsOutOfRange()) {
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700251 // Reached the end of the proto.
252 break;
253 }
254
255 // Proto data is malformed.
256 return status;
257 }
258
259 Status status = handler_->ProcessField(*this, decoder_.FieldNumber());
260 if (!status.ok()) {
Wyatt Heplerf276c6b2020-11-11 21:13:38 -0800261 state_ = status.IsCancelled() ? kDecodeCancelled : kDecodeFailed;
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700262 return status;
263 }
264
265 // The callback function can modify the decoder's state; check that
266 // everything is still okay.
267 if (state_ == kDecodeFailed) {
268 break;
269 }
270 }
271
Alexei Frolovdea46f72020-01-07 13:28:24 -0800272 if (state_ != kDecodeInProgress) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700273 return Status::DataLoss();
Alexei Frolovdea46f72020-01-07 13:28:24 -0800274 }
275
Alexei Frolovfe9723c2020-05-11 13:20:47 -0700276 state_ = kReady;
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800277 return OkStatus();
Alexei Frolovdea46f72020-01-07 13:28:24 -0800278}
279
Alexei Frolovdea46f72020-01-07 13:28:24 -0800280} // namespace pw::protobuf