/src/zlib-ng/deflate_rle.c
Line | Count | Source |
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 | | #else |
16 | 2.51M | # define compare256_rle compare256_rle_64 |
17 | | #endif |
18 | | |
19 | | /* =========================================================================== |
20 | | * For Z_RLE, simply look for runs of bytes, generate matches only of distance |
21 | | * one. Do not maintain a hash table. (It will be regenerated if this run of |
22 | | * deflate switches away from Z_RLE.) |
23 | | */ |
24 | 4.77k | Z_INTERNAL block_state deflate_rle(deflate_state *s, int flush) { |
25 | 4.77k | unsigned char *window = s->window; |
26 | 4.77k | unsigned char *scan; /* scan goes up to strend for length of run */ |
27 | 4.77k | int bflush = 0; /* set if current block must be flushed */ |
28 | 4.77k | uint32_t match_len = 0; |
29 | | |
30 | 43.5M | for (;;) { |
31 | | /* Make sure that we always have enough lookahead, except |
32 | | * at the end of the input file. We need STD_MAX_MATCH bytes |
33 | | * for the longest run, plus one for the unrolled loop. |
34 | | */ |
35 | 43.5M | if (s->lookahead <= STD_MAX_MATCH) { |
36 | 104k | PREFIX(fill_window)(s); |
37 | 104k | if (s->lookahead <= STD_MAX_MATCH && flush == Z_NO_FLUSH) |
38 | 304 | return need_more; |
39 | 104k | if (s->lookahead == 0) |
40 | 4.33k | break; /* flush the current block */ |
41 | 104k | } |
42 | | |
43 | | /* See how many times the previous byte repeats */ |
44 | 43.5M | if (s->lookahead >= STD_MIN_MATCH && s->strstart > 0) { |
45 | 43.5M | scan = window + s->strstart - 1; |
46 | 43.5M | if (scan[0] == scan[1] && scan[1] == scan[2]) { |
47 | 2.51M | match_len = compare256_rle(scan, scan+3)+2; |
48 | 2.51M | match_len = MIN(match_len, s->lookahead); |
49 | 2.51M | } |
50 | 43.5M | Assert(scan+match_len <= window + s->window_size - 1, "wild scan"); |
51 | 43.5M | } |
52 | | |
53 | | /* Emit match if have run of STD_MIN_MATCH or longer, else emit literal */ |
54 | 43.5M | if (match_len >= STD_MIN_MATCH) { |
55 | 2.38M | Assert(s->strstart <= UINT16_MAX, "strstart should fit in uint16_t"); |
56 | 2.38M | check_match(s, s->strstart, s->strstart - 1, match_len); |
57 | | |
58 | 2.38M | bflush = zng_tr_tally_dist(s, 1, match_len - STD_MIN_MATCH); |
59 | | |
60 | 2.38M | s->lookahead -= match_len; |
61 | 2.38M | s->strstart += match_len; |
62 | 2.38M | match_len = 0; |
63 | 41.1M | } else { |
64 | | /* No match, output a literal byte */ |
65 | 41.1M | bflush = zng_tr_tally_lit(s, window[s->strstart]); |
66 | 41.1M | s->lookahead--; |
67 | 41.1M | s->strstart++; |
68 | 41.1M | } |
69 | 43.5M | if (bflush) |
70 | 43.5M | FLUSH_BLOCK(s, window, 0); |
71 | 43.5M | } |
72 | 4.33k | s->insert = 0; |
73 | 4.33k | if (flush == Z_FINISH) { |
74 | 4.33k | FLUSH_BLOCK(s, window, 1); |
75 | 4.31k | return finish_done; |
76 | 4.33k | } |
77 | 0 | if (s->sym_next) |
78 | 0 | FLUSH_BLOCK(s, window, 0); |
79 | 0 | return block_done; |
80 | 0 | } |