use crate::{util, ManifestRef, PayloadRef, RestoreInfoRef, Tag};
use der::{
asn1::Ia5StringRef, Decode, DecodeValue, Encode, EncodeValue, FixedTag, Header, Length, Reader,
TagNumber, Writer,
};
#[cfg(any(feature = "alloc", test))]
use {
super::Image,
der::referenced::{OwnedToRef, RefToOwned},
};
#[derive(Clone, Debug)]
pub struct ImageRef<'a> {
pub(super) payload: PayloadRef<'a>,
pub(super) manifest: Option<ManifestRef<'a>>,
pub(super) restore_info: Option<RestoreInfoRef<'a>>,
}
impl<'a> ImageRef<'a> {
pub fn new(tag: Tag, builder_string: &'a str, data: &'a [u8]) -> der::Result<Self> {
Ok(Self {
payload: PayloadRef::new(tag, builder_string, data)?,
manifest: None,
restore_info: None,
})
}
pub fn from_payload(payload: PayloadRef<'a>) -> Self {
Self {
payload,
manifest: None,
restore_info: None,
}
}
pub fn from_payload_bytes(bytes: &'a [u8]) -> der::Result<Self> {
Ok(Self {
payload: PayloadRef::from_der(bytes)?,
manifest: None,
restore_info: None,
})
}
pub fn parse_manifest(&mut self, bytes: &'a [u8]) -> der::Result<()> {
self.manifest = Some(ManifestRef::from_der(bytes)?);
Ok(())
}
pub fn payload(&self) -> &PayloadRef<'a> {
&self.payload
}
pub fn payload_mut(&mut self) -> &mut PayloadRef<'a> {
&mut self.payload
}
pub fn manifest(&self) -> Option<&ManifestRef<'a>> {
self.manifest.as_ref()
}
pub fn manifest_mut(&mut self) -> Option<&mut ManifestRef<'a>> {
self.manifest.as_mut()
}
pub fn set_manifest(&mut self, manifest: Option<ManifestRef<'a>>) {
self.manifest = manifest;
}
pub fn restore_info(&self) -> Option<&RestoreInfoRef<'a>> {
self.restore_info.as_ref()
}
pub fn restore_info_mut(&mut self) -> Option<&mut RestoreInfoRef<'a>> {
self.restore_info.as_mut()
}
pub fn set_restore_info(&mut self, restore_info: Option<RestoreInfoRef<'a>>) {
self.restore_info = restore_info;
}
pub fn decode_after_magic<R: Reader<'a>>(decoder: &mut R) -> der::Result<Self> {
let payload = decoder.decode()?;
let manifest = util::decode_opt_context_specific_field(decoder, TagNumber::N0, true)?;
let restore_info = util::decode_opt_context_specific_field(decoder, TagNumber::N1, true)?;
Ok(ImageRef {
payload,
manifest,
restore_info,
})
}
}
impl FixedTag for ImageRef<'_> {
const TAG: der::Tag = der::Tag::Sequence;
}
impl<'a> DecodeValue<'a> for ImageRef<'a> {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
debug_assert_eq!(header.tag, der::Tag::Sequence);
reader.read_nested(header.length, |reader| {
util::decode_and_check_magic(reader, b"IMG4")?;
ImageRef::decode_after_magic(reader)
})
}
}
impl EncodeValue for ImageRef<'_> {
fn value_len(&self) -> der::Result<Length> {
let magic = Ia5StringRef::new(b"IMG4")?;
let magic_len = magic.encoded_len()?;
let payload_len = self.payload.encoded_len()?;
let manifest_len =
util::encoded_opt_context_specific_field_len(self.manifest(), TagNumber::N0, true)?;
let restore_info_len = util::encoded_opt_context_specific_field_len(
self.restore_info.as_ref(),
TagNumber::N1,
true,
)?;
magic_len + payload_len + manifest_len + restore_info_len
}
fn encode_value(&self, encoder: &mut impl Writer) -> der::Result<()> {
let magic = Ia5StringRef::new(b"IMG4")?;
magic.encode(encoder)?;
self.payload.encode(encoder)?;
util::encode_opt_context_specific_field(encoder, self.manifest(), TagNumber::N0, true)?;
util::encode_opt_context_specific_field(
encoder,
self.restore_info.as_ref(),
TagNumber::N1,
true,
)
}
}
#[cfg(any(feature = "alloc", test))]
impl<'a> From<&'a Image> for ImageRef<'a> {
fn from(value: &'a Image) -> Self {
Self {
payload: value.payload.owned_to_ref(),
manifest: value.manifest.as_ref().map(|m| m.owned_to_ref()),
restore_info: value.restore_info.as_ref().map(OwnedToRef::owned_to_ref),
}
}
}
#[cfg(any(feature = "alloc", test))]
impl<'a> RefToOwned<'a> for ImageRef<'a> {
type Owned = Image;
fn ref_to_owned(&self) -> Self::Owned {
self.into()
}
}