xref: /isa-l/igzip/igzip_base.c (revision 55fbfabfc60f1002bc8133b730a59f6abd22cfce)
1 #include <stdint.h>
2 #include "igzip_lib.h"
3 #include "huffman.h"
4 #include "huff_codes.h"
5 #include "bitbuf2.h"
6 
7 extern const struct isal_hufftables hufftables_default;
8 
9 static inline void
update_state(struct isal_zstream * stream,uint8_t * start_in,uint8_t * next_in,uint8_t * end_in)10 update_state(struct isal_zstream *stream, uint8_t *start_in, uint8_t *next_in, uint8_t *end_in)
11 {
12         struct isal_zstate *state = &stream->internal_state;
13         uint32_t bytes_written;
14 
15         if (next_in - start_in > 0)
16                 state->has_hist = IGZIP_HIST;
17 
18         stream->next_in = next_in;
19         stream->total_in += next_in - start_in;
20         stream->avail_in = end_in - next_in;
21 
22         bytes_written = buffer_used(&state->bitbuf);
23         stream->total_out += bytes_written;
24         stream->next_out += bytes_written;
25         stream->avail_out -= bytes_written;
26 }
27 
28 void
isal_deflate_body_base(struct isal_zstream * stream)29 isal_deflate_body_base(struct isal_zstream *stream)
30 {
31         uint32_t literal, hash;
32         uint8_t *start_in, *next_in, *end_in, *end, *next_hash;
33         uint16_t match_length;
34         uint32_t dist;
35         uint64_t code, code_len, code2, code_len2;
36         struct isal_zstate *state = &stream->internal_state;
37         uint16_t *last_seen = state->head;
38         uint8_t *file_start = (uint8_t *) ((uintptr_t) stream->next_in - stream->total_in);
39         uint32_t hist_size = state->dist_mask;
40         uint32_t hash_mask = state->hash_mask;
41 
42         if (stream->avail_in == 0) {
43                 if (stream->end_of_stream || stream->flush != NO_FLUSH)
44                         state->state = ZSTATE_FLUSH_READ_BUFFER;
45                 return;
46         }
47 
48         set_buf(&state->bitbuf, stream->next_out, stream->avail_out);
49 
50         start_in = stream->next_in;
51         end_in = start_in + stream->avail_in;
52         next_in = start_in;
53 
54         while (next_in + ISAL_LOOK_AHEAD < end_in) {
55 
56                 if (is_full(&state->bitbuf)) {
57                         update_state(stream, start_in, next_in, end_in);
58                         return;
59                 }
60 
61                 literal = load_le_u32(next_in);
62                 hash = compute_hash(literal) & hash_mask;
63                 dist = (next_in - file_start - last_seen[hash]) & 0xFFFF;
64                 last_seen[hash] = (uint64_t) (next_in - file_start);
65 
66                 /* The -1 are to handle the case when dist = 0 */
67                 if (dist - 1 < hist_size) {
68                         assert(dist != 0);
69 
70                         match_length = compare258(next_in - dist, next_in, 258);
71 
72                         if (match_length >= SHORTEST_MATCH) {
73                                 next_hash = next_in;
74 #ifdef ISAL_LIMIT_HASH_UPDATE
75                                 end = next_hash + 3;
76 #else
77                                 end = next_hash + match_length;
78 #endif
79                                 next_hash++;
80 
81                                 for (; next_hash < end; next_hash++) {
82                                         literal = load_le_u32(next_hash);
83                                         hash = compute_hash(literal) & hash_mask;
84                                         last_seen[hash] = (uint64_t) (next_hash - file_start);
85                                 }
86 
87                                 get_len_code(stream->hufftables, match_length, &code, &code_len);
88                                 get_dist_code(stream->hufftables, dist, &code2, &code_len2);
89 
90                                 code |= code2 << code_len;
91                                 code_len += code_len2;
92 
93                                 write_bits(&state->bitbuf, code, code_len);
94 
95                                 next_in += match_length;
96 
97                                 continue;
98                         }
99                 }
100 
101                 get_lit_code(stream->hufftables, literal & 0xFF, &code, &code_len);
102                 write_bits(&state->bitbuf, code, code_len);
103                 next_in++;
104         }
105 
106         update_state(stream, start_in, next_in, end_in);
107 
108         assert(stream->avail_in <= ISAL_LOOK_AHEAD);
109         if (stream->end_of_stream || stream->flush != NO_FLUSH)
110                 state->state = ZSTATE_FLUSH_READ_BUFFER;
111 
112         return;
113 }
114 
115 void
isal_deflate_finish_base(struct isal_zstream * stream)116 isal_deflate_finish_base(struct isal_zstream *stream)
117 {
118         uint32_t literal = 0, hash;
119         uint8_t *start_in, *next_in, *end_in, *end, *next_hash;
120         uint16_t match_length;
121         uint32_t dist;
122         uint64_t code, code_len, code2, code_len2;
123         struct isal_zstate *state = &stream->internal_state;
124         uint16_t *last_seen = state->head;
125         uint8_t *file_start = (uint8_t *) ((uintptr_t) stream->next_in - stream->total_in);
126         uint32_t hist_size = state->dist_mask;
127         uint32_t hash_mask = state->hash_mask;
128 
129         set_buf(&state->bitbuf, stream->next_out, stream->avail_out);
130 
131         start_in = stream->next_in;
132         end_in = start_in + stream->avail_in;
133         next_in = start_in;
134 
135         if (stream->avail_in != 0) {
136                 while (next_in + 3 < end_in) {
137                         if (is_full(&state->bitbuf)) {
138                                 update_state(stream, start_in, next_in, end_in);
139                                 return;
140                         }
141 
142                         literal = load_le_u32(next_in);
143                         hash = compute_hash(literal) & hash_mask;
144                         dist = (next_in - file_start - last_seen[hash]) & 0xFFFF;
145                         last_seen[hash] = (uint64_t) (next_in - file_start);
146 
147                         if (dist - 1 <
148                             hist_size) { /* The -1 are to handle the case when dist = 0 */
149                                 match_length =
150                                         compare258(next_in - dist, next_in, end_in - next_in);
151 
152                                 if (match_length >= SHORTEST_MATCH) {
153                                         next_hash = next_in;
154 #ifdef ISAL_LIMIT_HASH_UPDATE
155                                         end = next_hash + 3;
156 #else
157                                         end = next_hash + match_length;
158 #endif
159                                         next_hash++;
160 
161                                         for (; next_hash < end - 3; next_hash++) {
162                                                 literal = load_le_u32(next_hash);
163                                                 hash = compute_hash(literal) & hash_mask;
164                                                 last_seen[hash] =
165                                                         (uint64_t) (next_hash - file_start);
166                                         }
167 
168                                         get_len_code(stream->hufftables, match_length, &code,
169                                                      &code_len);
170                                         get_dist_code(stream->hufftables, dist, &code2, &code_len2);
171 
172                                         code |= code2 << code_len;
173                                         code_len += code_len2;
174 
175                                         write_bits(&state->bitbuf, code, code_len);
176 
177                                         next_in += match_length;
178 
179                                         continue;
180                                 }
181                         }
182 
183                         get_lit_code(stream->hufftables, literal & 0xFF, &code, &code_len);
184                         write_bits(&state->bitbuf, code, code_len);
185                         next_in++;
186                 }
187 
188                 while (next_in < end_in) {
189                         if (is_full(&state->bitbuf)) {
190                                 update_state(stream, start_in, next_in, end_in);
191                                 return;
192                         }
193 
194                         literal = *next_in;
195                         get_lit_code(stream->hufftables, literal & 0xFF, &code, &code_len);
196                         write_bits(&state->bitbuf, code, code_len);
197                         next_in++;
198                 }
199         }
200 
201         if (!is_full(&state->bitbuf)) {
202                 get_lit_code(stream->hufftables, 256, &code, &code_len);
203                 write_bits(&state->bitbuf, code, code_len);
204                 state->has_eob = 1;
205 
206                 if (stream->end_of_stream == 1)
207                         state->state = ZSTATE_TRL;
208                 else
209                         state->state = ZSTATE_SYNC_FLUSH;
210         }
211 
212         update_state(stream, start_in, next_in, end_in);
213 
214         return;
215 }
216 
217 void
isal_deflate_hash_base(uint16_t * hash_table,uint32_t hash_mask,uint32_t current_index,uint8_t * dict,uint32_t dict_len)218 isal_deflate_hash_base(uint16_t *hash_table, uint32_t hash_mask, uint32_t current_index,
219                        uint8_t *dict, uint32_t dict_len)
220 {
221         uint8_t *next_in = dict;
222         uint8_t *end_in = dict + dict_len - SHORTEST_MATCH;
223         uint32_t literal;
224         uint32_t hash;
225         uint16_t index = current_index - dict_len;
226 
227         while (next_in <= end_in) {
228                 literal = load_le_u32(next_in);
229                 hash = compute_hash(literal) & hash_mask;
230                 hash_table[hash] = index;
231                 index++;
232                 next_in++;
233         }
234 }
235