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 
update_state(struct isal_zstream * stream,uint8_t * start_in,uint8_t * next_in,uint8_t * end_in)9 static inline void update_state(struct isal_zstream *stream, uint8_t * start_in,
10 				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 
isal_deflate_body_base(struct isal_zstream * stream)29 void 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_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_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,
88 					     &code_len);
89 				get_dist_code(stream->hufftables, dist, &code2, &code_len2);
90 
91 				code |= code2 << code_len;
92 				code_len += code_len2;
93 
94 				write_bits(&state->bitbuf, code, code_len);
95 
96 				next_in += match_length;
97 
98 				continue;
99 			}
100 		}
101 
102 		get_lit_code(stream->hufftables, literal & 0xFF, &code, &code_len);
103 		write_bits(&state->bitbuf, code, code_len);
104 		next_in++;
105 	}
106 
107 	update_state(stream, start_in, next_in, end_in);
108 
109 	assert(stream->avail_in <= ISAL_LOOK_AHEAD);
110 	if (stream->end_of_stream || stream->flush != NO_FLUSH)
111 		state->state = ZSTATE_FLUSH_READ_BUFFER;
112 
113 	return;
114 
115 }
116 
isal_deflate_finish_base(struct isal_zstream * stream)117 void isal_deflate_finish_base(struct isal_zstream *stream)
118 {
119 	uint32_t literal = 0, hash;
120 	uint8_t *start_in, *next_in, *end_in, *end, *next_hash;
121 	uint16_t match_length;
122 	uint32_t dist;
123 	uint64_t code, code_len, code2, code_len2;
124 	struct isal_zstate *state = &stream->internal_state;
125 	uint16_t *last_seen = state->head;
126 	uint8_t *file_start = (uint8_t *) ((uintptr_t) stream->next_in - stream->total_in);
127 	uint32_t hist_size = state->dist_mask;
128 	uint32_t hash_mask = state->hash_mask;
129 
130 	set_buf(&state->bitbuf, stream->next_out, stream->avail_out);
131 
132 	start_in = stream->next_in;
133 	end_in = start_in + stream->avail_in;
134 	next_in = start_in;
135 
136 	if (stream->avail_in != 0) {
137 		while (next_in + 3 < end_in) {
138 			if (is_full(&state->bitbuf)) {
139 				update_state(stream, start_in, next_in, end_in);
140 				return;
141 			}
142 
143 			literal = load_u32(next_in);
144 			hash = compute_hash(literal) & hash_mask;
145 			dist = (next_in - file_start - last_seen[hash]) & 0xFFFF;
146 			last_seen[hash] = (uint64_t) (next_in - file_start);
147 
148 			if (dist - 1 < 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_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,
171 						      &code_len2);
172 
173 					code |= code2 << code_len;
174 					code_len += code_len2;
175 
176 					write_bits(&state->bitbuf, code, code_len);
177 
178 					next_in += match_length;
179 
180 					continue;
181 				}
182 			}
183 
184 			get_lit_code(stream->hufftables, literal & 0xFF, &code, &code_len);
185 			write_bits(&state->bitbuf, code, code_len);
186 			next_in++;
187 
188 		}
189 
190 		while (next_in < end_in) {
191 			if (is_full(&state->bitbuf)) {
192 				update_state(stream, start_in, next_in, end_in);
193 				return;
194 			}
195 
196 			literal = *next_in;
197 			get_lit_code(stream->hufftables, literal & 0xFF, &code, &code_len);
198 			write_bits(&state->bitbuf, code, code_len);
199 			next_in++;
200 
201 		}
202 	}
203 
204 	if (!is_full(&state->bitbuf)) {
205 		get_lit_code(stream->hufftables, 256, &code, &code_len);
206 		write_bits(&state->bitbuf, code, code_len);
207 		state->has_eob = 1;
208 
209 		if (stream->end_of_stream == 1)
210 			state->state = ZSTATE_TRL;
211 		else
212 			state->state = ZSTATE_SYNC_FLUSH;
213 	}
214 
215 	update_state(stream, start_in, next_in, end_in);
216 
217 	return;
218 }
219 
isal_deflate_hash_base(uint16_t * hash_table,uint32_t hash_mask,uint32_t current_index,uint8_t * dict,uint32_t dict_len)220 void isal_deflate_hash_base(uint16_t * hash_table, uint32_t hash_mask,
221 			    uint32_t current_index, uint8_t * dict, uint32_t dict_len)
222 {
223 	uint8_t *next_in = dict;
224 	uint8_t *end_in = dict + dict_len - SHORTEST_MATCH;
225 	uint32_t literal;
226 	uint32_t hash;
227 	uint16_t index = current_index - dict_len;
228 
229 	while (next_in <= end_in) {
230 		literal = load_u32(next_in);
231 		hash = compute_hash(literal) & hash_mask;
232 		hash_table[hash] = index;
233 		index++;
234 		next_in++;
235 	}
236 }
237