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