/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 | } |