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