openpack 0.2.2

Safe archive-reader for ZIP-derived formats (ZIP, CRX, JAR, APK, IPA) with BOM-safe checks.
Documentation
use std::ops::Range;

use crate::types::OpenPackError;

#[allow(dead_code)]
pub(crate) fn crx_zip_payload_range(bytes: &[u8]) -> Result<Range<usize>, OpenPackError> {
    if bytes.len() < 12 {
        return Err(OpenPackError::InvalidArchive("CRX header too short".into()));
    }

    if &bytes[0..4] != b"Cr24" {
        return Err(OpenPackError::InvalidArchive("not a CRX file".into()));
    }

    let version = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
    if version != 2 && version != 3 {
        return Err(OpenPackError::InvalidArchive(
            "unsupported CRX version".into(),
        ));
    }

    let start = match version {
        2 => {
            if bytes.len() < 16 {
                return Err(OpenPackError::InvalidArchive("CRX header too short".into()));
            }

            let pubkey_len = usize::try_from(u32::from_le_bytes([
                bytes[8], bytes[9], bytes[10], bytes[11],
            ]))
            .map_err(|_| OpenPackError::InvalidArchive("CRX header overflows".into()))?;
            let sig_len = usize::try_from(u32::from_le_bytes([
                bytes[12], bytes[13], bytes[14], bytes[15],
            ]))
            .map_err(|_| OpenPackError::InvalidArchive("CRX header overflows".into()))?;

            16usize
                .checked_add(pubkey_len)
                .and_then(|value| value.checked_add(sig_len))
                .ok_or_else(|| OpenPackError::InvalidArchive("CRX header overflows".into()))?
        }
        3 => {
            let header_len = usize::try_from(u32::from_le_bytes([
                bytes[8], bytes[9], bytes[10], bytes[11],
            ]))
            .map_err(|_| OpenPackError::InvalidArchive("CRX header overflows".into()))?;

            12usize
                .checked_add(header_len)
                .ok_or_else(|| OpenPackError::InvalidArchive("CRX header overflows".into()))?
        }
        _ => unreachable!("validated CRX version"),
    };

    if start >= bytes.len() {
        return Err(OpenPackError::InvalidArchive(
            "invalid CRX header lengths".into(),
        ));
    }

    Ok(start..bytes.len())
}