/src/zlib-ng/deflate_rle.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* deflate_rle.c -- compress data using RLE strategy of deflation algorithm |
2 | | * |
3 | | * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler |
4 | | * For conditions of distribution and use, see copyright notice in zlib.h |
5 | | */ |
6 | | |
7 | | #include "zbuild.h" |
8 | | #include "deflate.h" |
9 | | #include "deflate_p.h" |
10 | | #include "functable.h" |
11 | | #include "compare256_rle.h" |
12 | | |
13 | | #if OPTIMAL_CMP == 8 |
14 | | # define compare256_rle compare256_rle_8 |
15 | | #elif defined(HAVE_BUILTIN_CTZLL) |
16 | 79.3k | # define compare256_rle compare256_rle_64 |
17 | | #elif defined(HAVE_BUILTIN_CTZ) |
18 | | # define compare256_rle compare256_rle_32 |
19 | | #else |
20 | | # define compare256_rle compare256_rle_16 |
21 | | #endif |
22 | | |
23 | | /* =========================================================================== |
24 | | * For Z_RLE, simply look for runs of bytes, generate matches only of distance |
25 | | * one. Do not maintain a hash table. (It will be regenerated if this run of |
26 | | * deflate switches away from Z_RLE.) |
27 | | */ |
28 | 1.15k | Z_INTERNAL block_state deflate_rle(deflate_state *s, int flush) { |
29 | 1.15k | int bflush = 0; /* set if current block must be flushed */ |
30 | 1.15k | unsigned char *scan; /* scan goes up to strend for length of run */ |
31 | 1.15k | uint32_t match_len = 0; |
32 | | |
33 | 1.78M | for (;;) { |
34 | | /* Make sure that we always have enough lookahead, except |
35 | | * at the end of the input file. We need STD_MAX_MATCH bytes |
36 | | * for the longest run, plus one for the unrolled loop. |
37 | | */ |
38 | 1.78M | if (s->lookahead <= STD_MAX_MATCH) { |
39 | 89.8k | PREFIX(fill_window)(s); |
40 | 89.8k | if (s->lookahead <= STD_MAX_MATCH && flush == Z_NO_FLUSH) |
41 | 0 | return need_more; |
42 | 89.8k | if (s->lookahead == 0) |
43 | 1.15k | break; /* flush the current block */ |
44 | 89.8k | } |
45 | | |
46 | | /* See how many times the previous byte repeats */ |
47 | 1.78M | if (s->lookahead >= STD_MIN_MATCH && s->strstart > 0) { |
48 | 1.78M | scan = s->window + s->strstart - 1; |
49 | 1.78M | if (scan[0] == scan[1] && scan[1] == scan[2]) { |
50 | 79.3k | match_len = compare256_rle(scan, scan+3)+2; |
51 | 79.3k | match_len = MIN(match_len, s->lookahead); |
52 | 79.3k | match_len = MIN(match_len, STD_MAX_MATCH); |
53 | 79.3k | } |
54 | 1.78M | Assert(scan+match_len <= s->window + s->window_size - 1, "wild scan"); |
55 | 1.78M | } |
56 | | |
57 | | /* Emit match if have run of STD_MIN_MATCH or longer, else emit literal */ |
58 | 1.78M | if (match_len >= STD_MIN_MATCH) { |
59 | 56.4k | Assert(s->strstart <= UINT16_MAX, "strstart should fit in uint16_t"); |
60 | 56.4k | check_match(s, (Pos)s->strstart, (Pos)(s->strstart - 1), match_len); |
61 | | |
62 | 56.4k | bflush = zng_tr_tally_dist(s, 1, match_len - STD_MIN_MATCH); |
63 | | |
64 | 56.4k | s->lookahead -= match_len; |
65 | 56.4k | s->strstart += match_len; |
66 | 56.4k | match_len = 0; |
67 | 1.72M | } else { |
68 | | /* No match, output a literal byte */ |
69 | 1.72M | bflush = zng_tr_tally_lit(s, s->window[s->strstart]); |
70 | 1.72M | s->lookahead--; |
71 | 1.72M | s->strstart++; |
72 | 1.72M | } |
73 | 1.78M | if (bflush) |
74 | 1.78M | FLUSH_BLOCK(s, 0); |
75 | 1.78M | } |
76 | 1.15k | s->insert = 0; |
77 | 1.15k | if (flush == Z_FINISH) { |
78 | 1.15k | FLUSH_BLOCK(s, 1); |
79 | 1.15k | return finish_done; |
80 | 1.15k | } |
81 | 0 | if (s->sym_next) |
82 | 0 | FLUSH_BLOCK(s, 0); |
83 | 0 | return block_done; |
84 | 0 | } |