4 * This file provides the code to analyze a buffer of uncompressed data for
5 * matches, as per the LZ77 algorithm. It uses a hash table to accelerate the
6 * process. This is based on code from zlib (v. 1.2.5).
10 * Copyright (C) 2012, 2013 Eric Biggers
11 * Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
13 * This file is part of wimlib, a library for working with WIM files.
15 * wimlib is free software; you can redistribute it and/or modify it under the
16 * terms of the GNU General Public License as published by the Free
17 * Software Foundation; either version 3 of the License, or (at your option)
20 * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
21 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
22 * A PARTICULAR PURPOSE. See the GNU General Public License for more
25 * You should have received a copy of the GNU General Public License
26 * along with wimlib; if not, see http://www.gnu.org/licenses/.
33 #include "wimlib/compress.h"
34 #include "wimlib/util.h"
38 #define LZ_MIN_MATCH 3
41 #define HASH_SIZE (1 << HASH_BITS)
42 #define HASH_MASK (HASH_SIZE - 1)
46 #elif LZ_MIN_MATCH == 3
49 #error "Invalid LZ_MIN_MATCH"
52 /* Hash function, based on code from zlib. This function will update and return
53 * the hash value @hash for the string ending on the additional input character
54 * @c. This function must be called for each consecutive character, because it
55 * uses a running hash value rather than computing it separately for each
58 * The AND operation guarantees that only 3 characters will affect the hash
59 * value, so every identical 3-character string will have the same hash value.
61 static inline unsigned
62 update_hash(unsigned hash, u8 c)
64 return ((hash << HASH_SHIFT) ^ c) & HASH_MASK;
68 /* Insert a 3-character string at position @str_pos in @window and with hash
69 * code @hash into the hash table described by @hash_tab and @prev_tab. Based
72 * The hash table uses chains (linked lists) for the hash buckets, but there are
73 * no real pointers involved. Indexing `hash_tab' by hash value gives the index
74 * within the window of the last string in the hash bucket. To find the index
75 * of the previous string in the hash chain, the `prev_tab' array is indexed by
76 * the string index. `prev_tab' can be indexed repeatedly by the string index
77 * to walk through the hash chain, until the special index `0' is reached,
78 * indicating the end of the hash chain.
80 static inline unsigned
81 insert_string(input_idx_t hash_tab[], input_idx_t prev_tab[],
82 const u8 window[], unsigned str_pos,
85 hash = update_hash(hash, window[str_pos + LZ_MIN_MATCH - 1]);
86 prev_tab[str_pos] = hash_tab[hash];
87 hash_tab[hash] = str_pos;
93 * Returns the longest match for a given input position.
95 * @window: The window of uncompressed data.
96 * @bytes_remaining: The number of bytes remaining in the window.
97 * @strstart: The index of the start of the string in the window that
98 * we are trying to find a match for.
99 * @prev_tab: The array of prev pointers for the hash table.
100 * @cur_match: The index of the head of the hash chain for matches
101 * having the hash value of the string beginning
102 * at index @strstart.
103 * @prev_len: The length of the match that was found for the string
104 * beginning at (@strstart - 1).
105 * @match_start_ret: A location into which the index of the start of the
106 * match will be returned.
107 * @params: Parameters that affect how long the search will proceed
108 * before going with the best that has been found
110 * @min_start_pos: If the chain reaches a match starting before this
111 * position (including the end-of-chain 0), the search will
114 * Returns the length of the match that was found.
117 longest_match(const u8 window[], unsigned bytes_remaining,
118 unsigned strstart, const input_idx_t prev_tab[],
119 unsigned cur_match, unsigned prev_len,
120 unsigned *match_start_ret,
121 const struct lz_params *params,
122 unsigned min_start_pos)
124 unsigned chain_len = params->max_chain_len;
126 const u8 *scan = window + strstart;
129 unsigned best_len = prev_len;
130 unsigned match_start = cur_match;
132 unsigned nice_match = min(params->nice_match, bytes_remaining);
134 const u8 *strend = scan + min(params->max_match, bytes_remaining);
136 u8 scan_end1 = scan[best_len - 1];
137 u8 scan_end = scan[best_len];
140 /* Do not waste too much time if we already have a good match: */
141 if (best_len >= params->good_match)
145 match = &window[cur_match];
147 /* Skip to next match if the match length cannot increase or if
148 * the match length is less than 2. Note that the checks below
149 * for insufficient lookahead only occur occasionally for
150 * performance reasons. Therefore uninitialized memory will be
151 * accessed, and conditional jumps will be made that depend on
152 * those values. However the length of the match is limited to
153 * the lookahead, so the output of lz_analyze_block() is not
154 * affected by the uninitialized values. */
156 if (match[best_len] != scan_end
157 || match[best_len - 1] != scan_end1
159 || *++match != scan[1])
165 } while (scan < strend && *++match == *++scan);
170 *++match == *++scan && *++match == *++scan &&
171 *++match == *++scan && *++match == *++scan &&
172 *++match == *++scan && *++match == *++scan &&
173 *++match == *++scan && *++match == *++scan &&
176 len = match - &window[cur_match];
178 scan = &window[strstart];
180 if (len > best_len) {
181 match_start = cur_match;
183 if (len >= nice_match)
185 scan_end1 = scan[best_len - 1];
186 scan_end = scan[best_len];
188 } while (--chain_len != 0 && (cur_match = prev_tab[cur_match]) >= min_start_pos);
189 *match_start_ret = match_start;
190 return min(min(best_len, bytes_remaining), params->max_match);
196 * Determines the sequence of matches and literals that a block of data will be
199 * @window: The data that is to be compressed.
200 * @window_size: The length of @window, in bytes.
201 * @record_match: Consumer for matches.
202 * @record_literal: Consumer for literals.
203 * @record_ctx: Context passed to @record_match and @record_literal.
204 * @params: Structure that contains parameters that affect how the
205 * analysis proceeds (mainly how good the matches
207 * @prev_tab: Temporary space containing least @window_size elements.
210 lz_analyze_block(const u8 window[],
211 input_idx_t window_size,
212 lz_record_match_t record_match,
213 lz_record_literal_t record_literal,
215 const struct lz_params *params,
216 input_idx_t prev_tab[])
218 unsigned cur_input_pos = 0;
220 unsigned hash_head = 0;
221 unsigned prev_len = params->min_match - 1;
223 unsigned match_len = params->min_match - 1;
224 unsigned match_start = 0;
225 bool match_available = false;
226 input_idx_t hash_tab[HASH_SIZE];
227 unsigned min_start_pos = 1;
229 ZERO_ARRAY(hash_tab);
232 /* If there are at least 3 characters remaining in the input,
233 * insert the 3-character string beginning at
234 * window[cur_input_pos] into the hash table.
236 * hash_head is set to the index of the previous string in the
237 * hash bucket, or 0 if there is no such string */
238 if (window_size - cur_input_pos >= params->min_match) {
239 hash = insert_string(hash_tab, prev_tab,
241 cur_input_pos, hash);
242 hash_head = prev_tab[cur_input_pos];
248 /* Find the longest match, discarding those <= prev_len. */
249 prev_len = match_len;
250 prev_start = match_start;
251 match_len = params->min_match - 1;
253 if (cur_input_pos > params->max_offset)
254 min_start_pos = cur_input_pos - params->max_offset;
258 if (hash_head >= min_start_pos &&
259 prev_len < params->max_lazy_match)
261 /* To simplify the code, we prevent matches with the
262 * string of window index 0 (in particular we have to
263 * avoid a match of the string with itself at the start
264 * of the input file). */
265 match_len = longest_match(window,
266 window_size - cur_input_pos,
267 cur_input_pos, prev_tab,
269 &match_start, params,
272 if (match_len == params->min_match &&
273 cur_input_pos - match_start > params->too_far)
274 match_len = params->min_match - 1;
277 /* If there was a match at the previous step and the current
278 * match is not better, output the previous match:
280 if (prev_len >= params->min_match && match_len <= prev_len) {
283 (*record_match)(prev_len,
284 cur_input_pos - 1 - prev_start,
287 /* Insert in hash table all strings up to the end of the
288 * match. strstart-1 and strstart are already inserted.
289 * If there is not enough lookahead, the last two
290 * strings are not inserted in the hash table. */
292 /* Do not insert strings in hash table beyond this. */
293 unsigned max_insert = window_size - params->min_match;
294 #if LZ_MIN_MATCH == 2
301 if (++cur_input_pos <= max_insert) {
302 hash = insert_string(hash_tab, prev_tab,
307 } while (--prev_len != 0);
309 match_available = false;
310 match_len = params->min_match - 1;
311 } else if (match_available) {
312 /* If there was no match at the previous position,
313 * output a single literal. If there was a match but the
314 * current match is longer, truncate the previous match
315 * to a single literal. */
316 (*record_literal)(window[cur_input_pos - 1], record_ctx);
318 /* There is no previous match to compare with, wait for
319 * the next step to decide. */
320 match_available = true;
322 } while (++cur_input_pos < window_size);
325 (*record_literal)(window[cur_input_pos - 1], record_ctx);