image4 0.8.2

A no_std-friendly library for parsing and generation of Image4 images written in pure Rust.
Documentation
#[cfg(any(feature = "payload", feature = "manifest", feature = "restore_info"))]
use der::{asn1::Ia5StringRef, ErrorKind, Reader};
#[cfg(feature = "payload")]
use {
    core::ops::Add,
    der::{asn1::ContextSpecific, Decode, Encode, Header, Length, TagNumber, Writer},
};

#[cfg(any(feature = "payload", feature = "manifest", feature = "restore_info"))]
pub fn decode_and_check_magic<'a, R: Reader<'a>>(
    decoder: &mut R,
    expected: &[u8; 4],
) -> der::Result<()> {
    let position = decoder.position();
    let magic = decoder.decode::<Ia5StringRef<'a>>()?;
    if magic.as_bytes() == expected {
        Ok(())
    } else {
        Err(ErrorKind::Value {
            tag: der::Tag::Ia5String,
        }
        .at(position))
    }
}

#[cfg(feature = "payload")]
pub fn decode_opt_field<'a, R: Reader<'a>, T: Decode<'a>>(
    decoder: &mut R,
    expected_tag: der::Tag,
) -> der::Result<Option<T>> {
    match decoder.peek_tag() {
        Ok(tag) if tag == expected_tag => decoder.decode::<T>().map(Some),
        Ok(_) => Ok(None),
        Err(e) if matches!(e.kind(), ErrorKind::Incomplete { .. }) => Ok(None),
        Err(e) => Err(e),
    }
}

#[cfg(feature = "payload")]
pub fn decode_opt_context_specific_field<'a, R: Reader<'a>, T: Decode<'a>>(
    decoder: &mut R,
    tag_number: TagNumber,
    constructed: bool,
) -> der::Result<Option<T>> {
    let field: Option<ContextSpecific<T>> = decode_opt_field(
        decoder,
        der::Tag::ContextSpecific {
            constructed,
            number: tag_number,
        },
    )?;
    Ok(field.map(|f| f.value))
}

#[cfg(feature = "payload")]
pub fn encoded_opt_context_specific_field_len<T: Encode>(
    field: Option<&T>,
    tag_number: TagNumber,
    constructed: bool,
) -> der::Result<Length> {
    if let Some(field) = field {
        let tag = der::Tag::ContextSpecific {
            constructed,
            number: tag_number,
        };
        let length = field.encoded_len()?;
        let header = Header { tag, length };

        header.encoded_len()?.add(length)
    } else {
        Ok(Length::ZERO)
    }
}

#[cfg(feature = "payload")]
pub fn encode_opt_context_specific_field<W: Writer, T: Encode>(
    writer: &mut W,
    field: Option<&T>,
    tag_number: TagNumber,
    constructed: bool,
) -> der::Result<()> {
    if let Some(field) = field {
        let tag = der::Tag::ContextSpecific {
            constructed,
            number: tag_number,
        };
        let length = field.encoded_len()?;
        let header = Header { tag, length };

        header.encode(writer)?;
        field.encode(writer)
    } else {
        Ok(())
    }
}

#[cfg(feature = "property")]
pub fn shift_error_position(error: der::Error, position: der::Length) -> der::Error {
    if let Some(cur_position) = error.position() {
        (position + cur_position)
            .map(|position| error.kind().at(position))
            .unwrap_or_else(|e| e)
    } else {
        error
    }
}