Coverage Report

Created: 2025-07-23 07:29

/rust/registry/src/index.crates.io-6f17d22bba15001f/lzma-rs-0.2.0/src/encode/xz.rs
Line
Count
Source (jump to first uncovered line)
1
use crate::decode;
2
use crate::encode::lzma2;
3
use crate::encode::util;
4
use crate::xz::{footer, header, CheckMethod, StreamFlags};
5
use byteorder::{LittleEndian, WriteBytesExt};
6
use crc::{crc32, Hasher32};
7
use std::io;
8
use std::io::Write;
9
10
0
pub fn encode_stream<R, W>(input: &mut R, output: &mut W) -> io::Result<()>
11
0
where
12
0
    R: io::BufRead,
13
0
    W: io::Write,
14
0
{
15
0
    let stream_flags = StreamFlags {
16
0
        check_method: CheckMethod::None,
17
0
    };
18
0
19
0
    // Header
20
0
    write_header(output, stream_flags)?;
21
22
    // Block
23
0
    let (unpadded_size, unpacked_size) = write_block(input, output)?;
24
25
    // Index
26
0
    let index_size = write_index(output, unpadded_size, unpacked_size)?;
27
28
    // Footer
29
0
    write_footer(output, stream_flags, index_size)
30
0
}
31
32
0
fn write_header<W>(output: &mut W, stream_flags: StreamFlags) -> io::Result<()>
33
0
where
34
0
    W: io::Write,
35
0
{
36
0
    output.write_all(header::XZ_MAGIC)?;
37
0
    let mut digest = crc32::Digest::new(crc32::IEEE);
38
0
    {
39
0
        let mut digested = util::HasherWrite::new(output, &mut digest);
40
0
        stream_flags.serialize(&mut digested)?;
41
    }
42
0
    let crc32 = digest.sum32();
43
0
    output.write_u32::<LittleEndian>(crc32)?;
44
0
    Ok(())
45
0
}
46
47
0
fn write_footer<W>(output: &mut W, stream_flags: StreamFlags, index_size: usize) -> io::Result<()>
48
0
where
49
0
    W: io::Write,
50
0
{
51
0
    let mut digest = crc32::Digest::new(crc32::IEEE);
52
0
    let mut footer_buf: Vec<u8> = Vec::new();
53
0
    {
54
0
        let mut digested = util::HasherWrite::new(&mut footer_buf, &mut digest);
55
0
56
0
        let backward_size = (index_size >> 2) - 1;
57
0
        digested.write_u32::<LittleEndian>(backward_size as u32)?;
58
0
        stream_flags.serialize(&mut digested)?;
59
    }
60
0
    let crc32 = digest.sum32();
61
0
    output.write_u32::<LittleEndian>(crc32)?;
62
0
    output.write_all(footer_buf.as_slice())?;
63
64
0
    output.write_all(footer::XZ_MAGIC_FOOTER)?;
65
0
    Ok(())
66
0
}
67
68
0
fn write_block<R, W>(input: &mut R, output: &mut W) -> io::Result<(usize, usize)>
69
0
where
70
0
    R: io::BufRead,
71
0
    W: io::Write,
72
0
{
73
0
    let (unpadded_size, unpacked_size) = {
74
0
        let mut count_output = util::CountWrite::new(output);
75
0
76
0
        // Block header
77
0
        let mut digest = crc32::Digest::new(crc32::IEEE);
78
0
        {
79
0
            let mut digested = util::HasherWrite::new(&mut count_output, &mut digest);
80
0
            let header_size = 8;
81
0
            digested.write_u8((header_size >> 2) as u8)?;
82
0
            let flags = 0x00; // 1 filter, no (un)packed size provided
83
0
            digested.write_u8(flags)?;
84
0
            let filter_id = 0x21; // LZMA2
85
0
            digested.write_u8(filter_id)?;
86
0
            let size_of_properties = 1;
87
0
            digested.write_u8(size_of_properties)?;
88
0
            let properties = 22; // TODO
89
0
            digested.write_u8(properties)?;
90
0
            let padding = [0, 0, 0];
91
0
            digested.write_all(&padding)?;
92
        }
93
0
        let crc32 = digest.sum32();
94
0
        count_output.write_u32::<LittleEndian>(crc32)?;
95
96
        // Block
97
0
        let mut count_input = decode::util::CountBufRead::new(input);
98
0
        lzma2::encode_stream(&mut count_input, &mut count_output)?;
99
0
        (count_output.count(), count_input.count())
100
0
    };
101
0
    lzma_info!(
102
0
        "Unpadded size = {}, unpacked_size = {}",
103
0
        unpadded_size,
104
0
        unpacked_size
105
0
    );
106
0
107
0
    let padding_size = ((unpadded_size ^ 0x03) + 1) & 0x03;
108
0
    let padding = vec![0; padding_size];
109
0
    output.write_all(padding.as_slice())?;
110
    // Checksum = None (cf. above)
111
112
0
    Ok((unpadded_size, unpacked_size))
113
0
}
114
115
0
fn write_index<W>(output: &mut W, unpadded_size: usize, unpacked_size: usize) -> io::Result<usize>
116
0
where
117
0
    W: io::Write,
118
0
{
119
0
    let mut count_output = util::CountWrite::new(output);
120
0
121
0
    let mut digest = crc32::Digest::new(crc32::IEEE);
122
0
    {
123
0
        let mut digested = util::HasherWrite::new(&mut count_output, &mut digest);
124
0
        digested.write_u8(0)?; // No more block
125
0
        let num_records = 1;
126
0
        write_multibyte(&mut digested, num_records)?;
127
128
0
        write_multibyte(&mut digested, unpadded_size as u64)?;
129
0
        write_multibyte(&mut digested, unpacked_size as u64)?;
130
    }
131
132
    // Padding
133
0
    let count = count_output.count();
134
0
    let padding_size = ((count ^ 0x03) + 1) & 0x03;
135
0
    {
136
0
        let mut digested = util::HasherWrite::new(&mut count_output, &mut digest);
137
0
        let padding = vec![0; padding_size];
138
0
        digested.write_all(padding.as_slice())?;
139
    }
140
141
0
    let crc32 = digest.sum32();
142
0
    count_output.write_u32::<LittleEndian>(crc32)?;
143
144
0
    Ok(count_output.count())
145
0
}
146
147
0
fn write_multibyte<W>(output: &mut W, mut value: u64) -> io::Result<()>
148
0
where
149
0
    W: io::Write,
150
0
{
151
    loop {
152
0
        let byte = (value & 0x7F) as u8;
153
0
        value >>= 7;
154
0
        if value == 0 {
155
0
            output.write_u8(byte)?;
156
0
            break;
157
        } else {
158
0
            output.write_u8(0x80 | byte)?;
159
        }
160
    }
161
162
0
    Ok(())
163
0
}