/rust/registry/src/index.crates.io-1949cf8c6b5b557f/lzma-rs-0.2.0/src/encode/dumbencoder.rs
Line | Count | Source |
1 | | use crate::compress::{Options, UnpackedSize}; |
2 | | use crate::encode::rangecoder; |
3 | | use byteorder::{LittleEndian, WriteBytesExt}; |
4 | | use std::io; |
5 | | |
6 | | pub struct Encoder<'a, W> |
7 | | where |
8 | | W: 'a + io::Write, |
9 | | { |
10 | | rangecoder: rangecoder::RangeEncoder<'a, W>, |
11 | | literal_probs: [[u16; 0x300]; 8], |
12 | | is_match: [u16; 4], // true = LZ, false = literal |
13 | | unpacked_size: UnpackedSize, |
14 | | } |
15 | | |
16 | | const LC: u32 = 3; |
17 | | const LP: u32 = 0; |
18 | | const PB: u32 = 2; |
19 | | |
20 | | impl<'a, W> Encoder<'a, W> |
21 | | where |
22 | | W: io::Write, |
23 | | { |
24 | 0 | pub fn from_stream(stream: &'a mut W, options: &Options) -> io::Result<Self> { |
25 | 0 | let dict_size = 0x0080_0000; |
26 | | |
27 | | // Properties |
28 | 0 | let props = (LC + 9 * (LP + 5 * PB)) as u8; |
29 | | lzma_info!("Properties {{ lc: {}, lp: {}, pb: {} }}", LC, LP, PB); |
30 | 0 | stream.write_u8(props)?; |
31 | | |
32 | | // Dictionary |
33 | | lzma_info!("Dict size: {}", dict_size); |
34 | 0 | stream.write_u32::<LittleEndian>(dict_size)?; |
35 | | |
36 | | // Unpacked size |
37 | 0 | match &options.unpacked_size { |
38 | 0 | UnpackedSize::WriteToHeader(unpacked_size) => { |
39 | 0 | let value: u64 = match unpacked_size { |
40 | | None => { |
41 | | lzma_info!("Unpacked size: unknown"); |
42 | 0 | 0xFFFF_FFFF_FFFF_FFFF |
43 | | } |
44 | 0 | Some(x) => { |
45 | | lzma_info!("Unpacked size: {}", x); |
46 | 0 | *x |
47 | | } |
48 | | }; |
49 | 0 | stream.write_u64::<LittleEndian>(value)?; |
50 | | } |
51 | 0 | UnpackedSize::SkipWritingToHeader => {} |
52 | | }; |
53 | | |
54 | 0 | let encoder = Encoder { |
55 | 0 | rangecoder: rangecoder::RangeEncoder::new(stream), |
56 | 0 | literal_probs: [[0x400; 0x300]; 8], |
57 | 0 | is_match: [0x400; 4], |
58 | 0 | unpacked_size: options.unpacked_size, |
59 | 0 | }; |
60 | | |
61 | 0 | Ok(encoder) |
62 | 0 | } |
63 | | |
64 | 0 | pub fn process<R>(mut self, input: R) -> io::Result<()> |
65 | 0 | where |
66 | 0 | R: io::Read, |
67 | | { |
68 | 0 | let mut prev_byte = 0u8; |
69 | 0 | let mut input_len = 0; |
70 | | |
71 | 0 | for (out_len, byte_result) in input.bytes().enumerate() { |
72 | 0 | let byte = byte_result?; |
73 | 0 | let pos_state = out_len & 3; |
74 | 0 | input_len = out_len; |
75 | | |
76 | | // Literal |
77 | 0 | self.rangecoder |
78 | 0 | .encode_bit(&mut self.is_match[pos_state], false)?; |
79 | | |
80 | 0 | self.encode_literal(byte, prev_byte)?; |
81 | 0 | prev_byte = byte; |
82 | | } |
83 | | |
84 | 0 | self.finish(input_len + 1) |
85 | 0 | } |
86 | | |
87 | 0 | fn finish(&mut self, input_len: usize) -> io::Result<()> { |
88 | 0 | match self.unpacked_size { |
89 | 0 | UnpackedSize::SkipWritingToHeader | UnpackedSize::WriteToHeader(Some(_)) => {} |
90 | | UnpackedSize::WriteToHeader(None) => { |
91 | | // Write end-of-stream marker |
92 | 0 | let pos_state = input_len & 3; |
93 | | |
94 | | // Match |
95 | 0 | self.rangecoder |
96 | 0 | .encode_bit(&mut self.is_match[pos_state], true)?; |
97 | | // New distance |
98 | 0 | self.rangecoder.encode_bit(&mut 0x400, false)?; |
99 | | |
100 | | // Dummy len, as small as possible (len = 0) |
101 | 0 | for _ in 0..4 { |
102 | 0 | self.rangecoder.encode_bit(&mut 0x400, false)?; |
103 | | } |
104 | | |
105 | | // Distance marker = 0xFFFFFFFF |
106 | | // pos_slot = 63 |
107 | 0 | for _ in 0..6 { |
108 | 0 | self.rangecoder.encode_bit(&mut 0x400, true)?; |
109 | | } |
110 | | // num_direct_bits = 30 |
111 | | // result = 3 << 30 = C000_0000 |
112 | | // + 3FFF_FFF0 (26 bits) |
113 | | // + F ( 4 bits) |
114 | 0 | for _ in 0..30 { |
115 | 0 | self.rangecoder.encode_bit(&mut 0x400, true)?; |
116 | | } |
117 | | // = FFFF_FFFF |
118 | | } |
119 | | } |
120 | | |
121 | | // Flush range coder |
122 | 0 | self.rangecoder.finish() |
123 | 0 | } |
124 | | |
125 | 0 | fn encode_literal(&mut self, byte: u8, prev_byte: u8) -> io::Result<()> { |
126 | 0 | let prev_byte = prev_byte as usize; |
127 | | |
128 | 0 | let mut result: usize = 1; |
129 | 0 | let lit_state = prev_byte >> 5; |
130 | 0 | let probs = &mut self.literal_probs[lit_state]; |
131 | | |
132 | 0 | for i in 0..8 { |
133 | 0 | let bit = ((byte >> (7 - i)) & 1) != 0; |
134 | 0 | self.rangecoder.encode_bit(&mut probs[result], bit)?; |
135 | 0 | result = (result << 1) ^ (bit as usize); |
136 | | } |
137 | | |
138 | 0 | Ok(()) |
139 | 0 | } |
140 | | } |