For my future self: The file content is divided into compression units, which comprise as many clusters as indicated by clusters_per_unit. The idea is to iterate over the list of VCNs in the stream content, grouping them by compression unit. If a compression unit begins with a sparse VCN, it is assumed that it is not compressed. If it begins with a real VCN, then it may be compressed,
(vcn_list: &[VCN], cluster_size: usize, clusters_per_unit: usize, file_size: u64, stream_marked_compressed: bool)
| 2774 | by simply joining the content of the VCNs that compose it (here the sparse ones are taken into account). |
| 2775 | */ |
| 2776 | fn process_units(vcn_list: &[VCN], cluster_size: usize, clusters_per_unit: usize, file_size: u64, stream_marked_compressed: bool) -> Option<Vec<u8>> |
| 2777 | { |
| 2778 | if clusters_per_unit <= 0 { // Can this even happen? |
| 2779 | return None; |
| 2780 | } |
| 2781 | |
| 2782 | let bytes_per_unit = clusters_per_unit * cluster_size; |
| 2783 | let total_clusters_needed = ((file_size + (cluster_size as u64) - 1) / (cluster_size as u64)) as usize; // round up |
| 2784 | |
| 2785 | if vcn_list.len() < total_clusters_needed { |
| 2786 | return None; |
| 2787 | } |
| 2788 | |
| 2789 | let mut final_output = Vec::with_capacity(file_size as usize); |
| 2790 | let mut unit_index = 0usize; |
| 2791 | let mut bytes_remaining = file_size as usize; |
| 2792 | |
| 2793 | while bytes_remaining > 0 { |
| 2794 | let start = unit_index * clusters_per_unit; |
| 2795 | let end = (start + clusters_per_unit).min(vcn_list.len()); |
| 2796 | let unit_vcns = &vcn_list[start..end]; |
| 2797 | |
| 2798 | let logical_len = bytes_remaining.min(bytes_per_unit); |
| 2799 | |
| 2800 | let starts_sparse = unit_vcns.first().map(|v| v.is_sparse).unwrap_or(true); |
| 2801 | let first_sparse = unit_vcns.iter().position(|v| v.is_sparse); |
| 2802 | |
| 2803 | // I don't know whether I should keep this check or not |
| 2804 | //let only_tail_sparse = has_sparse && !starts_sparse && !has_sparse_middle; |
| 2805 | |
| 2806 | // Unit candidate to LZNT1 decompression |
| 2807 | let mut produced: Option<Vec<u8>> = None; |
| 2808 | if stream_marked_compressed && !starts_sparse { |
| 2809 | let run_end = first_sparse.unwrap_or(unit_vcns.len()); |
| 2810 | // Adjacent real vcns |
| 2811 | let mut stored_prefix = Vec::new(); |
| 2812 | for i in 0..run_end { |
| 2813 | let v = &unit_vcns[i]; |
| 2814 | let off = i * cluster_size; |
| 2815 | if off >= logical_len { |
| 2816 | break; |
| 2817 | } |
| 2818 | |
| 2819 | // In case we don't have to take the whole content of the last VCN |
| 2820 | // because it would exceed the file size |
| 2821 | let take = (logical_len - off).min(v.content.len()); |
| 2822 | stored_prefix.extend_from_slice(&v.content[..take]); |
| 2823 | } |
| 2824 | |
| 2825 | if !stored_prefix.is_empty() { |
| 2826 | match unsafe { decompress_lznt1_unit(&stored_prefix, bytes_per_unit) } { |
| 2827 | Ok(mut dec) => { |
| 2828 | if dec.len() > logical_len { |
| 2829 | dec.truncate(logical_len); |
| 2830 | } else if dec.len() < logical_len { |
| 2831 | dec.resize(logical_len, 0); // Fill with zeros at the end if needed |
| 2832 | } |
| 2833 |
no test coverage detected