blob: d30e2e7d1f8b322616645946a32751b36bd47232 [file] [log] [blame]
Denis Vlasenko052ad9a2009-04-29 12:01:51 +00001/* lzo1x_9x.c -- implementation of the LZO1X-999 compression algorithm
2
3 This file is part of the LZO real-time data compression library.
4
5 Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
6 Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
7 Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
8 Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
9 Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
10 Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
11 Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
12 Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
13 Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
14 Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
15 Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
16 Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
17 Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
18 All Rights Reserved.
19
20 The LZO library is free software; you can redistribute it and/or
21 modify it under the terms of the GNU General Public License as
22 published by the Free Software Foundation; either version 2 of
23 the License, or (at your option) any later version.
24
25 The LZO library is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 GNU General Public License for more details.
29
30 You should have received a copy of the GNU General Public License
31 along with the LZO library; see the file COPYING.
32 If not, write to the Free Software Foundation, Inc.,
33 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
34
35 Markus F.X.J. Oberhumer
36 <markus@oberhumer.com>
37 http://www.oberhumer.com/opensource/lzo/
38*/
39#include "libbb.h"
40
41/* The following is probably only safe on Intel-compatible processors ... */
42#define LZO_UNALIGNED_OK_2
43#define LZO_UNALIGNED_OK_4
44
45#include "liblzo.h"
46
47#define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b))
48#define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b))
49#define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c))
50
51/***********************************************************************
52//
53************************************************************************/
54#define SWD_N M4_MAX_OFFSET /* size of ring buffer */
55#define SWD_F 2048 /* upper limit for match length */
56
57#define SWD_BEST_OFF (LZO_MAX3(M2_MAX_LEN, M3_MAX_LEN, M4_MAX_LEN) + 1)
58
59typedef struct {
60 int init;
61
62 unsigned look; /* bytes in lookahead buffer */
63
64 unsigned m_len;
65 unsigned m_off;
66
67 const uint8_t *bp;
68 const uint8_t *ip;
69 const uint8_t *in;
70 const uint8_t *in_end;
71 uint8_t *out;
72
73 unsigned r1_lit;
74
75} lzo1x_999_t;
76
77#define getbyte(c) ((c).ip < (c).in_end ? *((c).ip)++ : (-1))
78
79/* lzo_swd.c -- sliding window dictionary */
80
81/***********************************************************************
82//
83************************************************************************/
84#define SWD_UINT_MAX USHRT_MAX
85
86#ifndef SWD_HSIZE
87# define SWD_HSIZE 16384
88#endif
89#ifndef SWD_MAX_CHAIN
90# define SWD_MAX_CHAIN 2048
91#endif
92
93#define HEAD3(b, p) \
94 ( ((0x9f5f * ((((b[p]<<5)^b[p+1])<<5) ^ b[p+2])) >> 5) & (SWD_HSIZE-1) )
95
96#if defined(LZO_UNALIGNED_OK_2)
97# define HEAD2(b,p) (* (uint16_t *) &(b[p]))
98#else
99# define HEAD2(b,p) (b[p] ^ ((unsigned)b[p+1]<<8))
100#endif
101#define NIL2 SWD_UINT_MAX
102
103typedef struct lzo_swd {
104 /* public - "built-in" */
105
106 /* public - configuration */
107 unsigned max_chain;
108 int use_best_off;
109
110 /* public - output */
111 unsigned m_len;
112 unsigned m_off;
113 unsigned look;
114 int b_char;
115#if defined(SWD_BEST_OFF)
116 unsigned best_off[SWD_BEST_OFF];
117#endif
118
119 /* semi public */
120 lzo1x_999_t *c;
121 unsigned m_pos;
122#if defined(SWD_BEST_OFF)
123 unsigned best_pos[SWD_BEST_OFF];
124#endif
125
126 /* private */
127 unsigned ip; /* input pointer (lookahead) */
128 unsigned bp; /* buffer pointer */
129 unsigned rp; /* remove pointer */
130
131 unsigned node_count;
132 unsigned first_rp;
133
134 uint8_t b[SWD_N + SWD_F];
135 uint8_t b_wrap[SWD_F]; /* must follow b */
136 uint16_t head3[SWD_HSIZE];
137 uint16_t succ3[SWD_N + SWD_F];
138 uint16_t best3[SWD_N + SWD_F];
139 uint16_t llen3[SWD_HSIZE];
140#ifdef HEAD2
141 uint16_t head2[65536L];
142#endif
143} lzo_swd_t, *lzo_swd_p;
144
145#define SIZEOF_LZO_SWD_T (sizeof(lzo_swd_t))
146
147
148/* Access macro for head3.
149 * head3[key] may be uninitialized, but then its value will never be used.
150 */
151#define s_get_head3(s,key) s->head3[key]
152
153
154/***********************************************************************
155//
156************************************************************************/
157#define B_SIZE (SWD_N + SWD_F)
158
159static int swd_init(lzo_swd_p s)
160{
161 /* defaults */
162 s->node_count = SWD_N;
163
164 memset(s->llen3, 0, sizeof(s->llen3[0]) * (unsigned)SWD_HSIZE);
165#ifdef HEAD2
166 memset(s->head2, 0xff, sizeof(s->head2[0]) * 65536L);
167 assert(s->head2[0] == NIL2);
168#endif
169
170 s->ip = 0;
171 s->bp = s->ip;
172 s->first_rp = s->ip;
173
174 assert(s->ip + SWD_F <= B_SIZE);
175 s->look = (unsigned) (s->c->in_end - s->c->ip);
176 if (s->look > 0) {
177 if (s->look > SWD_F)
178 s->look = SWD_F;
179 memcpy(&s->b[s->ip],s->c->ip,s->look);
180 s->c->ip += s->look;
181 s->ip += s->look;
182 }
183 if (s->ip == B_SIZE)
184 s->ip = 0;
185
186 s->rp = s->first_rp;
187 if (s->rp >= s->node_count)
188 s->rp -= s->node_count;
189 else
190 s->rp += B_SIZE - s->node_count;
191
192 return LZO_E_OK;
193}
194
195#define swd_pos2off(s,pos) \
196 (s->bp > (pos) ? s->bp - (pos) : B_SIZE - ((pos) - s->bp))
197
198
199/***********************************************************************
200//
201************************************************************************/
202static void swd_getbyte(lzo_swd_p s)
203{
204 int c;
205
206 if ((c = getbyte(*(s->c))) < 0) {
207 if (s->look > 0)
208 --s->look;
209 } else {
210 s->b[s->ip] = c;
211 if (s->ip < SWD_F)
212 s->b_wrap[s->ip] = c;
213 }
214 if (++s->ip == B_SIZE)
215 s->ip = 0;
216 if (++s->bp == B_SIZE)
217 s->bp = 0;
218 if (++s->rp == B_SIZE)
219 s->rp = 0;
220}
221
222
223/***********************************************************************
224// remove node from lists
225************************************************************************/
226static void swd_remove_node(lzo_swd_p s, unsigned node)
227{
228 if (s->node_count == 0) {
229 unsigned key;
230
231 key = HEAD3(s->b,node);
232 assert(s->llen3[key] > 0);
233 --s->llen3[key];
234
235#ifdef HEAD2
236 key = HEAD2(s->b,node);
237 assert(s->head2[key] != NIL2);
238 if ((unsigned) s->head2[key] == node)
239 s->head2[key] = NIL2;
240#endif
241 } else
242 --s->node_count;
243}
244
245
246/***********************************************************************
247//
248************************************************************************/
249static void swd_accept(lzo_swd_p s, unsigned n)
250{
251 assert(n <= s->look);
252
253 while (n--) {
254 unsigned key;
255
256 swd_remove_node(s,s->rp);
257
258 /* add bp into HEAD3 */
259 key = HEAD3(s->b,s->bp);
260 s->succ3[s->bp] = s_get_head3(s,key);
261 s->head3[key] = s->bp;
262 s->best3[s->bp] = SWD_F + 1;
263 s->llen3[key]++;
264 assert(s->llen3[key] <= SWD_N);
265
266#ifdef HEAD2
267 /* add bp into HEAD2 */
268 key = HEAD2(s->b,s->bp);
269 s->head2[key] = s->bp;
270#endif
271
272 swd_getbyte(s);
273 }
274}
275
276
277/***********************************************************************
278//
279************************************************************************/
280static void swd_search(lzo_swd_p s, unsigned node, unsigned cnt)
281{
282 const uint8_t *p1;
283 const uint8_t *p2;
284 const uint8_t *px;
285 unsigned m_len = s->m_len;
286 const uint8_t *b = s->b;
287 const uint8_t *bp = s->b + s->bp;
288 const uint8_t *bx = s->b + s->bp + s->look;
289 unsigned char scan_end1;
290
291 assert(s->m_len > 0);
292
293 scan_end1 = bp[m_len - 1];
294 for ( ; cnt-- > 0; node = s->succ3[node]) {
295 p1 = bp;
296 p2 = b + node;
297 px = bx;
298
299 assert(m_len < s->look);
300
301 if (p2[m_len - 1] == scan_end1 &&
302 p2[m_len] == p1[m_len] &&
303 p2[0] == p1[0] &&
304 p2[1] == p1[1]) {
305 unsigned i;
306 assert(lzo_memcmp(bp,&b[node],3) == 0);
307
308 p1 += 2; p2 += 2;
309 do {} while (++p1 < px && *p1 == *++p2);
310 i = p1-bp;
311
312 assert(lzo_memcmp(bp,&b[node],i) == 0);
313
314#if defined(SWD_BEST_OFF)
315 if (i < SWD_BEST_OFF) {
316 if (s->best_pos[i] == 0)
317 s->best_pos[i] = node + 1;
318 }
319#endif
320 if (i > m_len) {
321 s->m_len = m_len = i;
322 s->m_pos = node;
323 if (m_len == s->look)
324 return;
325 if (m_len >= SWD_F)
326 return;
327 if (m_len > (unsigned) s->best3[node])
328 return;
329 scan_end1 = bp[m_len - 1];
330 }
331 }
332 }
333}
334
335
336/***********************************************************************
337//
338************************************************************************/
339#ifdef HEAD2
340
341static int swd_search2(lzo_swd_p s)
342{
343 unsigned key;
344
345 assert(s->look >= 2);
346 assert(s->m_len > 0);
347
348 key = s->head2[ HEAD2(s->b,s->bp) ];
349 if (key == NIL2)
350 return 0;
351 assert(lzo_memcmp(&s->b[s->bp],&s->b[key],2) == 0);
352#if defined(SWD_BEST_OFF)
353 if (s->best_pos[2] == 0)
354 s->best_pos[2] = key + 1;
355#endif
356
357 if (s->m_len < 2) {
358 s->m_len = 2;
359 s->m_pos = key;
360 }
361 return 1;
362}
363
364#endif
365
366
367/***********************************************************************
368//
369************************************************************************/
370static void swd_findbest(lzo_swd_p s)
371{
372 unsigned key;
373 unsigned cnt, node;
374 unsigned len;
375
376 assert(s->m_len > 0);
377
378 /* get current head, add bp into HEAD3 */
379 key = HEAD3(s->b,s->bp);
380 node = s->succ3[s->bp] = s_get_head3(s,key);
381 cnt = s->llen3[key]++;
382 assert(s->llen3[key] <= SWD_N + SWD_F);
383 if (cnt > s->max_chain)
384 cnt = s->max_chain;
385 s->head3[key] = s->bp;
386
387 s->b_char = s->b[s->bp];
388 len = s->m_len;
389 if (s->m_len >= s->look) {
390 if (s->look == 0)
391 s->b_char = -1;
392 s->m_off = 0;
393 s->best3[s->bp] = SWD_F + 1;
394 } else {
395#ifdef HEAD2
396 if (swd_search2(s))
397#endif
398 if (s->look >= 3)
399 swd_search(s,node,cnt);
400 if (s->m_len > len)
401 s->m_off = swd_pos2off(s,s->m_pos);
402 s->best3[s->bp] = s->m_len;
403
404#if defined(SWD_BEST_OFF)
405 if (s->use_best_off) {
406 int i;
407 for (i = 2; i < SWD_BEST_OFF; i++)
408 if (s->best_pos[i] > 0)
409 s->best_off[i] = swd_pos2off(s,s->best_pos[i]-1);
410 else
411 s->best_off[i] = 0;
412 }
413#endif
414 }
415
416 swd_remove_node(s,s->rp);
417
418#ifdef HEAD2
419 /* add bp into HEAD2 */
420 key = HEAD2(s->b,s->bp);
421 s->head2[key] = s->bp;
422#endif
423}
424
425#undef HEAD3
426#undef HEAD2
427#undef s_get_head3
428
429
430/***********************************************************************
431//
432************************************************************************/
433static int init_match(lzo1x_999_t *c, lzo_swd_p s, uint32_t use_best_off)
434{
435 int r;
436
437 assert(!c->init);
438 c->init = 1;
439
440 s->c = c;
441
442 r = swd_init(s);
443 if (r != 0)
444 return r;
445
446 s->use_best_off = use_best_off;
447 return r;
448}
449
450
451/***********************************************************************
452//
453************************************************************************/
454static int find_match(lzo1x_999_t *c, lzo_swd_p s,
455 unsigned this_len, unsigned skip)
456{
457 assert(c->init);
458
459 if (skip > 0) {
460 assert(this_len >= skip);
461 swd_accept(s, this_len - skip);
462 } else {
463 assert(this_len <= 1);
464 }
465
466 s->m_len = 1;
467 s->m_len = 1;
468#ifdef SWD_BEST_OFF
469 if (s->use_best_off)
470 memset(s->best_pos,0,sizeof(s->best_pos));
471#endif
472 swd_findbest(s);
473 c->m_len = s->m_len;
474 c->m_off = s->m_off;
475
476 swd_getbyte(s);
477
478 if (s->b_char < 0) {
479 c->look = 0;
480 c->m_len = 0;
481 } else {
482 c->look = s->look + 1;
483 }
484 c->bp = c->ip - c->look;
485
486 return LZO_E_OK;
487}
488
489/* this is a public functions, but there is no prototype in a header file */
490static int lzo1x_999_compress_internal(const uint8_t *in , unsigned in_len,
491 uint8_t *out, unsigned *out_len,
492 void *wrkmem,
493 unsigned good_length,
494 unsigned max_lazy,
495 unsigned max_chain,
496 uint32_t use_best_off);
497
498
499/***********************************************************************
500//
501************************************************************************/
502static uint8_t *code_match(lzo1x_999_t *c,
503 uint8_t *op, unsigned m_len, unsigned m_off)
504{
505 assert(op > c->out);
506 if (m_len == 2) {
507 assert(m_off <= M1_MAX_OFFSET);
508 assert(c->r1_lit > 0); assert(c->r1_lit < 4);
509 m_off -= 1;
510 *op++ = M1_MARKER | ((m_off & 3) << 2);
511 *op++ = m_off >> 2;
512 } else if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) {
513 assert(m_len >= 3);
514 m_off -= 1;
515 *op++ = ((m_len - 1) << 5) | ((m_off & 7) << 2);
516 *op++ = m_off >> 3;
517 assert(op[-2] >= M2_MARKER);
518 } else if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && c->r1_lit >= 4) {
519 assert(m_len == 3);
520 assert(m_off > M2_MAX_OFFSET);
521 m_off -= 1 + M2_MAX_OFFSET;
522 *op++ = M1_MARKER | ((m_off & 3) << 2);
523 *op++ = m_off >> 2;
524 } else if (m_off <= M3_MAX_OFFSET) {
525 assert(m_len >= 3);
526 m_off -= 1;
527 if (m_len <= M3_MAX_LEN)
528 *op++ = M3_MARKER | (m_len - 2);
529 else {
530 m_len -= M3_MAX_LEN;
531 *op++ = M3_MARKER | 0;
532 while (m_len > 255)
533 {
534 m_len -= 255;
535 *op++ = 0;
536 }
537 assert(m_len > 0);
538 *op++ = m_len;
539 }
540 *op++ = m_off << 2;
541 *op++ = m_off >> 6;
542 } else {
543 unsigned k;
544
545 assert(m_len >= 3);
546 assert(m_off > 0x4000); assert(m_off <= 0xbfff);
547 m_off -= 0x4000;
548 k = (m_off & 0x4000) >> 11;
549 if (m_len <= M4_MAX_LEN)
550 *op++ = M4_MARKER | k | (m_len - 2);
551 else {
552 m_len -= M4_MAX_LEN;
553 *op++ = M4_MARKER | k | 0;
554 while (m_len > 255)
555 {
556 m_len -= 255;
557 *op++ = 0;
558 }
559 assert(m_len > 0);
560 *op++ = m_len;
561 }
562 *op++ = m_off << 2;
563 *op++ = m_off >> 6;
564 }
565
566 return op;
567}
568
569
570static uint8_t *STORE_RUN(lzo1x_999_t *c, uint8_t *op,
571 const uint8_t *ii, unsigned t)
572{
573 if (op == c->out && t <= 238) {
574 *op++ = 17 + t;
575 } else if (t <= 3) {
576 op[-2] |= t;
577 } else if (t <= 18) {
578 *op++ = t - 3;
579 } else {
580 unsigned tt = t - 18;
581
582 *op++ = 0;
583 while (tt > 255) {
584 tt -= 255;
585 *op++ = 0;
586 }
587 assert(tt > 0);
588 *op++ = tt;
589 }
590 do *op++ = *ii++; while (--t > 0);
591
592 return op;
593}
594
595
596static uint8_t *code_run(lzo1x_999_t *c, uint8_t *op, const uint8_t *ii,
597 unsigned lit)
598{
599 if (lit > 0) {
600 assert(m_len >= 2);
601 op = STORE_RUN(c,op,ii,lit);
602 } else {
603 assert(m_len >= 3);
604 }
605 c->r1_lit = lit;
606
607 return op;
608}
609
610
611/***********************************************************************
612//
613************************************************************************/
614static int len_of_coded_match(unsigned m_len, unsigned m_off, unsigned lit)
615{
616 int n = 4;
617
618 if (m_len < 2)
619 return -1;
620 if (m_len == 2)
621 return (m_off <= M1_MAX_OFFSET && lit > 0 && lit < 4) ? 2 : -1;
622 if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET)
623 return 2;
624 if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && lit >= 4)
625 return 2;
626 if (m_off <= M3_MAX_OFFSET) {
627 if (m_len <= M3_MAX_LEN)
628 return 3;
629 m_len -= M3_MAX_LEN;
630 } else if (m_off <= M4_MAX_OFFSET) {
631 if (m_len <= M4_MAX_LEN)
632 return 3;
633 m_len -= M4_MAX_LEN;
634 } else
635 return -1;
636 while (m_len > 255) {
637 m_len -= 255;
638 n++;
639 }
640 return n;
641}
642
643
644static int min_gain(unsigned ahead, unsigned lit1,
645 unsigned lit2, int l1, int l2, int l3)
646{
647 int lazy_match_min_gain = 0;
648
649 assert (ahead >= 1);
650 lazy_match_min_gain += ahead;
651
652 if (lit1 <= 3)
653 lazy_match_min_gain += (lit2 <= 3) ? 0 : 2;
654 else if (lit1 <= 18)
655 lazy_match_min_gain += (lit2 <= 18) ? 0 : 1;
656
657 lazy_match_min_gain += (l2 - l1) * 2;
658 if (l3 > 0)
659 lazy_match_min_gain -= (ahead - l3) * 2;
660
661 if (lazy_match_min_gain < 0)
662 lazy_match_min_gain = 0;
663
664 return lazy_match_min_gain;
665}
666
667
668/***********************************************************************
669//
670************************************************************************/
671#if defined(SWD_BEST_OFF)
672
673static void better_match(const lzo_swd_p swd,
674 unsigned *m_len, unsigned *m_off)
675{
676
677 if (*m_len <= M2_MIN_LEN)
678 return;
679
680 if (*m_off <= M2_MAX_OFFSET)
681 return;
682
683 /* M3/M4 -> M2 */
684 if (*m_off > M2_MAX_OFFSET &&
685 *m_len >= M2_MIN_LEN + 1 && *m_len <= M2_MAX_LEN + 1 &&
686 swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M2_MAX_OFFSET)
687 {
688 *m_len = *m_len - 1;
689 *m_off = swd->best_off[*m_len];
690 return;
691 }
692
693 /* M4 -> M2 */
694 if (*m_off > M3_MAX_OFFSET &&
695 *m_len >= M4_MAX_LEN + 1 && *m_len <= M2_MAX_LEN + 2 &&
696 swd->best_off[*m_len-2] && swd->best_off[*m_len-2] <= M2_MAX_OFFSET)
697 {
698 *m_len = *m_len - 2;
699 *m_off = swd->best_off[*m_len];
700 return;
701 }
702 /* M4 -> M3 */
703 if (*m_off > M3_MAX_OFFSET &&
704 *m_len >= M4_MAX_LEN + 1 && *m_len <= M3_MAX_LEN + 1 &&
705 swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M3_MAX_OFFSET)
706 {
707 *m_len = *m_len - 1;
708 *m_off = swd->best_off[*m_len];
709 }
710}
711
712#endif
713
714
715/***********************************************************************
716//
717************************************************************************/
718static int lzo1x_999_compress_internal(const uint8_t *in, unsigned in_len,
719 uint8_t *out, unsigned *out_len,
720 void *wrkmem,
721 unsigned good_length,
722 unsigned max_lazy,
723 unsigned max_chain,
724 uint32_t use_best_off)
725{
726 uint8_t *op;
727 const uint8_t *ii;
728 unsigned lit;
729 unsigned m_len, m_off;
730 lzo1x_999_t cc;
731 lzo1x_999_t * const c = &cc;
732 lzo_swd_p const swd = (lzo_swd_p) wrkmem;
733 int r;
734
735 c->init = 0;
736 c->ip = c->in = in;
737 c->in_end = in + in_len;
738 c->out = out;
739
740 op = out;
741 ii = c->ip; /* point to start of literal run */
742 lit = 0;
743 c->r1_lit = 0;
744
745 r = init_match(c, swd, use_best_off);
746 if (r != 0)
747 return r;
748 swd->max_chain = max_chain;
749
750 r = find_match(c, swd, 0, 0);
751 if (r != 0)
752 return r;
753
754 while (c->look > 0) {
755 unsigned ahead;
756 unsigned max_ahead;
757 int l1, l2, l3;
758
759 m_len = c->m_len;
760 m_off = c->m_off;
761
762 assert(c->bp == c->ip - c->look);
763 assert(c->bp >= in);
764 if (lit == 0)
765 ii = c->bp;
766 assert(ii + lit == c->bp);
767 assert(swd->b_char == *(c->bp));
768
769 if ( m_len < 2 ||
770 (m_len == 2 && (m_off > M1_MAX_OFFSET || lit == 0 || lit >= 4)) ||
771 /* Do not accept this match for compressed-data compatibility
772 * with LZO v1.01 and before
773 * [ might be a problem for decompress() and optimize() ]
774 */
775 (m_len == 2 && op == out) ||
776 (op == out && lit == 0))
777 {
778 /* a literal */
779 m_len = 0;
780 }
781 else if (m_len == M2_MIN_LEN) {
782 /* compression ratio improves if we code a literal in some cases */
783 if (m_off > MX_MAX_OFFSET && lit >= 4)
784 m_len = 0;
785 }
786
787 if (m_len == 0) {
788 /* a literal */
789 lit++;
790 swd->max_chain = max_chain;
791 r = find_match(c,swd,1,0);
792 assert(r == 0);
793 continue;
794 }
795
796 /* a match */
797#if defined(SWD_BEST_OFF)
798 if (swd->use_best_off)
799 better_match(swd,&m_len,&m_off);
800#endif
801
802 /* shall we try a lazy match ? */
803 ahead = 0;
804 if (m_len >= max_lazy) {
805 /* no */
806 l1 = 0;
807 max_ahead = 0;
808 } else {
809 /* yes, try a lazy match */
810 l1 = len_of_coded_match(m_len,m_off,lit);
811 assert(l1 > 0);
812 max_ahead = LZO_MIN(2, (unsigned)l1 - 1);
813 }
814
815
816 while (ahead < max_ahead && c->look > m_len) {
817 int lazy_match_min_gain;
818
819 if (m_len >= good_length)
820 swd->max_chain = max_chain >> 2;
821 else
822 swd->max_chain = max_chain;
823 r = find_match(c,swd,1,0);
824 ahead++;
825
826 assert(r == 0);
827 assert(c->look > 0);
828 assert(ii + lit + ahead == c->bp);
829
830 if (c->m_len < m_len)
831 continue;
832 if (c->m_len == m_len && c->m_off >= m_off)
833 continue;
834#if defined(SWD_BEST_OFF)
835 if (swd->use_best_off)
836 better_match(swd,&c->m_len,&c->m_off);
837#endif
838 l2 = len_of_coded_match(c->m_len,c->m_off,lit+ahead);
839 if (l2 < 0)
840 continue;
841
842 /* compressed-data compatibility [see above] */
843 l3 = (op == out) ? -1 : len_of_coded_match(ahead,m_off,lit);
844
845 lazy_match_min_gain = min_gain(ahead,lit,lit+ahead,l1,l2,l3);
846 if (c->m_len >= m_len + lazy_match_min_gain) {
847 if (l3 > 0) {
848 /* code previous run */
849 op = code_run(c,op,ii,lit);
850 lit = 0;
851 /* code shortened match */
852 op = code_match(c,op,ahead,m_off);
853 } else {
854 lit += ahead;
855 assert(ii + lit == c->bp);
856 }
857 goto lazy_match_done;
858 }
859 }
860
861 assert(ii + lit + ahead == c->bp);
862
863 /* 1 - code run */
864 op = code_run(c,op,ii,lit);
865 lit = 0;
866
867 /* 2 - code match */
868 op = code_match(c,op,m_len,m_off);
869 swd->max_chain = max_chain;
870 r = find_match(c,swd,m_len,1+ahead);
871 assert(r == 0);
872
873 lazy_match_done: ;
874 }
875
876 /* store final run */
877 if (lit > 0)
878 op = STORE_RUN(c,op,ii,lit);
879
880#if defined(LZO_EOF_CODE)
881 *op++ = M4_MARKER | 1;
882 *op++ = 0;
883 *op++ = 0;
884#endif
885
886 *out_len = op - out;
887
888 return LZO_E_OK;
889}
890
891
892/***********************************************************************
893//
894************************************************************************/
895int lzo1x_999_compress_level(const uint8_t *in, unsigned in_len,
896 uint8_t *out, unsigned *out_len,
897 void *wrkmem,
898 int compression_level)
899{
900 static const struct {
901 uint16_t good_length;
902 uint16_t max_lazy;
903 uint16_t max_chain;
904 uint16_t use_best_off;
905 } c[3] = {
906 { 8, 32, 256, 0 },
907 { 32, 128, 2048, 1 },
908 { SWD_F, SWD_F, 4096, 1 } /* max. compression */
909 };
910
911 if (compression_level < 7 || compression_level > 9)
912 return LZO_E_ERROR;
913
914 compression_level -= 7;
915 return lzo1x_999_compress_internal(in, in_len, out, out_len, wrkmem,
916 c[compression_level].good_length,
917 c[compression_level].max_lazy,
918 c[compression_level].max_chain,
919 c[compression_level].use_best_off);
920}