• 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::kTargetsMetadata))[kTopLevelTargetsName]
27           .AsMessage(static_cast<uint32_t>(
28               SignedTargetsMetadata::Fields::kSerializedTargetsMetadata));
29 
30   protobuf::Bytes user_manifest =
31       bundle.AsStringToBytesMap(static_cast<uint32_t>(
32           UpdateBundle::Fields::kTargetPayloads))[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::kTargetsMetadata))[kTopLevelTargetsName];
41 
42   protobuf::Bytes user_manifest =
43       manifest.AsBytes(static_cast<uint32_t>(Manifest::Fields::kUserManifest));
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::kTargetFiles));
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::kCommonMetadata))
59       .AsUint32(static_cast<uint32_t>(CommonMetadata::Fields::kVersion));
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(as_bytes(span(kTopLevelTargetsName)));
67   stream::IntervalReader metadata_reader =
68       targets_metadata_.ToBytes().GetBytesReader();
69   std::byte stream_pipe_buffer[WRITE_MANIFEST_STREAM_PIPE_BUFFER_SIZE];
70   PW_TRY(protobuf::WriteProtoStringToBytesMapEntry(
71       static_cast<uint32_t>(Manifest::Fields::kTargetsMetadata),
72       name_reader,
73       kTopLevelTargetsName.size(),
74       metadata_reader,
75       metadata_reader.interval_size(),
76       stream_pipe_buffer,
77       writer));
78 
79   // The user manifest is optional, write it out if available().
80   stream::IntervalReader user_manifest_reader = user_manifest_.GetBytesReader();
81   if (user_manifest_reader.ok()) {
82     protobuf::StreamEncoder encoder(writer, {});
83     PW_TRY(encoder.WriteBytesFromStream(
84         static_cast<uint32_t>(Manifest::Fields::kUserManifest),
85         user_manifest_reader,
86         user_manifest_reader.interval_size(),
87         stream_pipe_buffer));
88   }
89 
90   return OkStatus();
91 }
92 
GetTargetFile(protobuf::String name)93 protobuf::Message ManifestAccessor::GetTargetFile(protobuf::String name) {
94   PW_TRY(status());
95 
96   std::array<std::byte, MAX_TARGET_NAME_LENGTH> name_buf = {};
97 
98   stream::IntervalReader name_reader = name.GetBytesReader();
99   PW_TRY(name_reader.status());
100 
101   if (name_reader.interval_size() > name_buf.size()) {
102     return Status::OutOfRange();
103   }
104 
105   Result<ByteSpan> read_result = name_reader.Read(name_buf);
106   PW_TRY(read_result.status());
107 
108   const ConstByteSpan name_span = read_result.value();
109   const std::string_view name_view(
110       reinterpret_cast<const char*>(name_span.data()), name_span.size_bytes());
111 
112   return GetTargetFile(name_view);
113 }
114 
GetTargetFile(std::string_view name)115 protobuf::Message ManifestAccessor::GetTargetFile(std::string_view name) {
116   PW_TRY(status());
117 
118   for (protobuf::Message target_file : GetTargetFiles()) {
119     protobuf::String target_name = target_file.AsString(
120         static_cast<uint32_t>(TargetFile::Fields::kFileName));
121     Result<bool> compare_result = target_name.Equal(name);
122     PW_TRY(compare_result.status());
123     if (compare_result.value()) {
124       return target_file;
125     }
126   }
127 
128   return Status::NotFound();
129 }
130 
131 }  // namespace pw::software_update
132