/src/lzo-2.10/src/lzo1a.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* lzo1a.c -- implementation of the LZO1A algorithm |
2 | | |
3 | | This file is part of the LZO real-time data compression library. |
4 | | |
5 | | Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer |
6 | | All Rights Reserved. |
7 | | |
8 | | The LZO library is free software; you can redistribute it and/or |
9 | | modify it under the terms of the GNU General Public License as |
10 | | published by the Free Software Foundation; either version 2 of |
11 | | the License, or (at your option) any later version. |
12 | | |
13 | | The LZO library is distributed in the hope that it will be useful, |
14 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | GNU General Public License for more details. |
17 | | |
18 | | You should have received a copy of the GNU General Public License |
19 | | along with the LZO library; see the file COPYING. |
20 | | If not, write to the Free Software Foundation, Inc., |
21 | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
22 | | |
23 | | Markus F.X.J. Oberhumer |
24 | | <markus@oberhumer.com> |
25 | | http://www.oberhumer.com/opensource/lzo/ |
26 | | */ |
27 | | |
28 | | |
29 | | #include "lzo_conf.h" |
30 | | #include <lzo/lzo1a.h> |
31 | | |
32 | | |
33 | | /*********************************************************************** |
34 | | // The next two defines can be changed to customize LZO1A. |
35 | | // The default version is LZO1A-5/1. |
36 | | ************************************************************************/ |
37 | | |
38 | | /* run bits (3 - 5) - the compressor and the decompressor |
39 | | * must use the same value. */ |
40 | | #if !defined(RBITS) |
41 | 2.37M | # define RBITS 5 |
42 | | #endif |
43 | | |
44 | | /* compression level (1 - 9) - this only affects the compressor. |
45 | | * 1 is fastest, 9 is best compression ratio |
46 | | */ |
47 | | #if !defined(CLEVEL) |
48 | 0 | # define CLEVEL 1 /* fastest by default */ |
49 | | #endif |
50 | | |
51 | | |
52 | | /* Collect statistics */ |
53 | | #if 0 && !defined(LZO_COLLECT_STATS) |
54 | | # define LZO_COLLECT_STATS 1 |
55 | | #endif |
56 | | |
57 | | |
58 | | /*********************************************************************** |
59 | | // You should not have to change anything below this line. |
60 | | ************************************************************************/ |
61 | | |
62 | | /* check configuration */ |
63 | | #if (RBITS < 3 || RBITS > 5) |
64 | | # error "invalid RBITS" |
65 | | #endif |
66 | | #if (CLEVEL < 1 || CLEVEL > 9) |
67 | | # error "invalid CLEVEL" |
68 | | #endif |
69 | | |
70 | | |
71 | | /*********************************************************************** |
72 | | // internal configuration |
73 | | // all of these affect compression only |
74 | | ************************************************************************/ |
75 | | |
76 | | /* choose the hashing strategy */ |
77 | | #ifndef LZO_HASH |
78 | | #define LZO_HASH LZO_HASH_LZO_INCREMENTAL_A |
79 | | #endif |
80 | 14.8M | #define D_INDEX1(d,p) d = DM(DMUL(0x21,DX2(p,5,5)) >> 5) |
81 | 9.61M | #define D_INDEX2(d,p) d = d ^ D_MASK |
82 | | |
83 | | #include "lzo1a_de.h" |
84 | | #include "stats1a.h" |
85 | | |
86 | | |
87 | | /* check other constants */ |
88 | | #if (LBITS < 5 || LBITS > 8) |
89 | | # error "invalid LBITS" |
90 | | #endif |
91 | | |
92 | | |
93 | | #if (LZO_COLLECT_STATS) |
94 | | static lzo1a_stats_t lzo_statistics; |
95 | | lzo1a_stats_t *lzo1a_stats = &lzo_statistics; |
96 | | # define lzo_stats lzo1a_stats |
97 | | #endif |
98 | | |
99 | | |
100 | | /*********************************************************************** |
101 | | // get algorithm info, return memory required for compression |
102 | | ************************************************************************/ |
103 | | |
104 | | LZO_EXTERN(lzo_uint) lzo1a_info ( int *rbits, int *clevel ); |
105 | | |
106 | | LZO_PUBLIC(lzo_uint) |
107 | | lzo1a_info ( int *rbits, int *clevel ) |
108 | 0 | { |
109 | 0 | if (rbits) |
110 | 0 | *rbits = RBITS; |
111 | 0 | if (clevel) |
112 | 0 | *clevel = CLEVEL; |
113 | 0 | return D_SIZE * lzo_sizeof(lzo_bytep); |
114 | 0 | } |
115 | | |
116 | | |
117 | | /*********************************************************************** |
118 | | // LZO1A decompress a block of data. |
119 | | // |
120 | | // Could be easily translated into assembly code. |
121 | | ************************************************************************/ |
122 | | |
123 | | LZO_PUBLIC(int) |
124 | | lzo1a_decompress ( const lzo_bytep in , lzo_uint in_len, |
125 | | lzo_bytep out, lzo_uintp out_len, |
126 | | lzo_voidp wrkmem ) |
127 | 985 | { |
128 | 985 | lzo_bytep op; |
129 | 985 | const lzo_bytep ip; |
130 | 985 | lzo_uint t; |
131 | 985 | const lzo_bytep m_pos; |
132 | 985 | const lzo_bytep const ip_end = in + in_len; |
133 | | |
134 | 985 | LZO_UNUSED(wrkmem); |
135 | | |
136 | 985 | op = out; |
137 | 985 | ip = in; |
138 | 291k | while (ip < ip_end) |
139 | 290k | { |
140 | 290k | t = *ip++; /* get marker */ |
141 | 290k | LZO_STATS(lzo_stats->marker[t]++); |
142 | | |
143 | 290k | if (t == 0) /* a R0 literal run */ |
144 | 23.2k | { |
145 | 23.2k | t = *ip++; |
146 | 23.2k | if (t >= R0FAST - R0MIN) /* a long R0 run */ |
147 | 10.1k | { |
148 | 10.1k | t -= R0FAST - R0MIN; |
149 | 10.1k | if (t == 0) |
150 | 3.39k | t = R0FAST; |
151 | 6.74k | else |
152 | 6.74k | { |
153 | | #if 0 |
154 | | t = 256u << ((unsigned) t); |
155 | | #else |
156 | | /* help the optimizer */ |
157 | 6.74k | lzo_uint tt = 256; |
158 | 13.0k | do tt <<= 1; while (--t > 0); |
159 | 6.74k | t = tt; |
160 | 6.74k | #endif |
161 | 6.74k | } |
162 | 10.1k | MEMCPY8_DS(op,ip,t); |
163 | 10.1k | continue; |
164 | 10.1k | } |
165 | 13.1k | t += R0MIN; |
166 | 13.1k | goto literal; |
167 | 23.2k | } |
168 | 267k | else if (t < R0MIN) /* a short literal run */ |
169 | 111k | { |
170 | 124k | literal: |
171 | 124k | MEMCPY_DS(op,ip,t); |
172 | | |
173 | | /* after a literal a match must follow */ |
174 | 134k | while (ip < ip_end) |
175 | 133k | { |
176 | 133k | t = *ip++; /* get R1 marker */ |
177 | 133k | if (t >= R0MIN) |
178 | 123k | goto match; |
179 | | |
180 | | /* R1 match - a context sensitive 3 byte match + 1 byte literal */ |
181 | 10.2k | assert((t & OMASK) == t); |
182 | 10.2k | m_pos = op - MIN_OFFSET; |
183 | 10.2k | m_pos -= t | (((lzo_uint) *ip++) << OBITS); |
184 | 10.2k | assert(m_pos >= out); assert(m_pos < op); |
185 | 10.2k | *op++ = m_pos[0]; |
186 | 10.2k | *op++ = m_pos[1]; |
187 | 10.2k | *op++ = m_pos[2]; |
188 | 10.2k | *op++ = *ip++; |
189 | 10.2k | } |
190 | 124k | } |
191 | 156k | else /* a match */ |
192 | 156k | { |
193 | 279k | match: |
194 | | /* get match offset */ |
195 | 279k | m_pos = op - MIN_OFFSET; |
196 | 279k | m_pos -= (t & OMASK) | (((lzo_uint) *ip++) << OBITS); |
197 | 279k | assert(m_pos >= out); assert(m_pos < op); |
198 | | |
199 | | /* get match len */ |
200 | 279k | if (t < ((MSIZE - 1) << OBITS)) /* a short match */ |
201 | 166k | { |
202 | 166k | t >>= OBITS; |
203 | 166k | *op++ = *m_pos++; |
204 | 166k | *op++ = *m_pos++; |
205 | 166k | MEMCPY_DS(op,m_pos,t); |
206 | 166k | } |
207 | 112k | else /* a long match */ |
208 | 112k | { |
209 | | #if (LBITS < 8) |
210 | | t = (MIN_MATCH_LONG - THRESHOLD) + ((lzo_uint)(*ip++) & LMASK); |
211 | | #else |
212 | 112k | t = (MIN_MATCH_LONG - THRESHOLD) + (lzo_uint)(*ip++); |
213 | 112k | #endif |
214 | 112k | *op++ = *m_pos++; |
215 | 112k | *op++ = *m_pos++; |
216 | 112k | MEMCPY_DS(op,m_pos,t); |
217 | | #if (LBITS < 8) |
218 | | /* a very short literal following a long match */ |
219 | | t = ip[-1] >> LBITS; |
220 | | if (t) do |
221 | | *op++ = *ip++; |
222 | | while (--t); |
223 | | #endif |
224 | 112k | } |
225 | 279k | } |
226 | 290k | } |
227 | | |
228 | 985 | *out_len = pd(op, out); |
229 | | |
230 | | /* the next line is the only check in the decompressor */ |
231 | 985 | return (ip == ip_end ? LZO_E_OK : |
232 | 985 | (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); |
233 | 985 | } |
234 | | |
235 | | |
236 | | |
237 | | /*********************************************************************** |
238 | | // LZO1A compress a block of data. |
239 | | // |
240 | | // I apologize for the spaghetti code, but it really helps the optimizer. |
241 | | ************************************************************************/ |
242 | | |
243 | | #include "lzo1a_cr.ch" |
244 | | |
245 | | static int |
246 | | do_compress ( const lzo_bytep in , lzo_uint in_len, |
247 | | lzo_bytep out, lzo_uintp out_len, |
248 | | lzo_voidp wrkmem ) |
249 | 541 | { |
250 | 541 | const lzo_bytep ip; |
251 | 541 | #if defined(__LZO_HASH_INCREMENTAL) |
252 | 541 | lzo_xint dv; |
253 | 541 | #endif |
254 | 541 | const lzo_bytep m_pos; |
255 | 541 | lzo_bytep op; |
256 | 541 | const lzo_bytep const ip_end = in+in_len - DVAL_LEN - MIN_MATCH_LONG; |
257 | 541 | const lzo_bytep const in_end = in+in_len - DVAL_LEN; |
258 | 541 | const lzo_bytep ii; |
259 | 541 | lzo_dict_p const dict = (lzo_dict_p) wrkmem; |
260 | 541 | const lzo_bytep r1 = ip_end; /* pointer for R1 match (none yet) */ |
261 | | #if (LBITS < 8) |
262 | | const lzo_bytep im = ip_end; /* pointer to last match start */ |
263 | | #endif |
264 | | |
265 | | #if !defined(NDEBUG) |
266 | | const lzo_bytep m_pos_sav; |
267 | | #endif |
268 | | |
269 | 541 | op = out; |
270 | 541 | ip = in; |
271 | 541 | ii = ip; /* point to start of current literal run */ |
272 | | |
273 | | /* init dictionary */ |
274 | 541 | #if (LZO_DETERMINISTIC) |
275 | 541 | BZERO8_PTR(wrkmem,sizeof(lzo_dict_t),D_SIZE); |
276 | 541 | #endif |
277 | | |
278 | 541 | DVAL_FIRST(dv,ip); UPDATE_D(dict,0,dv,ip,in); ip++; |
279 | 541 | DVAL_NEXT(dv,ip); |
280 | | |
281 | 14.8M | do { |
282 | 14.8M | LZO_DEFINE_UNINITIALIZED_VAR(lzo_uint, m_off, 0); |
283 | 14.8M | lzo_uint dindex; |
284 | | |
285 | 14.8M | DINDEX1(dindex,ip); |
286 | 14.8M | GINDEX(m_pos,m_off,dict,dindex,in); |
287 | 14.8M | if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,MAX_OFFSET)) |
288 | 5.23M | goto literal; |
289 | 9.61M | if (m_pos[0] == ip[0] && m_pos[1] == ip[1] && m_pos[2] == ip[2]) |
290 | 185k | goto match; |
291 | 9.43M | DINDEX2(dindex,ip); |
292 | 9.43M | GINDEX(m_pos,m_off,dict,dindex,in); |
293 | 9.43M | if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,MAX_OFFSET)) |
294 | 2.61M | goto literal; |
295 | 6.81M | if (m_pos[0] == ip[0] && m_pos[1] == ip[1] && m_pos[2] == ip[2]) |
296 | 46.7k | goto match; |
297 | 6.76M | goto literal; |
298 | | |
299 | 14.6M | literal: |
300 | 14.6M | UPDATE_I(dict,0,dindex,ip,in); |
301 | 14.6M | if (++ip >= ip_end) |
302 | 255 | break; |
303 | 14.6M | continue; |
304 | | |
305 | 14.6M | match: |
306 | 232k | UPDATE_I(dict,0,dindex,ip,in); |
307 | | #if !defined(NDEBUG) && (LZO_DICT_USE_PTR) |
308 | | assert(m_pos == NULL || m_pos >= in); |
309 | | m_pos_sav = m_pos; |
310 | | #endif |
311 | 232k | m_pos += 3; |
312 | 232k | { |
313 | | /* we have found a match (of at least length 3) */ |
314 | | |
315 | | #if !defined(NDEBUG) && !(LZO_DICT_USE_PTR) |
316 | | assert((m_pos_sav = ip - m_off) == (m_pos - 3)); |
317 | | #endif |
318 | | |
319 | 232k | assert(m_pos >= in); |
320 | 232k | assert(ip < ip_end); |
321 | | |
322 | | /* 1) store the current literal run */ |
323 | 232k | if (pd(ip,ii) > 0) |
324 | 111k | { |
325 | 111k | lzo_uint t = pd(ip,ii); |
326 | | |
327 | 111k | if (ip - r1 == MIN_MATCH + 1) |
328 | 7.84k | { |
329 | | /* Code a context sensitive R1 match. |
330 | | * This is tricky and somewhat difficult to explain: |
331 | | * multiplex a literal run of length 1 into the previous |
332 | | * short match of length MIN_MATCH. |
333 | | * The key idea is: |
334 | | * - after a short run a match MUST follow |
335 | | * - therefore the value m = 000 in the mmmooooo marker is free |
336 | | * - use 000ooooo to indicate a MIN_MATCH match (this |
337 | | * is already coded) plus a 1 byte literal |
338 | | */ |
339 | 7.84k | assert(t == 1); |
340 | | /* modify marker byte */ |
341 | 7.84k | assert((op[-2] >> OBITS) == (MIN_MATCH - THRESHOLD)); |
342 | 7.84k | op[-2] &= OMASK; |
343 | 7.84k | assert((op[-2] >> OBITS) == 0); |
344 | | /* copy 1 literal */ |
345 | 7.84k | *op++ = *ii; |
346 | 7.84k | LZO_STATS(lzo_stats->r1_matches++); |
347 | 7.84k | r1 = ip; /* set new R1 pointer */ |
348 | 7.84k | } |
349 | 103k | else if (t < R0MIN) |
350 | 92.4k | { |
351 | | /* inline the copying of a short run */ |
352 | | #if (LBITS < 8) |
353 | | if (t < (1 << (8-LBITS)) && ii - im >= MIN_MATCH_LONG) |
354 | | { |
355 | | /* Code a very short literal run into the |
356 | | * previous long match length byte. |
357 | | */ |
358 | | LZO_STATS(lzo_stats->lit_runs_after_long_match++); |
359 | | LZO_STATS(lzo_stats->lit_run_after_long_match[t]++); |
360 | | assert(ii - im <= MAX_MATCH_LONG); |
361 | | assert((op[-1] >> LBITS) == 0); |
362 | | op[-1] = LZO_BYTE(op[-1] | (t << LBITS)); |
363 | | MEMCPY_DS(op, ii, t); |
364 | | } |
365 | | else |
366 | | #endif |
367 | 92.4k | { |
368 | 92.4k | LZO_STATS(lzo_stats->lit_runs++); |
369 | 92.4k | LZO_STATS(lzo_stats->lit_run[t]++); |
370 | 92.4k | *op++ = LZO_BYTE(t); |
371 | 92.4k | MEMCPY_DS(op, ii, t); |
372 | 92.4k | r1 = ip; /* set new R1 pointer */ |
373 | 92.4k | } |
374 | 92.4k | } |
375 | 11.1k | else if (t < R0FAST) |
376 | 5.99k | { |
377 | | /* inline the copying of a short R0 run */ |
378 | 5.99k | LZO_STATS(lzo_stats->r0short_runs++); |
379 | 5.99k | *op++ = 0; *op++ = LZO_BYTE(t - R0MIN); |
380 | 5.99k | MEMCPY_DS(op, ii, t); |
381 | 5.99k | r1 = ip; /* set new R1 pointer */ |
382 | 5.99k | } |
383 | 5.13k | else |
384 | 5.13k | op = store_run(op,ii,t); |
385 | 111k | } |
386 | | #if (LBITS < 8) |
387 | | im = ip; |
388 | | #endif |
389 | | |
390 | | |
391 | | /* 2) compute match len */ |
392 | 232k | ii = ip; /* point to start of current match */ |
393 | | |
394 | | /* we already matched MIN_MATCH bytes, |
395 | | * m_pos also already advanced MIN_MATCH bytes */ |
396 | 232k | ip += MIN_MATCH; |
397 | 232k | assert(m_pos < ip); |
398 | | |
399 | | /* try to match another MIN_MATCH_LONG - MIN_MATCH bytes |
400 | | * to see if we get a long match */ |
401 | | |
402 | 1.91M | #define PS *m_pos++ != *ip++ |
403 | | |
404 | | #if (MIN_MATCH_LONG - MIN_MATCH == 2) /* MBITS == 2 */ |
405 | | if (PS || PS) |
406 | | #elif (MIN_MATCH_LONG - MIN_MATCH == 6) /* MBITS == 3 */ |
407 | 232k | if (PS || PS || PS || PS || PS || PS) |
408 | | #elif (MIN_MATCH_LONG - MIN_MATCH == 14) /* MBITS == 4 */ |
409 | | if (PS || PS || PS || PS || PS || PS || PS || |
410 | | PS || PS || PS || PS || PS || PS || PS) |
411 | | #elif (MIN_MATCH_LONG - MIN_MATCH == 30) /* MBITS == 5 */ |
412 | | if (PS || PS || PS || PS || PS || PS || PS || PS || |
413 | | PS || PS || PS || PS || PS || PS || PS || PS || |
414 | | PS || PS || PS || PS || PS || PS || PS || PS || |
415 | | PS || PS || PS || PS || PS || PS) |
416 | | #else |
417 | | # error "MBITS not yet implemented" |
418 | | #endif |
419 | 147k | { |
420 | | /* we've found a short match */ |
421 | 147k | lzo_uint m_len; |
422 | | |
423 | | /* 2a) compute match parameters */ |
424 | 147k | assert(ip-m_pos == (int)m_off); |
425 | 147k | --ip; /* ran one too far, point back to non-match */ |
426 | 147k | m_len = pd(ip, ii); |
427 | 147k | assert(m_len >= MIN_MATCH_SHORT); |
428 | 147k | assert(m_len <= MAX_MATCH_SHORT); |
429 | 147k | assert(m_off >= MIN_OFFSET); |
430 | 147k | assert(m_off <= MAX_OFFSET); |
431 | 147k | assert(ii-m_off == m_pos_sav); |
432 | 147k | assert(lzo_memcmp(m_pos_sav,ii,m_len) == 0); |
433 | 147k | m_off -= MIN_OFFSET; |
434 | | |
435 | | /* 2b) code a short match */ |
436 | | /* code short match len + low offset bits */ |
437 | 147k | *op++ = LZO_BYTE(((m_len - THRESHOLD) << OBITS) | |
438 | 147k | (m_off & OMASK)); |
439 | | /* code high offset bits */ |
440 | 147k | *op++ = LZO_BYTE(m_off >> OBITS); |
441 | | |
442 | | |
443 | | #if (LZO_COLLECT_STATS) |
444 | | lzo_stats->short_matches++; |
445 | | lzo_stats->short_match[m_len]++; |
446 | | if (m_off < OSIZE) |
447 | | lzo_stats->short_match_offset_osize[m_len]++; |
448 | | if (m_off < 256) |
449 | | lzo_stats->short_match_offset_256[m_len]++; |
450 | | if (m_off < 1024) |
451 | | lzo_stats->short_match_offset_1024[m_len]++; |
452 | | #endif |
453 | | |
454 | | |
455 | | /* 2c) Insert phrases (beginning with ii+1) into the dictionary. */ |
456 | | |
457 | 147k | #define SI /* nothing */ |
458 | 147k | #define DI ++ii; DVAL_NEXT(dv,ii); UPDATE_D(dict,0,dv,ii,in); |
459 | 232k | #define XI assert(ii < ip); ii = ip; DVAL_FIRST(dv,(ip)); |
460 | | |
461 | | #if (CLEVEL == 9) || (CLEVEL >= 7 && MBITS <= 4) || (CLEVEL >= 5 && MBITS <= 3) |
462 | | /* Insert the whole match (ii+1)..(ip-1) into dictionary. */ |
463 | | ++ii; |
464 | | do { |
465 | | DVAL_NEXT(dv,ii); |
466 | | UPDATE_D(dict,0,dv,ii,in); |
467 | | } while (++ii < ip); |
468 | | DVAL_NEXT(dv,ii); |
469 | | assert(ii == ip); |
470 | | DVAL_ASSERT(dv,ip); |
471 | | #elif (CLEVEL >= 3) |
472 | | SI DI DI XI |
473 | | #elif (CLEVEL >= 2) |
474 | | SI DI XI |
475 | | #else |
476 | 147k | XI |
477 | 147k | #endif |
478 | | |
479 | 147k | } |
480 | 84.6k | else |
481 | 84.6k | { |
482 | | /* we've found a long match - see how far we can still go */ |
483 | 84.6k | const lzo_bytep end; |
484 | 84.6k | lzo_uint m_len; |
485 | | |
486 | 84.6k | assert(ip <= in_end); |
487 | 84.6k | assert(ii == ip - MIN_MATCH_LONG); |
488 | | |
489 | 84.6k | if (pd(in_end,ip) <= (MAX_MATCH_LONG - MIN_MATCH_LONG)) |
490 | 449 | end = in_end; |
491 | 84.1k | else |
492 | 84.1k | { |
493 | 84.1k | end = ip + (MAX_MATCH_LONG - MIN_MATCH_LONG); |
494 | 84.1k | assert(end < in_end); |
495 | 84.1k | } |
496 | | |
497 | 7.75M | while (ip < end && *m_pos == *ip) |
498 | 7.66M | { m_pos++; ip++; } |
499 | 84.6k | assert(ip <= in_end); |
500 | | |
501 | | /* 2a) compute match parameters */ |
502 | 84.6k | m_len = pd(ip, ii); |
503 | 84.6k | assert(m_len >= MIN_MATCH_LONG); |
504 | 84.6k | assert(m_len <= MAX_MATCH_LONG); |
505 | 84.6k | assert(m_off >= MIN_OFFSET); |
506 | 84.6k | assert(m_off <= MAX_OFFSET); |
507 | 84.6k | assert(ii-m_off == m_pos_sav); |
508 | 84.6k | assert(lzo_memcmp(m_pos_sav,ii,m_len) == 0); |
509 | 84.6k | assert(pd(ip,m_pos) == m_off); |
510 | 84.6k | m_off -= MIN_OFFSET; |
511 | | |
512 | | /* 2b) code the long match */ |
513 | | /* code long match flag + low offset bits */ |
514 | 84.6k | *op++ = LZO_BYTE(((MSIZE - 1) << OBITS) | (m_off & OMASK)); |
515 | | /* code high offset bits */ |
516 | 84.6k | *op++ = LZO_BYTE(m_off >> OBITS); |
517 | | /* code match len */ |
518 | 84.6k | *op++ = LZO_BYTE(m_len - MIN_MATCH_LONG); |
519 | | |
520 | | |
521 | | #if (LZO_COLLECT_STATS) |
522 | | lzo_stats->long_matches++; |
523 | | lzo_stats->long_match[m_len]++; |
524 | | #endif |
525 | | |
526 | | |
527 | | /* 2c) Insert phrases (beginning with ii+1) into the dictionary. */ |
528 | | #if (CLEVEL == 9) |
529 | | /* Insert the whole match (ii+1)..(ip-1) into dictionary. */ |
530 | | /* This is not recommended because it is slow. */ |
531 | | ++ii; |
532 | | do { |
533 | | DVAL_NEXT(dv,ii); |
534 | | UPDATE_D(dict,0,dv,ii,in); |
535 | | } while (++ii < ip); |
536 | | DVAL_NEXT(dv,ii); |
537 | | assert(ii == ip); |
538 | | DVAL_ASSERT(dv,ip); |
539 | | #elif (CLEVEL >= 8) |
540 | | SI DI DI DI DI DI DI DI DI XI |
541 | | #elif (CLEVEL >= 7) |
542 | | SI DI DI DI DI DI DI DI XI |
543 | | #elif (CLEVEL >= 6) |
544 | | SI DI DI DI DI DI DI XI |
545 | | #elif (CLEVEL >= 5) |
546 | | SI DI DI DI DI XI |
547 | | #elif (CLEVEL >= 4) |
548 | | SI DI DI DI XI |
549 | | #elif (CLEVEL >= 3) |
550 | | SI DI DI XI |
551 | | #elif (CLEVEL >= 2) |
552 | | SI DI XI |
553 | | #else |
554 | 84.6k | XI |
555 | 84.6k | #endif |
556 | 84.6k | } |
557 | | |
558 | | /* ii now points to the start of the next literal run */ |
559 | 232k | assert(ii == ip); |
560 | 232k | } |
561 | | |
562 | 14.8M | } while (ip < ip_end); |
563 | | |
564 | 541 | assert(ip <= in_end); |
565 | | |
566 | | |
567 | | #if defined(LZO_RETURN_IF_NOT_COMPRESSIBLE) |
568 | | /* return -1 if op == out to indicate that we |
569 | | * couldn't compress and didn't copy anything. |
570 | | */ |
571 | | if (op == out) |
572 | | { |
573 | | *out_len = 0; |
574 | | return LZO_E_NOT_COMPRESSIBLE; |
575 | | } |
576 | | #endif |
577 | | |
578 | | /* store the final literal run */ |
579 | 541 | if (pd(in_end+DVAL_LEN,ii) > 0) |
580 | 541 | op = store_run(op,ii,pd(in_end+DVAL_LEN,ii)); |
581 | | |
582 | 541 | *out_len = pd(op, out); |
583 | 541 | return 0; /* compression went ok */ |
584 | 541 | } |
585 | | |
586 | | |
587 | | /*********************************************************************** |
588 | | // LZO1A compress public entry point. |
589 | | ************************************************************************/ |
590 | | |
591 | | LZO_PUBLIC(int) |
592 | | lzo1a_compress ( const lzo_bytep in , lzo_uint in_len, |
593 | | lzo_bytep out, lzo_uintp out_len, |
594 | | lzo_voidp wrkmem ) |
595 | 549 | { |
596 | 549 | int r = LZO_E_OK; |
597 | | |
598 | | |
599 | | #if (LZO_COLLECT_STATS) |
600 | | lzo_memset(lzo_stats,0,sizeof(*lzo_stats)); |
601 | | lzo_stats->rbits = RBITS; |
602 | | lzo_stats->clevel = CLEVEL; |
603 | | lzo_stats->dbits = DBITS; |
604 | | lzo_stats->lbits = LBITS; |
605 | | lzo_stats->min_match_short = MIN_MATCH_SHORT; |
606 | | lzo_stats->max_match_short = MAX_MATCH_SHORT; |
607 | | lzo_stats->min_match_long = MIN_MATCH_LONG; |
608 | | lzo_stats->max_match_long = MAX_MATCH_LONG; |
609 | | lzo_stats->min_offset = MIN_OFFSET; |
610 | | lzo_stats->max_offset = MAX_OFFSET; |
611 | | lzo_stats->r0min = R0MIN; |
612 | | lzo_stats->r0fast = R0FAST; |
613 | | lzo_stats->r0max = R0MAX; |
614 | | lzo_stats->in_len = in_len; |
615 | | #endif |
616 | | |
617 | | |
618 | | /* don't try to compress a block that's too short */ |
619 | 549 | if (in_len == 0) |
620 | 1 | *out_len = 0; |
621 | 548 | else if (in_len <= MIN_MATCH_LONG + DVAL_LEN + 1) |
622 | 7 | { |
623 | | #if defined(LZO_RETURN_IF_NOT_COMPRESSIBLE) |
624 | | r = LZO_E_NOT_COMPRESSIBLE; |
625 | | #else |
626 | 7 | *out_len = pd(store_run(out,in,in_len), out); |
627 | 7 | #endif |
628 | 7 | } |
629 | 541 | else |
630 | 541 | r = do_compress(in,in_len,out,out_len,wrkmem); |
631 | | |
632 | | |
633 | | #if (LZO_COLLECT_STATS) |
634 | | lzo_stats->short_matches -= lzo_stats->r1_matches; |
635 | | lzo_stats->short_match[MIN_MATCH] -= lzo_stats->r1_matches; |
636 | | lzo_stats->out_len = *out_len; |
637 | | #endif |
638 | | |
639 | 549 | return r; |
640 | 549 | } |
641 | | |
642 | | |
643 | | /* vim:set ts=4 sw=4 et: */ |