precomp2 0.2.0

Reversible preprocessing for compressed and container data.
Documentation
use super::{
  EncodeConfig,
  budget::EncodeBudget,
  deflate::{encode_deflate, encode_zlib},
};
use crate::{error::Result, pcf2::Pcf2Segment};

pub(super) fn encode_zip(input: &[u8], config: &EncodeConfig, depth: u32, budget: &mut EncodeBudget) -> Result<Option<Vec<Pcf2Segment>>> {
  if input.len() < 4 || &input[..4] != b"PK\x03\x04" {
    return Ok(None);
  }
  let mut segments = Vec::new();
  let mut cursor = 0usize;
  let mut offset = 0usize;

  while offset + 30 <= input.len() {
    if &input[offset..offset + 4] != b"PK\x03\x04" {
      break;
    }
    let flags = u16::from_le_bytes([input[offset + 6], input[offset + 7]]);
    if flags & 0x0008 != 0 {
      return Ok(None);
    }
    let compression = u16::from_le_bytes([input[offset + 8], input[offset + 9]]);
    let compressed_size = u32::from_le_bytes([input[offset + 18], input[offset + 19], input[offset + 20], input[offset + 21]]) as usize;
    let name_len = u16::from_le_bytes([input[offset + 26], input[offset + 27]]) as usize;
    let extra_len = u16::from_le_bytes([input[offset + 28], input[offset + 29]]) as usize;
    let data_start = offset + 30 + name_len + extra_len;
    let data_end = data_start + compressed_size;
    if data_end > input.len() {
      break;
    }

    if cursor < data_start {
      segments.push(Pcf2Segment::lit(input[cursor..data_start].to_vec()));
    }

    if compression == 8 {
      if let Some(segment) = encode_deflate(&input[data_start..data_end], config, depth, budget)? {
        segments.push(segment);
      } else {
        return Ok(None);
      }
    } else {
      segments.push(Pcf2Segment::lit(input[data_start..data_end].to_vec()));
    }

    cursor = data_end;
    offset = data_end;
  }

  if segments.is_empty() {
    return Ok(None);
  }

  if cursor < input.len() {
    segments.push(Pcf2Segment::lit(input[cursor..].to_vec()));
  }

  Ok(Some(segments))
}

pub(super) fn encode_swf(input: &[u8], config: &EncodeConfig, depth: u32, budget: &mut EncodeBudget) -> Result<Option<Vec<Pcf2Segment>>> {
  if input.len() < 8 {
    return Ok(None);
  }
  if &input[..3] != b"CWS" {
    return Ok(None);
  }
  let header = &input[..8];
  let body = &input[8..];
  let mut segments = Vec::new();
  segments.push(Pcf2Segment::lit(header.to_vec()));
  if let Some(segment) = encode_zlib(body, config, depth, budget)? {
    segments.push(segment);
  } else {
    return Ok(None);
  }
  Ok(Some(segments))
}