aboutsummaryrefslogtreecommitdiff
path: root/pw_protobuf/message.cc
diff options
context:
space:
mode:
authorYecheng Zhao <zyecheng@google.com>2021-09-06 10:26:04 -0700
committerCQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>2021-09-18 00:35:32 +0000
commit321fb69c2a67f4c301a463b7dc99c7b395511fe1 (patch)
tree0e41f8f9bc11e015b41663d38cefa36e437c2871 /pw_protobuf/message.cc
parent545d4974536994c391c77ee0e72b88aa3f0c1592 (diff)
downloadpigweed-321fb69c2a67f4c301a463b7dc99c7b395511fe1.tar.gz
pw_protobuf: Adds a Message class for parsing
Implement a `Message` class for processing common field types such as uint32, string, bytes, map<string, >, repeated and nested messages. The class works on top of protobuf::StreamDecoder. The purpose is to wrap low level details of StreamDecoder operations, and have an abstraction layer where proto messages and fields can be represented and handled like objects. This faciliates implementation of higher level functionalities that involves sophisticated processing logic on proto messages, such as update bundle verification. Bug: 456 Change-Id: I75c30e183c9df0e260f251f51363d3dc79d36703 Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/60780 Reviewed-by: Armando Montanez <amontanez@google.com> Reviewed-by: Ali Zhang <alizhang@google.com> Commit-Queue: Yecheng Zhao <zyecheng@google.com>
Diffstat (limited to 'pw_protobuf/message.cc')
-rw-r--r--pw_protobuf/message.cc184
1 files changed, 184 insertions, 0 deletions
diff --git a/pw_protobuf/message.cc b/pw_protobuf/message.cc
new file mode 100644
index 000000000..fa4c69f63
--- /dev/null
+++ b/pw_protobuf/message.cc
@@ -0,0 +1,184 @@
+// Copyright 2021 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include "pw_protobuf/message.h"
+
+#include <cstddef>
+
+#include "pw_protobuf/serialized_size.h"
+#include "pw_protobuf/stream_decoder.h"
+#include "pw_result/result.h"
+#include "pw_status/status_with_size.h"
+#include "pw_stream/interval_reader.h"
+#include "pw_stream/stream.h"
+
+namespace pw::protobuf {
+
+template <>
+Uint32 Message::Field::As<Uint32>() {
+ protobuf::StreamDecoder decoder(field_reader_.Reset());
+ PW_TRY(decoder.Next());
+ return decoder.ReadUint32();
+}
+
+template <>
+Int32 Message::Field::As<Int32>() {
+ protobuf::StreamDecoder decoder(field_reader_.Reset());
+ PW_TRY(decoder.Next());
+ return decoder.ReadInt32();
+}
+
+template <>
+Sint32 Message::Field::As<Sint32>() {
+ protobuf::StreamDecoder decoder(field_reader_.Reset());
+ PW_TRY(decoder.Next());
+ return decoder.ReadSint32();
+}
+
+template <>
+Fixed32 Message::Field::As<Fixed32>() {
+ protobuf::StreamDecoder decoder(field_reader_.Reset());
+ PW_TRY(decoder.Next());
+ return decoder.ReadFixed32();
+}
+
+template <>
+Sfixed32 Message::Field::As<Sfixed32>() {
+ protobuf::StreamDecoder decoder(field_reader_.Reset());
+ PW_TRY(decoder.Next());
+ return decoder.ReadSfixed32();
+}
+
+template <>
+Uint64 Message::Field::As<Uint64>() {
+ protobuf::StreamDecoder decoder(field_reader_.Reset());
+ PW_TRY(decoder.Next());
+ return decoder.ReadUint64();
+}
+
+template <>
+Int64 Message::Field::As<Int64>() {
+ protobuf::StreamDecoder decoder(field_reader_.Reset());
+ PW_TRY(decoder.Next());
+ return decoder.ReadInt64();
+}
+
+template <>
+Sint64 Message::Field::As<Sint64>() {
+ protobuf::StreamDecoder decoder(field_reader_.Reset());
+ PW_TRY(decoder.Next());
+ return decoder.ReadSint64();
+}
+
+template <>
+Fixed64 Message::Field::As<Fixed64>() {
+ protobuf::StreamDecoder decoder(field_reader_.Reset());
+ PW_TRY(decoder.Next());
+ return decoder.ReadFixed64();
+}
+
+template <>
+Sfixed64 Message::Field::As<Sfixed64>() {
+ protobuf::StreamDecoder decoder(field_reader_.Reset());
+ PW_TRY(decoder.Next());
+ return decoder.ReadSfixed64();
+}
+
+Result<bool> Bytes::Equal(ConstByteSpan bytes) {
+ stream::IntervalReader bytes_reader = GetBytesReader();
+ if (bytes_reader.interval_size() != bytes.size()) {
+ return false;
+ }
+
+ std::byte buf[1];
+ for (size_t i = 0; i < bytes.size();) {
+ Result<ByteSpan> res = bytes_reader.Read(buf);
+ PW_TRY(res.status());
+ if (res.value().size() == 1) {
+ if (buf[0] != bytes[i++])
+ return false;
+ }
+ }
+
+ return true;
+}
+
+Result<bool> String::Equal(std::string_view str) {
+ return Bytes::Equal(std::as_bytes(std::span{str}));
+}
+
+Message::iterator& Message::iterator::operator++() {
+ // Store the starting offset of the field.
+ size_t field_start = reader_.current();
+ protobuf::StreamDecoder decoder(reader_);
+ Status status = decoder.Next();
+ if (status.IsOutOfRange()) {
+ eof_ = true;
+ return *this;
+ }
+
+ PW_CHECK(status.ok());
+ Result<uint32_t> field_number = decoder.FieldNumber();
+ // Consume the field so that the reader will be pointing to the start
+ // of the next field, which is equivalent to the end offset of the
+ // current field.
+ PW_CHECK(ConsumeCurrentField(decoder).ok());
+
+ // Create a Field object with the field interval.
+ current_ = Field(stream::IntervalReader(
+ reader_.source_reader(), field_start, reader_.current()),
+ field_number.value());
+ return *this;
+}
+
+Message::iterator Message::begin() {
+ PW_CHECK(ok());
+ return iterator(reader_.Reset());
+}
+
+Message::iterator Message::end() {
+ PW_CHECK(ok());
+ // The end iterator is created by using an exahusted stream::IntervalReader,
+ // i.e. the reader is pointing at the internval end.
+ stream::IntervalReader reader_end = reader_;
+ PW_CHECK(reader_end.Seek(0, stream::Stream::Whence::kEnd).ok());
+ return iterator(reader_end);
+}
+
+RepeatedBytes Message::AsRepeatedBytes(uint32_t field_number) {
+ return AsRepeated<Bytes>(field_number);
+}
+
+RepeatedFieldParser<String> Message::AsRepeatedStrings(uint32_t field_number) {
+ return AsRepeated<String>(field_number);
+}
+
+RepeatedFieldParser<Message> Message::AsRepeatedMessages(
+ uint32_t field_number) {
+ return AsRepeated<Message>(field_number);
+}
+
+StringMapParser<Message> Message::AsStringToMessageMap(uint32_t field_number) {
+ return AsStringMap<Message>(field_number);
+}
+
+StringMapParser<Bytes> Message::AsStringToBytesMap(uint32_t field_number) {
+ return AsStringMap<Bytes>(field_number);
+}
+
+StringMapParser<String> Message::AsStringToStringMap(uint32_t field_number) {
+ return AsStringMap<String>(field_number);
+}
+
+} // namespace pw::protobuf