1use super::encode::BROTLI_NUM_DISTANCE_SHORT_CODES;
2use super::util::Log2FloorNonZero;
3#[derive(Copy, Clone, Debug)]
4pub struct BrotliDistanceParams {
5 pub distance_postfix_bits: u32,
6 pub num_direct_distance_codes: u32,
7 pub alphabet_size: u32,
8 pub max_distance: usize,
9}
10
11#[derive(Clone, Copy, Debug, Default)]
12pub struct Command {
13 pub insert_len_: u32,
15 pub copy_len_: u32,
16 pub dist_extra_: u32,
18 pub cmd_prefix_: u16,
19 pub dist_prefix_: u16,
21}
22
23pub fn CommandCopyLen(xself: &Command) -> u32 {
24 xself.copy_len_ & 0x1ffffffu32
25}
26
27pub fn CommandDistanceContext(xself: &Command) -> u32 {
28 let r: u32 = (xself.cmd_prefix_ as i32 >> 6) as u32;
29 let c: u32 = (xself.cmd_prefix_ as i32 & 7i32) as u32;
30 if (r == 0u32 || r == 2u32 || r == 4u32 || r == 7u32) && (c <= 2u32) {
31 c
32 } else {
33 3u32
34 }
35}
36
37#[inline(always)]
38pub fn ComputeDistanceCode(distance: usize, max_distance: usize, dist_cache: &[i32]) -> usize {
39 if distance <= max_distance {
40 let distance_plus_3: usize = distance.wrapping_add(3);
41 let offset0: usize = distance_plus_3.wrapping_sub(dist_cache[0] as usize);
42 let offset1: usize = distance_plus_3.wrapping_sub(dist_cache[1] as usize);
43 if distance == dist_cache[0] as usize {
44 return 0usize;
45 } else if distance == dist_cache[1] as usize {
46 return 1;
47 } else if offset0 < 7usize {
48 return (0x9750468i32 >> (4usize).wrapping_mul(offset0) & 0xfi32) as usize;
49 } else if offset1 < 7usize {
50 return (0xfdb1acei32 >> (4usize).wrapping_mul(offset1) & 0xfi32) as usize;
51 } else if distance == dist_cache[2] as usize {
52 return 2usize;
53 } else if distance == dist_cache[3] as usize {
54 return 3usize;
55 }
56 }
57 distance.wrapping_add(16).wrapping_sub(1)
58}
59
60#[inline(always)]
61pub fn GetInsertLengthCode(insertlen: usize) -> u16 {
62 if insertlen < 6usize {
63 insertlen as u16
64 } else if insertlen < 130usize {
65 let nbits: u32 = Log2FloorNonZero(insertlen.wrapping_sub(2) as u64).wrapping_sub(1);
66 ((nbits << 1) as usize)
67 .wrapping_add(insertlen.wrapping_sub(2) >> nbits)
68 .wrapping_add(2) as u16
69 } else if insertlen < 2114usize {
70 Log2FloorNonZero(insertlen.wrapping_sub(66) as u64).wrapping_add(10) as u16
71 } else if insertlen < 6210usize {
72 21u32 as u16
73 } else if insertlen < 22594usize {
74 22u32 as u16
75 } else {
76 23u32 as u16
77 }
78}
79
80#[inline(always)]
81pub fn GetCopyLengthCode(copylen: usize) -> u16 {
82 if copylen < 10usize {
83 copylen.wrapping_sub(2) as u16
84 } else if copylen < 134usize {
85 let nbits: u32 = Log2FloorNonZero(copylen.wrapping_sub(6) as u64).wrapping_sub(1);
86 ((nbits << 1) as usize)
87 .wrapping_add(copylen.wrapping_sub(6) >> nbits)
88 .wrapping_add(4) as u16
89 } else if copylen < 2118usize {
90 Log2FloorNonZero(copylen.wrapping_sub(70) as u64).wrapping_add(12) as u16
91 } else {
92 23u32 as u16
93 }
94}
95
96#[inline(always)]
97pub fn CombineLengthCodes(inscode: u16, copycode: u16, use_last_distance: i32) -> u16 {
98 let bits64: u16 = (copycode as u32 & 0x7u32 | (inscode as u32 & 0x7u32) << 3) as u16;
99 if use_last_distance != 0 && ((inscode as i32) < 8i32) && ((copycode as i32) < 16i32) {
100 if (copycode as i32) < 8i32 {
101 bits64
102 } else {
103 let s64: u16 = 64u16;
104 (bits64 as i32 | s64 as i32) as u16
105 }
106 } else {
107 let sub_offset: i32 = 2i32 * ((copycode as i32 >> 3) + 3i32 * (inscode as i32 >> 3));
108 let offset = (sub_offset << 5) + 0x40i32 + (0x520d40i32 >> sub_offset & 0xc0i32);
109 (offset as u16 as i32 | bits64 as i32) as u16
110 }
111}
112
113#[inline(always)]
114pub fn GetLengthCode(insertlen: usize, copylen: usize, use_last_distance: i32, code: &mut u16) {
115 let inscode: u16 = GetInsertLengthCode(insertlen);
116 let copycode: u16 = GetCopyLengthCode(copylen);
117 *code = CombineLengthCodes(inscode, copycode, use_last_distance);
118}
119pub fn PrefixEncodeCopyDistance(
120 distance_code: usize,
121 num_direct_codes: usize,
122 postfix_bits: u64,
123 code: &mut u16,
124 extra_bits: &mut u32,
125) {
126 if distance_code < (BROTLI_NUM_DISTANCE_SHORT_CODES as usize).wrapping_add(num_direct_codes) {
127 *code = distance_code as u16;
128 *extra_bits = 0u32;
129 } else {
130 let dist: u64 = (1u64 << postfix_bits.wrapping_add(2u32 as (u64))).wrapping_add(
131 (distance_code as u64)
132 .wrapping_sub(BROTLI_NUM_DISTANCE_SHORT_CODES as u64)
133 .wrapping_sub(num_direct_codes as u64),
134 );
135 let bucket: u64 = Log2FloorNonZero(dist).wrapping_sub(1) as (u64);
136 let postfix_mask: u64 = (1u32 << postfix_bits).wrapping_sub(1) as (u64);
137 let postfix: u64 = dist & postfix_mask;
138 let prefix: u64 = (dist >> bucket) & 1;
139 let offset: u64 = (2u64).wrapping_add(prefix) << bucket;
140 let nbits: u64 = bucket.wrapping_sub(postfix_bits);
141 *code = ((nbits << 10)
142 | ((BROTLI_NUM_DISTANCE_SHORT_CODES as u64)
143 .wrapping_add(num_direct_codes as u64)
144 .wrapping_add(
145 2u64.wrapping_mul(nbits.wrapping_sub(1))
146 .wrapping_add(prefix)
147 << postfix_bits,
148 )
149 .wrapping_add(postfix))) as u16;
150 *extra_bits = (dist.wrapping_sub(offset) >> postfix_bits) as u32;
151 }
158}
159pub fn CommandRestoreDistanceCode(xself: &Command, dist: &BrotliDistanceParams) -> u32 {
160 if (xself.dist_prefix_ as i32 & 0x3ff)
161 < BROTLI_NUM_DISTANCE_SHORT_CODES as i32 + dist.num_direct_distance_codes as i32
162 {
163 xself.dist_prefix_ as u32 & 0x3ff
164 } else {
165 let dcode = xself.dist_prefix_ as u32 & 0x3ff;
166 let nbits: u32 = u32::from(xself.dist_prefix_ >> 10);
167 let extra: u32 = xself.dist_extra_;
168 let postfix_mask = (1u32 << dist.distance_postfix_bits) - 1;
169 let hcode = dcode
170 .wrapping_sub(dist.num_direct_distance_codes)
171 .wrapping_sub(BROTLI_NUM_DISTANCE_SHORT_CODES)
172 >> dist.distance_postfix_bits;
173 let lcode = dcode
174 .wrapping_sub(dist.num_direct_distance_codes)
175 .wrapping_sub(BROTLI_NUM_DISTANCE_SHORT_CODES)
176 & postfix_mask;
177 let offset = (2u32.wrapping_add((hcode & 1)) << nbits).wrapping_sub(4);
178 (offset.wrapping_add(extra) << dist.distance_postfix_bits)
179 .wrapping_add(lcode)
180 .wrapping_add(dist.num_direct_distance_codes)
181 .wrapping_add(BROTLI_NUM_DISTANCE_SHORT_CODES)
182 }
183}
184
185pub fn CommandDistanceIndexAndOffset(cmd: &Command, dist: &BrotliDistanceParams) -> (usize, isize) {
187 let n_postfix = dist.distance_postfix_bits;
188 let n_direct = dist.num_direct_distance_codes;
189 let dextra = cmd.dist_extra_;
190 let dprefix = cmd.dist_prefix_ & 0x3ff;
191 let n_dist_bits = cmd.dist_prefix_ >> 10;
192 if u32::from(dprefix) < BROTLI_NUM_DISTANCE_SHORT_CODES {
193 let table: [(usize, isize); 16] = [
194 (1, 0),
195 (2, 0),
196 (3, 0),
197 (4, 0),
198 (1, -1),
199 (1, 1),
200 (1, -2),
201 (1, 2),
202 (1, -3),
203 (1, 3),
204 (2, -1),
205 (2, 1),
206 (2, -2),
207 (2, 2),
208 (2, -3),
209 (2, 3),
210 ];
211 return table[dprefix as usize];
213 }
214 if (dprefix as usize) < BROTLI_NUM_DISTANCE_SHORT_CODES as usize + n_direct as usize {
215 let ret = dprefix as isize + 1 - BROTLI_NUM_DISTANCE_SHORT_CODES as isize;
216 return (0, ret);
218 }
219 let postfix_mask = (1 << n_postfix) - 1;
220 let dcode = dprefix as u32 - BROTLI_NUM_DISTANCE_SHORT_CODES - n_direct;
221 let hcode = dcode >> n_postfix;
222 let lcode = dcode & postfix_mask;
223 let offset = ((2 + (hcode & 1)) << n_dist_bits) - 4;
224
225 let ret = (((offset + dextra) << n_postfix) + lcode + n_direct + 1) as isize;
226 (0, ret)
228}
229
230mod test {
231 #[cfg(test)]
233 pub fn helperCommandDistanceIndexAndOffset(
234 cmd: &super::Command,
235 dist: &super::BrotliDistanceParams,
236 ) -> (usize, isize) {
237 let n_postfix = dist.distance_postfix_bits;
238 let n_direct = dist.num_direct_distance_codes;
239 let dextra = cmd.dist_extra_;
240 let dist_prefix = cmd.dist_prefix_ & 0x3ff;
241 if dist_prefix < 16 {
242 let table: [(usize, isize); 16] = [
243 (1, 0),
244 (2, 0),
245 (3, 0),
246 (4, 0),
247 (1, -1),
248 (1, 1),
249 (1, -2),
250 (1, 2),
251 (1, -3),
252 (1, 3),
253 (2, -1),
254 (2, 1),
255 (2, -2),
256 (2, 2),
257 (2, -3),
258 (2, 3),
259 ];
260 return table[cmd.dist_prefix_ as usize];
261 }
262 if (dist_prefix as usize) < 16 + n_direct as usize {
263 return (0, dist_prefix as isize + 1 - 16);
264 }
265 let postfix_mask = (1 << n_postfix) - 1;
266 let dcode = dist_prefix as u32 - 16 - n_direct;
267 let n_dist_bits = 1 + (dcode >> (n_postfix + 1));
268
269 let hcode = dcode >> n_postfix;
270 let lcode = dcode & postfix_mask;
271 let offset = ((2 + (hcode & 1)) << n_dist_bits) - 4;
272 (
273 0,
274 (((offset + dextra) << n_postfix) + lcode + n_direct + 1) as isize,
275 )
276 }
277 #[test]
278 fn test_command_return_distance_index_offset() {
279 let param = super::BrotliDistanceParams {
280 distance_postfix_bits: 2,
281 num_direct_distance_codes: 16,
282 alphabet_size: 224,
283 max_distance: 268435456,
284 };
285 let mut cmd = super::Command::default();
286 cmd.insert_len_ = 63;
287 cmd.copy_len_ = 3;
288 cmd.dist_extra_ = 3;
289 cmd.cmd_prefix_ = 297;
290 cmd.dist_prefix_ = 2089;
291
292 assert_eq!(super::CommandDistanceIndexAndOffset(&cmd, ¶m), (0, 46));
293 assert_eq!(
294 super::CommandDistanceIndexAndOffset(&cmd, ¶m),
295 helperCommandDistanceIndexAndOffset(&cmd, ¶m)
296 );
297 cmd = super::Command {
298 insert_len_: 27,
299 copy_len_: 3,
300 dist_extra_: 0,
301 cmd_prefix_: 281,
302 dist_prefix_: 6,
303 };
304 assert_eq!(super::CommandDistanceIndexAndOffset(&cmd, ¶m), (1, -2));
305 assert_eq!(
306 super::CommandDistanceIndexAndOffset(&cmd, ¶m),
307 helperCommandDistanceIndexAndOffset(&cmd, ¶m)
308 );
309 cmd = super::Command {
310 insert_len_: 1,
311 copy_len_: 3,
312 dist_extra_: 0,
313 cmd_prefix_: 137,
314 dist_prefix_: 27,
315 };
316 assert_eq!(super::CommandDistanceIndexAndOffset(&cmd, ¶m), (0, 12));
317 assert_eq!(
318 super::CommandDistanceIndexAndOffset(&cmd, ¶m),
319 helperCommandDistanceIndexAndOffset(&cmd, ¶m)
320 );
321 cmd = super::Command {
322 insert_len_: 5,
323 copy_len_: 4,
324 dist_extra_: 297,
325 cmd_prefix_: 170,
326 dist_prefix_: 11377,
327 };
328 assert_eq!(
329 super::CommandDistanceIndexAndOffset(&cmd, ¶m),
330 (0, 17574)
331 );
332 assert_eq!(
333 super::CommandDistanceIndexAndOffset(&cmd, ¶m),
334 helperCommandDistanceIndexAndOffset(&cmd, ¶m)
335 );
336 super::super::encode::InitInsertCommand(&mut cmd, 24);
337 assert_eq!(super::CommandDistanceIndexAndOffset(&cmd, ¶m), (0, 1));
338 }
339 }
356pub fn RecomputeDistancePrefixes(
357 cmds: &mut [Command],
358 num_commands: usize,
359 num_direct_distance_codes: u32,
360 distance_postfix_bits: u32,
361 dist: &BrotliDistanceParams,
362) {
363 let mut i: usize;
364 if num_direct_distance_codes == 0u32 && (distance_postfix_bits == 0u32) {
365 return;
366 }
367 i = 0usize;
368 while i < num_commands {
369 {
370 let cmd: &mut Command = &mut cmds[i];
371 if CommandCopyLen(cmd) != 0 && (cmd.cmd_prefix_ as i32 >= 128i32) {
372 PrefixEncodeCopyDistance(
373 CommandRestoreDistanceCode(cmd, dist) as usize,
374 num_direct_distance_codes as usize,
375 distance_postfix_bits as (u64),
376 &mut cmd.dist_prefix_,
377 &mut cmd.dist_extra_,
378 );
379 }
380 }
381 i = i.wrapping_add(1);
382 }
383}
384
385pub fn InitCommand(
386 xself: &mut Command,
387 dist: &BrotliDistanceParams,
388 insertlen: usize,
389 copylen: usize,
390 copylen_code: usize,
391 distance_code: usize,
392) {
393 xself.insert_len_ = insertlen as u32;
394 let copylen_code_delta = (copylen_code as i32 - copylen as i32) as i8;
395 xself.copy_len_ = (copylen as u32 | (u32::from(copylen_code_delta as u8) << 25));
396 PrefixEncodeCopyDistance(
397 distance_code,
398 dist.num_direct_distance_codes as usize,
399 u64::from(dist.distance_postfix_bits),
400 &mut xself.dist_prefix_,
401 &mut xself.dist_extra_,
402 );
403 GetLengthCode(
404 insertlen,
405 copylen_code,
406 if (xself.dist_prefix_ & 0x3ff) == 0 {
407 1
408 } else {
409 0
410 },
411 &mut xself.cmd_prefix_,
412 );
413}
414pub fn NewCommand(
415 dist: &BrotliDistanceParams,
416 insertlen: usize,
417 copylen: usize,
418 copylen_code: usize,
419 distance_code: usize,
420) -> Command {
421 let mut xself: Command = Command {
422 insert_len_: insertlen as u32,
423 copy_len_: (copylen | ((copylen_code ^ copylen) << 25)) as u32,
424 dist_extra_: 0,
425 cmd_prefix_: 0,
426 dist_prefix_: 0,
427 };
428 InitCommand(
429 &mut xself,
430 dist,
431 insertlen,
432 copylen,
433 copylen_code,
434 distance_code,
435 );
436 xself
437}