• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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 #include "pw_software_update/manifest_accessor.h"
15 
16 #include "pw_software_update/config.h"
17 #include "pw_software_update/update_bundle.pwpb.h"
18 #include "pw_software_update/update_bundle_accessor.h"
19 
20 namespace pw::software_update {
21 
FromBundle(protobuf::Message bundle)22 ManifestAccessor ManifestAccessor::FromBundle(protobuf::Message bundle) {
23   protobuf::Message targets_metadata =
24       bundle
25           .AsStringToMessageMap(static_cast<uint32_t>(
26               UpdateBundle::Fields::TARGETS_METADATA))[kTopLevelTargetsName]
27           .AsMessage(static_cast<uint32_t>(
28               SignedTargetsMetadata::Fields::SERIALIZED_TARGETS_METADATA));
29 
30   protobuf::Bytes user_manifest =
31       bundle.AsStringToBytesMap(static_cast<uint32_t>(
32           UpdateBundle::Fields::TARGET_PAYLOADS))[kUserManifestTargetFileName];
33 
34   return ManifestAccessor(targets_metadata, user_manifest);
35 }
36 
FromManifest(protobuf::Message manifest)37 ManifestAccessor ManifestAccessor::FromManifest(protobuf::Message manifest) {
38   protobuf::Message targets_metadata =
39       manifest.AsStringToMessageMap(static_cast<uint32_t>(
40           Manifest::Fields::TARGETS_METADATA))[kTopLevelTargetsName];
41 
42   protobuf::Bytes user_manifest =
43       manifest.AsBytes(static_cast<uint32_t>(Manifest::Fields::USER_MANIFEST));
44 
45   return ManifestAccessor(targets_metadata, user_manifest);
46 }
47 
GetTargetFiles()48 protobuf::RepeatedMessages ManifestAccessor::GetTargetFiles() {
49   PW_TRY(status());
50   return targets_metadata_.AsRepeatedMessages(
51       static_cast<uint32_t>(TargetsMetadata::Fields::TARGET_FILES));
52 }
53 
GetVersion()54 protobuf::Uint32 ManifestAccessor::GetVersion() {
55   PW_TRY(status());
56   return targets_metadata_
57       .AsMessage(
58           static_cast<uint32_t>(TargetsMetadata::Fields::COMMON_METADATA))
59       .AsUint32(static_cast<uint32_t>(CommonMetadata::Fields::VERSION));
60 }
61 
Export(stream::Writer & writer)62 Status ManifestAccessor::Export(stream::Writer& writer) {
63   PW_TRY(status());
64 
65   // Write out the targets metadata map.
66   stream::MemoryReader name_reader(
67       std::as_bytes(std::span(kTopLevelTargetsName)));
68   stream::IntervalReader metadata_reader =
69       targets_metadata_.ToBytes().GetBytesReader();
70   std::byte stream_pipe_buffer[WRITE_MANIFEST_STREAM_PIPE_BUFFER_SIZE];
71   PW_TRY(protobuf::WriteProtoStringToBytesMapEntry(
72       static_cast<uint32_t>(Manifest::Fields::TARGETS_METADATA),
73       name_reader,
74       kTopLevelTargetsName.size(),
75       metadata_reader,
76       metadata_reader.interval_size(),
77       stream_pipe_buffer,
78       writer));
79 
80   // The user manifest is optional, write it out if available().
81   stream::IntervalReader user_manifest_reader = user_manifest_.GetBytesReader();
82   if (user_manifest_reader.ok()) {
83     protobuf::StreamEncoder encoder(writer, {});
84     PW_TRY(encoder.WriteBytesFromStream(
85         static_cast<uint32_t>(Manifest::Fields::USER_MANIFEST),
86         user_manifest_reader,
87         user_manifest_reader.interval_size(),
88         stream_pipe_buffer));
89   }
90 
91   return OkStatus();
92 }
93 
GetTargetFile(protobuf::String name)94 protobuf::Message ManifestAccessor::GetTargetFile(protobuf::String name) {
95   PW_TRY(status());
96 
97   std::array<std::byte, MAX_TARGET_NAME_LENGTH> name_buf = {};
98 
99   stream::IntervalReader name_reader = name.GetBytesReader();
100   PW_TRY(name_reader.status());
101 
102   if (name_reader.interval_size() > name_buf.size()) {
103     return Status::OutOfRange();
104   }
105 
106   Result<ByteSpan> read_result = name_reader.Read(name_buf);
107   PW_TRY(read_result.status());
108 
109   const ConstByteSpan name_span = read_result.value();
110   const std::string_view name_view(
111       reinterpret_cast<const char*>(name_span.data()), name_span.size_bytes());
112 
113   return GetTargetFile(name_view);
114 }
115 
GetTargetFile(std::string_view name)116 protobuf::Message ManifestAccessor::GetTargetFile(std::string_view name) {
117   PW_TRY(status());
118 
119   for (protobuf::Message target_file : GetTargetFiles()) {
120     protobuf::String target_name = target_file.AsString(
121         static_cast<uint32_t>(TargetFile::Fields::FILE_NAME));
122     Result<bool> compare_result = target_name.Equal(name);
123     PW_TRY(compare_result.status());
124     if (compare_result.value()) {
125       return target_file;
126     }
127   }
128 
129   return Status::NotFound();
130 }
131 
132 }  // namespace pw::software_update
133