use alloc::vec;
use alloc::vec::Vec;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum DetectedType {
Jpeg,
Png,
Mp3,
Mp4,
Gif,
Encrypted,
Zip,
Pdf,
Docx,
Unknown,
}
impl DetectedType {
pub fn detect(data: &[u8]) -> Self {
if data.len() < 4 {
return Self::Unknown;
}
if data[0] == 0xFF && data[1] == 0xD8 && data[2] == 0xFF {
return Self::Jpeg;
}
if data[0..4] == [0x89, 0x50, 0x4E, 0x47] {
return Self::Png;
}
if data.len() >= 6 && &data[0..6] == b"GIF87a"
|| (data.len() >= 6 && &data[0..6] == b"GIF89a")
{
return Self::Gif;
}
if data[0..3] == [0x49, 0x44, 0x33] || (data[0] == 0xFF && (data[1] & 0xE0) == 0xE0) {
return Self::Mp3;
}
if data.len() >= 8 && &data[4..8] == b"ftyp" {
return Self::Mp4;
}
if data[0..2] == [0x50, 0x4B] {
if data.len() > 100
&& data[30..100]
.windows(19)
.any(|w| w == b"[Content_Types].xml")
{
return Self::Docx;
}
return Self::Zip;
}
if data.len() >= 4 && &data[0..4] == b"%PDF" {
return Self::Pdf;
}
if data.len() >= 512 {
let entropy = Self::calculate_entropy(&data[..512]);
if entropy > 7.9 {
return Self::Encrypted;
}
} else if data.len() >= 64 {
let entropy = Self::calculate_entropy(data);
if entropy > 7.8 {
return Self::Encrypted;
}
}
Self::Unknown
}
pub fn calculate_entropy(data: &[u8]) -> f64 {
if data.is_empty() {
return 0.0;
}
let mut counts = [0usize; 256];
for &b in data {
counts[b as usize] += 1;
}
let len = data.len() as f64;
let mut entropy = 0.0;
#[cfg(feature = "std")]
{
for &c in &counts {
if c > 0 {
let p = c as f64 / len;
entropy -= p * p.log2();
}
}
}
#[cfg(not(feature = "std"))]
{
let unique = counts.iter().filter(|&&c| c > 0).count();
entropy = (unique as f64 / 256.0) * 8.0;
}
entropy
}
}
pub struct DeltaTransform;
impl DeltaTransform {
#[inline]
pub fn encode(data: &[u8]) -> Vec<u8> {
if data.is_empty() {
return Vec::new();
}
let mut result = Vec::with_capacity(data.len());
result.push(data[0]);
for w in data.windows(2) {
result.push(w[1].wrapping_sub(w[0]));
}
result
}
#[inline]
pub fn decode(data: &[u8]) -> Vec<u8> {
if data.is_empty() {
return Vec::new();
}
let mut result = Vec::with_capacity(data.len());
result.push(data[0]);
let mut prev = data[0];
for &b in &data[1..] {
prev = b.wrapping_add(prev);
result.push(prev);
}
result
}
}
pub struct PredictiveDelta;
impl PredictiveDelta {
#[inline]
pub fn encode(data: &[u8]) -> Vec<u8> {
if data.len() < 2 {
return data.to_vec();
}
let mut result = Vec::with_capacity(data.len());
result.push(data[0]);
result.push(data[1].wrapping_sub(data[0]));
for i in 2..data.len() {
let pred = data[i - 1].wrapping_add(data[i - 1].wrapping_sub(data[i - 2]));
result.push(data[i].wrapping_sub(pred));
}
result
}
#[inline]
pub fn decode(data: &[u8]) -> Vec<u8> {
if data.len() < 2 {
return data.to_vec();
}
let mut result = Vec::with_capacity(data.len());
result.push(data[0]);
result.push(data[1].wrapping_add(data[0]));
for i in 2..data.len() {
let pred = result[i - 1].wrapping_add(result[i - 1].wrapping_sub(result[i - 2]));
result.push(data[i].wrapping_add(pred));
}
result
}
}
pub struct BlockDeltaTransform {
pub block_size: usize,
}
impl BlockDeltaTransform {
pub fn new(block_size: usize) -> Self {
Self {
block_size: block_size.max(1),
}
}
pub fn encode(&self, data: &[u8]) -> Vec<u8> {
if data.len() <= self.block_size {
return data.to_vec();
}
let mut result = Vec::with_capacity(data.len());
result.extend_from_slice(&data[..self.block_size]);
for i in self.block_size..data.len() {
result.push(data[i].wrapping_sub(data[i - self.block_size]));
}
result
}
pub fn decode(&self, data: &[u8]) -> Vec<u8> {
if data.len() <= self.block_size {
return data.to_vec();
}
let mut result = Vec::with_capacity(data.len());
result.extend_from_slice(&data[..self.block_size]);
for i in self.block_size..data.len() {
result.push(data[i].wrapping_add(result[i - self.block_size]));
}
result
}
}
pub struct ChannelSeparator {
pub channels: usize,
}
impl ChannelSeparator {
pub fn new(channels: usize) -> Self {
Self {
channels: channels.max(1),
}
}
pub fn separate_yuv(&self, data: &[u8]) -> Vec<u8> {
if self.channels != 3 || data.len() % 3 != 0 {
return self.separate(data);
}
let n = data.len() / 3;
let mut result = vec![0u8; data.len()];
for i in 0..n {
let r = data[i * 3] as i32;
let g = data[i * 3 + 1] as i32;
let b = data[i * 3 + 2] as i32;
let y = (r + 2 * g + b) / 4;
let u = r - g;
let v = b - g;
result[i] = y as u8;
result[i + n] = (u + 128) as u8;
result[i + 2 * n] = (v + 128) as u8;
}
result
}
pub fn interleave_yuv(&self, data: &[u8]) -> Vec<u8> {
if self.channels != 3 || data.len() % 3 != 0 {
return self.interleave(data);
}
let n = data.len() / 3;
let mut result = vec![0u8; data.len()];
for i in 0..n {
let y = data[i] as i32;
let u = data[i + n] as i32 - 128;
let v = data[i + 2 * n] as i32 - 128;
let g = y - (u + v) / 4;
let r = u + g;
let b = v + g;
result[i * 3] = r.clamp(0, 255) as u8;
result[i * 3 + 1] = g.clamp(0, 255) as u8;
result[i * 3 + 2] = b.clamp(0, 255) as u8;
}
result
}
pub fn separate(&self, data: &[u8]) -> Vec<u8> {
let len = data.len();
if len == 0 {
return Vec::new();
}
let mut result = Vec::with_capacity(len);
for ch in 0..self.channels {
for i in (ch..len).step_by(self.channels) {
result.push(data[i]);
}
}
result
}
pub fn interleave(&self, data: &[u8]) -> Vec<u8> {
let len = data.len();
if len == 0 {
return Vec::new();
}
let mut result = vec![0u8; len];
let mut in_idx = 0;
let base_chunk = len / self.channels;
let rem = len % self.channels;
for ch in 0..self.channels {
let chunk_len = if ch < rem { base_chunk + 1 } else { base_chunk };
for i in 0..chunk_len {
let out_idx = i * self.channels + ch;
if out_idx < len && in_idx < len {
result[out_idx] = data[in_idx];
in_idx += 1;
}
}
}
result
}
}
pub struct XorDeltaTransform {
pub block_size: usize,
}
impl XorDeltaTransform {
pub fn new(block_size: usize) -> Self {
Self {
block_size: block_size.max(1),
}
}
#[inline]
pub fn encode(&self, data: &[u8]) -> Vec<u8> {
if data.len() <= self.block_size {
return data.to_vec();
}
let mut result = Vec::with_capacity(data.len());
result.extend_from_slice(&data[..self.block_size]);
for i in self.block_size..data.len() {
result.push(data[i] ^ data[i - self.block_size]);
}
result
}
#[inline]
pub fn decode(&self, data: &[u8]) -> Vec<u8> {
if data.len() <= self.block_size {
return data.to_vec();
}
let mut result = Vec::with_capacity(data.len());
result.extend_from_slice(&data[..self.block_size]);
for i in self.block_size..data.len() {
result.push(data[i] ^ result[i - self.block_size]);
}
result
}
}
pub struct MultiByteXor {
pub width: usize,
}
impl MultiByteXor {
pub fn new(width: usize) -> Self {
Self {
width: width.max(1),
}
}
#[inline]
pub fn encode(&self, data: &[u8]) -> Vec<u8> {
if data.len() <= self.width {
return data.to_vec();
}
let mut result = Vec::with_capacity(data.len());
result.extend_from_slice(&data[..self.width]);
for i in self.width..data.len() {
result.push(data[i] ^ data[i - self.width]);
}
result
}
#[inline]
pub fn decode(&self, data: &[u8]) -> Vec<u8> {
if data.len() <= self.width {
return data.to_vec();
}
let mut result = Vec::with_capacity(data.len());
result.extend_from_slice(&data[..self.width]);
for i in self.width..data.len() {
result.push(data[i] ^ result[i - self.width]);
}
result
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
#[test]
fn test_delta_roundtrip() {
let data = vec![0, 1, 3, 6, 10, 15, 21, 28];
let encoded = DeltaTransform::encode(&data);
let decoded = DeltaTransform::decode(&encoded);
assert_eq!(data, decoded);
}
#[test]
fn test_block_delta_roundtrip() {
let data: Vec<u8> = (0..100).map(|i| (i * 3 % 256) as u8).collect();
let transform = BlockDeltaTransform::new(4);
let encoded = transform.encode(&data);
let decoded = transform.decode(&encoded);
assert_eq!(data, decoded);
}
#[test]
fn test_channel_separator_roundtrip() {
let data: Vec<u8> = (0..90).map(|i| i as u8).collect(); let sep = ChannelSeparator::new(3);
let separated = sep.separate(&data);
let interleaved = sep.interleave(&separated);
assert_eq!(data, interleaved);
}
#[test]
fn test_xor_delta_roundtrip() {
let data: Vec<u8> = (0..100).map(|i| (i * 7 % 256) as u8).collect();
let transform = XorDeltaTransform::new(8);
let encoded = transform.encode(&data);
let decoded = transform.decode(&encoded);
assert_eq!(data, decoded);
}
#[test]
fn test_file_type_detection() {
let jpeg = vec![0xFF, 0xD8, 0xFF, 0xE0, 0, 0, 0, 0];
assert_eq!(DetectedType::detect(&jpeg), DetectedType::Jpeg);
let png = vec![0x89, 0x50, 0x4E, 0x47, 0, 0, 0, 0];
assert_eq!(DetectedType::detect(&png), DetectedType::Png);
let mp4 = vec![0, 0, 0, 0, b'f', b't', b'y', b'p'];
assert_eq!(DetectedType::detect(&mp4), DetectedType::Mp4);
}
}