Coverage Report

Created: 2026-02-26 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/exr-1.74.0/src/compression/rle.rs
Line
Count
Source
1
use super::*;
2
use super::optimize_bytes::*;
3
use super::Error;
4
use super::Result;
5
6
// inspired by  https://github.com/openexr/openexr/blob/master/OpenEXR/IlmImf/ImfRle.cpp
7
8
const MIN_RUN_LENGTH : usize = 3;
9
const MAX_RUN_LENGTH : usize = 127;
10
11
12
782k
pub fn decompress_bytes(
13
782k
    channels: &ChannelList,
14
782k
    compressed_le: ByteVec,
15
782k
    rectangle: IntegerBounds,
16
782k
    expected_byte_size: usize,
17
782k
    pedantic: bool,
18
782k
) -> Result<ByteVec> {
19
782k
    let mut remaining_le = compressed_le.as_slice();
20
782k
    let mut decompressed_le = Vec::with_capacity(expected_byte_size.min(8*2048));
21
22
13.0M
    while !remaining_le.is_empty() && decompressed_le.len() != expected_byte_size {
23
12.2M
        let count = take_1(&mut remaining_le)? as i8 as i32;
24
25
12.2M
        if count < 0 {
26
            // take the next '-count' bytes as-is
27
1.03M
            let values = take_n(&mut remaining_le, (-count) as usize)?;
28
1.03M
            decompressed_le.extend_from_slice(values);
29
        }
30
        else {
31
            // repeat the next value 'count + 1' times
32
11.2M
            let value = take_1(&mut remaining_le)?;
33
11.2M
            decompressed_le.resize(decompressed_le.len() + count as usize + 1, value);
34
        }
35
    }
36
37
782k
    if pedantic && !remaining_le.is_empty() {
38
0
        return Err(Error::invalid("data amount"));
39
782k
    }
40
41
782k
    differences_to_samples(&mut decompressed_le);
42
782k
    interleave_byte_blocks(&mut decompressed_le);
43
782k
    super::convert_little_endian_to_current(decompressed_le, channels, rectangle) // TODO no alloc
44
782k
}
45
46
776k
pub fn compress_bytes(channels: &ChannelList, uncompressed_ne: ByteVec, rectangle: IntegerBounds) -> Result<ByteVec> {
47
    // see https://github.com/AcademySoftwareFoundation/openexr/blob/3bd93f85bcb74c77255f28cdbb913fdbfbb39dfe/OpenEXR/IlmImf/ImfTiledOutputFile.cpp#L750-L842
48
776k
    let mut data_le = super::convert_current_to_little_endian(uncompressed_ne, channels, rectangle)?;// TODO no alloc
49
50
776k
    separate_bytes_fragments(&mut data_le);
51
776k
    samples_to_differences(&mut data_le);
52
53
776k
    let mut compressed_le = Vec::with_capacity(data_le.len());
54
776k
    let mut run_start = 0;
55
776k
    let mut run_end = 1;
56
57
9.61M
    while run_start < data_le.len() {
58
        while
59
1.01G
            run_end < data_le.len()
60
1.01G
                && data_le[run_start] == data_le[run_end]
61
1.01G
                && (run_end - run_start) as i32 - 1 < MAX_RUN_LENGTH as i32
62
1.00G
            {
63
1.00G
                run_end += 1;
64
1.00G
            }
65
66
8.84M
        if run_end - run_start >= MIN_RUN_LENGTH {
67
7.95M
            compressed_le.push(((run_end - run_start) as i32 - 1) as u8);
68
7.95M
            compressed_le.push(data_le[run_start]);
69
7.95M
            run_start = run_end;
70
7.95M
71
7.95M
        } else {
72
            while
73
4.48M
                run_end < data_le.len() && (
74
4.48M
                    (run_end + 1 >= data_le.len() || data_le[run_end] != data_le[run_end + 1])
75
875k
                        || (run_end + 2 >= data_le.len() || data_le[run_end + 1] != data_le[run_end + 2])
76
3.62M
                ) && run_end - run_start < MAX_RUN_LENGTH
77
3.60M
                {
78
3.60M
                    run_end += 1;
79
3.60M
                }
80
81
885k
            compressed_le.push((run_start as i32 - run_end as i32) as u8);
82
885k
            compressed_le.extend_from_slice(&data_le[run_start .. run_end]);
83
84
885k
            run_start = run_end;
85
885k
            run_end += 1;
86
        }
87
    }
88
89
776k
    Ok(compressed_le)
90
776k
}
91
92
23.4M
fn take_1(slice: &mut &[u8]) -> Result<u8> {
93
23.4M
    if !slice.is_empty() {
94
23.4M
        let result = slice[0];
95
23.4M
        *slice = &slice[1..];
96
23.4M
        Ok(result)
97
98
    } else {
99
24
        Err(Error::invalid("compressed data"))
100
    }
101
23.4M
}
102
103
1.03M
fn take_n<'s>(slice: &mut &'s [u8], n: usize) -> Result<&'s [u8]> {
104
1.03M
    if n <= slice.len() {
105
1.03M
        let (front, back) = slice.split_at(n);
106
1.03M
        *slice = back;
107
1.03M
        Ok(front)
108
109
    } else {
110
59
        Err(Error::invalid("compressed data"))
111
    }
112
1.03M
}