preflate-rs 0.6.3

Decompresses existing DEFLATE streams to allow for better compression (eg with ZStandard) while allowing the exact original binary DEFLATE stream to be recreated by detecting the parameters used during compression.
Documentation
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
 *  This software incorporates material from third parties. See NOTICE.txt for details.
 *--------------------------------------------------------------------------------------------*/

use crate::deflate::deflate_token::{DeflateHuffmanType, DeflateToken, DeflateTokenBlock};

pub struct PreflateStreamInfo {
    pub token_count: u32,
    pub literal_count: u32,
    pub reference_count: u32,
    pub max_dist: u32,
    pub min_len: u32,
    pub max_tokens_per_block: u32,
    pub count_blocks: u32,
    pub count_stored_blocks: u32,
    pub count_huff_blocks: u32,
    pub count_rle_blocks: u32,
    pub count_static_huff_tree_blocks: u32,
    pub max_dist_3_matches: u32,
}

fn process_tokens(tokens: &[DeflateToken], result: &mut PreflateStreamInfo) {
    result.token_count += tokens.len() as u32;
    result.max_tokens_per_block = std::cmp::max(result.max_tokens_per_block, tokens.len() as u32);
    let mut block_max_dist = 0;
    let mut block_min_len = u32::MAX;

    for j in 0..tokens.len() {
        match &tokens[j] {
            DeflateToken::Literal(_) => {
                result.literal_count += 1;
            }
            DeflateToken::Reference(t) => {
                result.reference_count += 1;
                block_max_dist = std::cmp::max(block_max_dist, t.dist());
                block_min_len = std::cmp::min(block_min_len, t.len());

                if t.len() == 3 {
                    result.max_dist_3_matches = std::cmp::max(result.max_dist_3_matches, t.dist());
                }
            }
        }
    }
    result.max_dist = std::cmp::max(result.max_dist, block_max_dist);
    result.min_len = std::cmp::min(result.min_len, block_min_len);

    if block_max_dist == 0 {
        result.count_huff_blocks += 1;
    } else if block_max_dist == 1 {
        result.count_rle_blocks += 1;
    }
}

pub(crate) fn extract_preflate_info(blocks: &[DeflateTokenBlock]) -> PreflateStreamInfo {
    let mut result: PreflateStreamInfo = PreflateStreamInfo {
        count_blocks: blocks.len() as u32,
        count_stored_blocks: 0,
        count_static_huff_tree_blocks: 0,
        token_count: 0,
        max_tokens_per_block: 0,
        literal_count: 0,
        reference_count: 0,
        min_len: u32::MAX,
        max_dist: 0,
        count_huff_blocks: 0,
        count_rle_blocks: 0,
        max_dist_3_matches: 0,
    };

    for i in 0..blocks.len() {
        match &blocks[i] {
            DeflateTokenBlock::Stored { .. } => {
                result.count_stored_blocks += 1;
            }
            DeflateTokenBlock::Huffman {
                tokens,
                huffman_type,
            } => {
                if let DeflateHuffmanType::Static { .. } = huffman_type {
                    result.count_static_huff_tree_blocks += 1;
                }
                process_tokens(&tokens, &mut result);
            }
        }
    }
    result
}