1 /* lzo1x_9x.c -- implementation of the LZO1X-999 compression algorithm
3 This file is part of the LZO real-time data compression library.
5 Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer
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.
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.
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.
23 Markus F.X.J. Oberhumer
24 <markus@oberhumer.com>
25 http://www.oberhumer.com/opensource/lzo/
29 #if !defined(LZO1X) && !defined(LZO1Y) && !defined(LZO1Z)
34 # include "config1x.h"
36 # include "config1y.h"
38 # include "config1z.h"
44 /***********************************************************************
46 ************************************************************************/
48 #define SWD_N M4_MAX_OFFSET /* size of ring buffer */
49 #define SWD_THRESHOLD 1 /* lower limit for match length */
50 #define SWD_F 2048 /* upper limit for match length */
52 #define SWD_BEST_OFF (LZO_MAX3( M2_MAX_LEN, M3_MAX_LEN, M4_MAX_LEN ) + 1)
55 # define LZO_COMPRESS_T lzo1x_999_t
56 # define lzo_swd_t lzo1x_999_swd_t
58 # define LZO_COMPRESS_T lzo1y_999_t
59 # define lzo_swd_t lzo1y_999_swd_t
60 # define lzo1x_999_compress_internal lzo1y_999_compress_internal
61 # define lzo1x_999_compress_dict lzo1y_999_compress_dict
62 # define lzo1x_999_compress_level lzo1y_999_compress_level
63 # define lzo1x_999_compress lzo1y_999_compress
65 # define LZO_COMPRESS_T lzo1z_999_t
66 # define lzo_swd_t lzo1z_999_swd_t
67 # define lzo1x_999_compress_internal lzo1z_999_compress_internal
68 # define lzo1x_999_compress_dict lzo1z_999_compress_dict
69 # define lzo1x_999_compress_level lzo1z_999_compress_level
70 # define lzo1x_999_compress lzo1z_999_compress
77 ((((((lzo_xint)b[p]<<3)^b[p+1])<<3)^b[p+2]) & (SWD_HSIZE-1))
79 #if 0 && (LZO_OPT_UNALIGNED32) && (LZO_ABI_LITTLE_ENDIAN)
81 (((* (lzo_uint32_tp) &b[p]) ^ ((* (lzo_uint32_tp) &b[p])>>10)) & (SWD_HSIZE-1))
84 #include "lzo_mchw.ch"
87 /* this is a public functions, but there is no prototype in a header file */
89 lzo1x_999_compress_internal ( const lzo_bytep in
, lzo_uint in_len
,
90 lzo_bytep out
, lzo_uintp out_len
,
92 const lzo_bytep dict
, lzo_uint dict_len
,
102 /***********************************************************************
104 ************************************************************************/
107 code_match ( LZO_COMPRESS_T
*c
, lzo_bytep op
, lzo_uint m_len
, lzo_uint m_off
)
109 lzo_uint x_len
= m_len
;
110 lzo_uint x_off
= m_off
;
112 c
->match_bytes
+= (unsigned long) m_len
;
116 static lzo_uint last_m_len = 0, last_m_off = 0;
117 static lzo_uint prev_m_off[4];
118 static unsigned prev_m_off_ptr = 0;
121 //if (m_len >= 3 && m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET)
122 if (m_len >= 3 && m_len <= M2_MAX_LEN)
124 //if (m_len == last_m_len && m_off == last_m_off)
125 //printf("last_m_len + last_m_off\n");
127 if (m_off == last_m_off)
128 printf("last_m_off\n");
131 for (i = 0; i < 4; i++)
132 if (m_off == prev_m_off[i])
133 printf("prev_m_off %u: %5ld\n",i,(long)m_off);
137 last_m_off = prev_m_off[prev_m_off_ptr] = m_off;
138 prev_m_off_ptr = (prev_m_off_ptr + 1) & 3;
145 assert(m_off
<= M1_MAX_OFFSET
);
146 assert(c
->r1_lit
> 0); assert(c
->r1_lit
< 4);
149 *op
++ = LZO_BYTE(M1_MARKER
| (m_off
>> 6));
150 *op
++ = LZO_BYTE(m_off
<< 2);
152 *op
++ = LZO_BYTE(M1_MARKER
| ((m_off
& 3) << 2));
153 *op
++ = LZO_BYTE(m_off
>> 2);
158 else if (m_len
<= M2_MAX_LEN
&& (m_off
<= M2_MAX_OFFSET
|| m_off
== c
->last_m_off
))
160 else if (m_len
<= M2_MAX_LEN
&& m_off
<= M2_MAX_OFFSET
)
166 *op
++ = LZO_BYTE(((m_len
- 1) << 5) | ((m_off
& 7) << 2));
167 *op
++ = LZO_BYTE(m_off
>> 3);
168 assert(op
[-2] >= M2_MARKER
);
171 *op
++ = LZO_BYTE(((m_len
+ 1) << 4) | ((m_off
& 3) << 2));
172 *op
++ = LZO_BYTE(m_off
>> 2);
173 assert(op
[-2] >= M2_MARKER
);
175 if (m_off
== c
->last_m_off
)
176 *op
++ = LZO_BYTE(((m_len
- 1) << 5) | (0x700 >> 6));
180 *op
++ = LZO_BYTE(((m_len
- 1) << 5) | (m_off
>> 6));
181 *op
++ = LZO_BYTE(m_off
<< 2);
186 else if (m_len
== M2_MIN_LEN
&& m_off
<= MX_MAX_OFFSET
&& c
->r1_lit
>= 4)
189 assert(m_off
> M2_MAX_OFFSET
);
190 m_off
-= 1 + M2_MAX_OFFSET
;
192 *op
++ = LZO_BYTE(M1_MARKER
| (m_off
>> 6));
193 *op
++ = LZO_BYTE(m_off
<< 2);
195 *op
++ = LZO_BYTE(M1_MARKER
| ((m_off
& 3) << 2));
196 *op
++ = LZO_BYTE(m_off
>> 2);
200 else if (m_off
<= M3_MAX_OFFSET
)
204 if (m_len
<= M3_MAX_LEN
)
205 *op
++ = LZO_BYTE(M3_MARKER
| (m_len
- 2));
209 *op
++ = M3_MARKER
| 0;
216 *op
++ = LZO_BYTE(m_len
);
219 *op
++ = LZO_BYTE(m_off
>> 6);
220 *op
++ = LZO_BYTE(m_off
<< 2);
222 *op
++ = LZO_BYTE(m_off
<< 2);
223 *op
++ = LZO_BYTE(m_off
>> 6);
232 assert(m_off
> 0x4000); assert(m_off
<= 0xbfff);
234 k
= (m_off
& 0x4000) >> 11;
235 if (m_len
<= M4_MAX_LEN
)
236 *op
++ = LZO_BYTE(M4_MARKER
| k
| (m_len
- 2));
240 *op
++ = LZO_BYTE(M4_MARKER
| k
| 0);
247 *op
++ = LZO_BYTE(m_len
);
250 *op
++ = LZO_BYTE(m_off
>> 6);
251 *op
++ = LZO_BYTE(m_off
<< 2);
253 *op
++ = LZO_BYTE(m_off
<< 2);
254 *op
++ = LZO_BYTE(m_off
>> 6);
259 c
->last_m_len
= x_len
;
260 c
->last_m_off
= x_off
;
266 STORE_RUN ( LZO_COMPRESS_T
*c
, lzo_bytep op
, const lzo_bytep ii
, lzo_uint t
)
268 c
->lit_bytes
+= (unsigned long) t
;
270 if (op
== c
->out
&& t
<= 238)
272 *op
++ = LZO_BYTE(17 + t
);
277 op
[-1] = LZO_BYTE(op
[-1] | t
);
279 op
[-2] = LZO_BYTE(op
[-2] | t
);
285 *op
++ = LZO_BYTE(t
- 3);
290 lzo_uint tt
= t
- 18;
299 *op
++ = LZO_BYTE(tt
);
302 do *op
++ = *ii
++; while (--t
> 0);
309 code_run ( LZO_COMPRESS_T
*c
, lzo_bytep op
, const lzo_bytep ii
,
310 lzo_uint lit
, lzo_uint m_len
)
315 op
= STORE_RUN(c
,op
,ii
,lit
);
330 /***********************************************************************
332 ************************************************************************/
335 len_of_coded_match ( lzo_uint m_len
, lzo_uint m_off
, lzo_uint lit
)
342 return (m_off
<= M1_MAX_OFFSET
&& lit
> 0 && lit
< 4) ? 2 : 0;
343 if (m_len
<= M2_MAX_LEN
&& m_off
<= M2_MAX_OFFSET
)
345 if (m_len
== M2_MIN_LEN
&& m_off
<= MX_MAX_OFFSET
&& lit
>= 4)
347 if (m_off
<= M3_MAX_OFFSET
)
349 if (m_len
<= M3_MAX_LEN
)
359 if (m_off
<= M4_MAX_OFFSET
)
361 if (m_len
<= M4_MAX_LEN
)
376 min_gain(lzo_uint ahead
, lzo_uint lit1
, lzo_uint lit2
, lzo_uint l1
, lzo_uint l2
, lzo_uint l3
)
378 lzo_uint lazy_match_min_gain
;
381 lazy_match_min_gain
= ahead
;
389 lazy_match_min_gain
+= (lit2
<= 3) ? 0 : 2;
391 lazy_match_min_gain
+= (lit2
<= 18) ? 0 : 1;
393 lazy_match_min_gain
+= (l2
- l1
) * 2;
395 lazy_match_min_gain
-= (ahead
- l3
) * 2;
397 if ((lzo_int
) lazy_match_min_gain
< 0)
398 lazy_match_min_gain
= 0;
402 if (lazy_match_min_gain
== 0)
403 lazy_match_min_gain
= 1;
406 return lazy_match_min_gain
;
410 /***********************************************************************
412 ************************************************************************/
416 void assert_match( const lzo_swd_p swd
, lzo_uint m_len
, lzo_uint m_off
)
418 const LZO_COMPRESS_T
*c
= swd
->c
;
422 if (m_off
<= (lzo_uint
) (c
->bp
- c
->in
))
424 assert(c
->bp
- m_off
+ m_len
< c
->ip
);
425 assert(lzo_memcmp(c
->bp
, c
->bp
- m_off
, m_len
) == 0);
429 assert(swd
->dict
!= NULL
);
430 d_off
= m_off
- (lzo_uint
) (c
->bp
- c
->in
);
431 assert(d_off
<= swd
->dict_len
);
434 assert(lzo_memcmp(c
->bp
, swd
->dict_end
- d_off
, d_off
) == 0);
435 assert(c
->in
+ m_len
- d_off
< c
->ip
);
436 assert(lzo_memcmp(c
->bp
+ d_off
, c
->in
, m_len
- d_off
) == 0);
440 assert(lzo_memcmp(c
->bp
, swd
->dict_end
- d_off
, m_len
) == 0);
445 # define assert_match(a,b,c) ((void)0)
449 #if defined(SWD_BEST_OFF)
452 better_match ( const lzo_swd_p swd
, lzo_uint
*m_len
, lzo_uint
*m_off
)
455 const LZO_COMPRESS_T
*c
= swd
->c
;
458 if (*m_len
<= M2_MIN_LEN
)
461 if (*m_off
== c
->last_m_off
&& *m_len
<= M2_MAX_LEN
)
464 if (*m_len
>= M2_MIN_LEN
+ 1 && *m_len
<= M2_MAX_LEN
+ 1 &&
465 c
->last_m_off
&& swd
->best_off
[*m_len
-1] == c
->last_m_off
)
468 *m_off
= swd
->best_off
[*m_len
];
474 if (*m_off
<= M2_MAX_OFFSET
)
479 if (*m_off
> M2_MAX_OFFSET
&&
480 *m_len
>= M2_MIN_LEN
+ 1 && *m_len
<= M2_MAX_LEN
+ 1 &&
481 swd
->best_off
[*m_len
-1] && swd
->best_off
[*m_len
-1] <= M2_MAX_OFFSET
)
484 *m_off
= swd
->best_off
[*m_len
];
491 if (*m_off
> M3_MAX_OFFSET
&&
492 *m_len
>= M4_MAX_LEN
+ 1 && *m_len
<= M2_MAX_LEN
+ 2 &&
493 swd
->best_off
[*m_len
-2] && swd
->best_off
[*m_len
-2] <= M2_MAX_OFFSET
)
496 *m_off
= swd
->best_off
[*m_len
];
503 if (*m_off
> M3_MAX_OFFSET
&&
504 *m_len
>= M4_MAX_LEN
+ 1 && *m_len
<= M3_MAX_LEN
+ 1 &&
505 swd
->best_off
[*m_len
-1] && swd
->best_off
[*m_len
-1] <= M3_MAX_OFFSET
)
508 *m_off
= swd
->best_off
[*m_len
];
516 /***********************************************************************
518 ************************************************************************/
521 lzo1x_999_compress_internal ( const lzo_bytep in
, lzo_uint in_len
,
522 lzo_bytep out
, lzo_uintp out_len
,
524 const lzo_bytep dict
, lzo_uint dict_len
,
527 lzo_uint good_length
,
529 lzo_uint nice_length
,
536 lzo_uint m_len
, m_off
;
538 LZO_COMPRESS_T
* const c
= &cc
;
539 lzo_swd_p
const swd
= (lzo_swd_p
) wrkmem
;
545 LZO_COMPILE_TIME_ASSERT(LZO1X_999_MEM_COMPRESS
>= SIZEOF_LZO_SWD_T
)
547 LZO_COMPILE_TIME_ASSERT(LZO1Y_999_MEM_COMPRESS
>= SIZEOF_LZO_SWD_T
)
549 LZO_COMPILE_TIME_ASSERT(LZO1Z_999_MEM_COMPRESS
>= SIZEOF_LZO_SWD_T
)
554 /* setup parameter defaults */
555 /* number of lazy match tries */
556 try_lazy
= (lzo_uint
) try_lazy_parm
;
557 if (try_lazy_parm
< 0)
559 /* reduce lazy match search if we already have a match with this length */
560 if (good_length
== 0)
562 /* do not try a lazy match if we already have a match with this length */
565 /* stop searching for longer matches than this one */
566 if (nice_length
== 0)
568 /* don't search more positions than this */
570 max_chain
= SWD_MAX_CHAIN
;
574 c
->in_end
= in
+ in_len
;
577 c
->m1a_m
= c
->m1b_m
= c
->m2_m
= c
->m3_m
= c
->m4_m
= 0;
578 c
->lit1_r
= c
->lit2_r
= c
->lit3_r
= 0;
581 ii
= c
->ip
; /* point to start of literal run */
583 c
->r1_lit
= c
->r1_m_len
= 0;
585 r
= init_match(c
,swd
,dict
,dict_len
,flags
);
589 swd
->max_chain
= max_chain
;
591 swd
->nice_length
= nice_length
;
593 r
= find_match(c
,swd
,0,0);
602 c
->codesize
= pd(op
, out
);
607 assert(c
->bp
== c
->ip
- c
->look
);
611 assert(ii
+ lit
== c
->bp
);
612 assert(swd
->b_char
== *(c
->bp
));
615 (m_len
== 2 && (m_off
> M1_MAX_OFFSET
|| lit
== 0 || lit
>= 4)) ||
617 /* Do not accept this match for compressed-data compatibility
618 * with LZO v1.01 and before
619 * [ might be a problem for decompress() and optimize() ]
621 (m_len
== 2 && op
== out
) ||
623 (op
== out
&& lit
== 0))
628 else if (m_len
== M2_MIN_LEN
)
630 /* compression ratio improves if we code a literal in some cases */
631 if (m_off
> MX_MAX_OFFSET
&& lit
>= 4)
639 swd
->max_chain
= max_chain
;
640 r
= find_match(c
,swd
,1,0);
641 assert(r
== 0); LZO_UNUSED(r
);
646 #if defined(SWD_BEST_OFF)
647 if (swd
->use_best_off
)
648 better_match(swd
,&m_len
,&m_off
);
650 assert_match(swd
,m_len
,m_off
);
653 /* shall we try a lazy match ? */
655 if (try_lazy
== 0 || m_len
>= max_lazy
)
663 /* yes, try a lazy match */
664 l1
= len_of_coded_match(m_len
,m_off
,lit
);
667 max_ahead
= LZO_MIN(try_lazy
, l1
- 1);
669 max_ahead
= LZO_MIN3(try_lazy
, l1
, m_len
- 1);
674 while (ahead
< max_ahead
&& c
->look
> m_len
)
676 lzo_uint lazy_match_min_gain
;
678 if (m_len
>= good_length
)
679 swd
->max_chain
= max_chain
>> 2;
681 swd
->max_chain
= max_chain
;
682 r
= find_match(c
,swd
,1,0);
685 assert(r
== 0); LZO_UNUSED(r
);
687 assert(ii
+ lit
+ ahead
== c
->bp
);
690 if (m_off
== c
->last_m_off
&& c
->m_off
!= c
->last_m_off
)
691 if (m_len
>= M2_MIN_LEN
&& m_len
<= M2_MAX_LEN
)
694 if (c
->m_len
< m_len
)
697 if (c
->m_len
== m_len
&& c
->m_off
>= m_off
)
700 #if defined(SWD_BEST_OFF)
701 if (swd
->use_best_off
)
702 better_match(swd
,&c
->m_len
,&c
->m_off
);
704 l2
= len_of_coded_match(c
->m_len
,c
->m_off
,lit
+ahead
);
708 if (c
->m_len
== m_len
&& l2
>= l1
)
714 /* compressed-data compatibility [see above] */
715 l3
= (op
== out
) ? 0 : len_of_coded_match(ahead
,m_off
,lit
);
717 l3
= len_of_coded_match(ahead
,m_off
,lit
);
720 lazy_match_min_gain
= min_gain(ahead
,lit
,lit
+ahead
,l1
,l2
,l3
);
721 if (c
->m_len
>= m_len
+ lazy_match_min_gain
)
724 assert_match(swd
,c
->m_len
,c
->m_off
);
728 /* code previous run */
729 op
= code_run(c
,op
,ii
,lit
,ahead
);
731 /* code shortened match */
732 op
= code_match(c
,op
,ahead
,m_off
);
737 assert(ii
+ lit
== c
->bp
);
739 goto lazy_match_done
;
744 assert(ii
+ lit
+ ahead
== c
->bp
);
747 op
= code_run(c
,op
,ii
,lit
,m_len
);
751 op
= code_match(c
,op
,m_len
,m_off
);
752 swd
->max_chain
= max_chain
;
753 r
= find_match(c
,swd
,m_len
,1+ahead
);
754 assert(r
== 0); LZO_UNUSED(r
);
760 /* store final run */
762 op
= STORE_RUN(c
,op
,ii
,lit
);
764 #if defined(LZO_EOF_CODE)
765 *op
++ = M4_MARKER
| 1;
770 c
->codesize
= pd(op
, out
);
771 assert(c
->textsize
== in_len
);
773 *out_len
= pd(op
, out
);
775 if (c
->cb
&& c
->cb
->nprogress
)
776 (*c
->cb
->nprogress
)(c
->cb
, c
->textsize
, c
->codesize
, 0);
779 printf("%ld %ld -> %ld %ld: %ld %ld %ld %ld %ld %ld: %ld %ld %ld %ld\n",
780 (long) c
->textsize
, (long) in_len
, (long) c
->codesize
,
781 c
->match_bytes
, c
->m1a_m
, c
->m1b_m
, c
->m2_m
, c
->m3_m
, c
->m4_m
,
782 c
->lit_bytes
, c
->lit1_r
, c
->lit2_r
, c
->lit3_r
, c
->lazy
);
784 assert(c
->lit_bytes
+ c
->match_bytes
== in_len
);
790 /***********************************************************************
792 ************************************************************************/
795 lzo1x_999_compress_level ( const lzo_bytep in
, lzo_uint in_len
,
796 lzo_bytep out
, lzo_uintp out_len
,
798 const lzo_bytep dict
, lzo_uint dict_len
,
800 int compression_level
)
805 lzo_uint good_length
;
807 lzo_uint nice_length
;
811 /* faster compression */
812 { 0, 0, 0, 8, 4, 0 },
813 { 0, 0, 0, 16, 8, 0 },
814 { 0, 0, 0, 32, 16, 0 },
815 { 1, 4, 4, 16, 16, 0 },
816 { 1, 8, 16, 32, 32, 0 },
817 { 1, 8, 16, 128, 128, 0 },
818 { 2, 8, 32, 128, 256, 0 },
819 { 2, 32, 128, SWD_F
, 2048, 1 },
820 { 2, SWD_F
, SWD_F
, SWD_F
, 4096, 1 }
821 /* max. compression */
824 if (compression_level
< 1 || compression_level
> 9)
827 compression_level
-= 1;
828 return lzo1x_999_compress_internal(in
, in_len
, out
, out_len
, wrkmem
,
830 c
[compression_level
].try_lazy_parm
,
831 c
[compression_level
].good_length
,
832 c
[compression_level
].max_lazy
,
834 c
[compression_level
].nice_length
,
838 c
[compression_level
].max_chain
,
839 c
[compression_level
].flags
);
843 /***********************************************************************
845 ************************************************************************/
848 lzo1x_999_compress_dict ( const lzo_bytep in
, lzo_uint in_len
,
849 lzo_bytep out
, lzo_uintp out_len
,
851 const lzo_bytep dict
, lzo_uint dict_len
)
853 return lzo1x_999_compress_level(in
, in_len
, out
, out_len
, wrkmem
,
854 dict
, dict_len
, 0, 8);
858 lzo1x_999_compress ( const lzo_bytep in
, lzo_uint in_len
,
859 lzo_bytep out
, lzo_uintp out_len
,
862 return lzo1x_999_compress_level(in
, in_len
, out
, out_len
, wrkmem
,
863 NULL
, 0, (lzo_callback_p
) 0, 8);