133 lines
4.5 KiB
C++
133 lines
4.5 KiB
C++
// 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_software_update/manifest_accessor.h"
|
|
|
|
#include "pw_software_update/config.h"
|
|
#include "pw_software_update/update_bundle.pwpb.h"
|
|
#include "pw_software_update/update_bundle_accessor.h"
|
|
|
|
namespace pw::software_update {
|
|
|
|
ManifestAccessor ManifestAccessor::FromBundle(protobuf::Message bundle) {
|
|
protobuf::Message targets_metadata =
|
|
bundle
|
|
.AsStringToMessageMap(static_cast<uint32_t>(
|
|
UpdateBundle::Fields::TARGETS_METADATA))[kTopLevelTargetsName]
|
|
.AsMessage(static_cast<uint32_t>(
|
|
SignedTargetsMetadata::Fields::SERIALIZED_TARGETS_METADATA));
|
|
|
|
protobuf::Bytes user_manifest =
|
|
bundle.AsStringToBytesMap(static_cast<uint32_t>(
|
|
UpdateBundle::Fields::TARGET_PAYLOADS))[kUserManifestTargetFileName];
|
|
|
|
return ManifestAccessor(targets_metadata, user_manifest);
|
|
}
|
|
|
|
ManifestAccessor ManifestAccessor::FromManifest(protobuf::Message manifest) {
|
|
protobuf::Message targets_metadata =
|
|
manifest.AsStringToMessageMap(static_cast<uint32_t>(
|
|
Manifest::Fields::TARGETS_METADATA))[kTopLevelTargetsName];
|
|
|
|
protobuf::Bytes user_manifest =
|
|
manifest.AsBytes(static_cast<uint32_t>(Manifest::Fields::USER_MANIFEST));
|
|
|
|
return ManifestAccessor(targets_metadata, user_manifest);
|
|
}
|
|
|
|
protobuf::RepeatedMessages ManifestAccessor::GetTargetFiles() {
|
|
PW_TRY(status());
|
|
return targets_metadata_.AsRepeatedMessages(
|
|
static_cast<uint32_t>(TargetsMetadata::Fields::TARGET_FILES));
|
|
}
|
|
|
|
protobuf::Uint32 ManifestAccessor::GetVersion() {
|
|
PW_TRY(status());
|
|
return targets_metadata_
|
|
.AsMessage(
|
|
static_cast<uint32_t>(TargetsMetadata::Fields::COMMON_METADATA))
|
|
.AsUint32(static_cast<uint32_t>(CommonMetadata::Fields::VERSION));
|
|
}
|
|
|
|
Status ManifestAccessor::Export(stream::Writer& writer) {
|
|
PW_TRY(status());
|
|
|
|
// Write out the targets metadata map.
|
|
stream::MemoryReader name_reader(
|
|
std::as_bytes(std::span(kTopLevelTargetsName)));
|
|
stream::IntervalReader metadata_reader =
|
|
targets_metadata_.ToBytes().GetBytesReader();
|
|
std::byte stream_pipe_buffer[WRITE_MANIFEST_STREAM_PIPE_BUFFER_SIZE];
|
|
PW_TRY(protobuf::WriteProtoStringToBytesMapEntry(
|
|
static_cast<uint32_t>(Manifest::Fields::TARGETS_METADATA),
|
|
name_reader,
|
|
kTopLevelTargetsName.size(),
|
|
metadata_reader,
|
|
metadata_reader.interval_size(),
|
|
stream_pipe_buffer,
|
|
writer));
|
|
|
|
// The user manifest is optional, write it out if available().
|
|
stream::IntervalReader user_manifest_reader = user_manifest_.GetBytesReader();
|
|
if (user_manifest_reader.ok()) {
|
|
protobuf::StreamEncoder encoder(writer, {});
|
|
PW_TRY(encoder.WriteBytesFromStream(
|
|
static_cast<uint32_t>(Manifest::Fields::USER_MANIFEST),
|
|
user_manifest_reader,
|
|
user_manifest_reader.interval_size(),
|
|
stream_pipe_buffer));
|
|
}
|
|
|
|
return OkStatus();
|
|
}
|
|
|
|
protobuf::Message ManifestAccessor::GetTargetFile(protobuf::String name) {
|
|
PW_TRY(status());
|
|
|
|
std::array<std::byte, MAX_TARGET_NAME_LENGTH> name_buf = {};
|
|
|
|
stream::IntervalReader name_reader = name.GetBytesReader();
|
|
PW_TRY(name_reader.status());
|
|
|
|
if (name_reader.interval_size() > name_buf.size()) {
|
|
return Status::OutOfRange();
|
|
}
|
|
|
|
Result<ByteSpan> read_result = name_reader.Read(name_buf);
|
|
PW_TRY(read_result.status());
|
|
|
|
const ConstByteSpan name_span = read_result.value();
|
|
const std::string_view name_view(
|
|
reinterpret_cast<const char*>(name_span.data()), name_span.size_bytes());
|
|
|
|
return GetTargetFile(name_view);
|
|
}
|
|
|
|
protobuf::Message ManifestAccessor::GetTargetFile(std::string_view name) {
|
|
PW_TRY(status());
|
|
|
|
for (protobuf::Message target_file : GetTargetFiles()) {
|
|
protobuf::String target_name = target_file.AsString(
|
|
static_cast<uint32_t>(TargetFile::Fields::FILE_NAME));
|
|
Result<bool> compare_result = target_name.Equal(name);
|
|
PW_TRY(compare_result.status());
|
|
if (compare_result.value()) {
|
|
return target_file;
|
|
}
|
|
}
|
|
|
|
return Status::NotFound();
|
|
}
|
|
|
|
} // namespace pw::software_update
|