|
kusano |
7d535a |
/* lzo1.c -- implementation of the LZO1 algorithm
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
This file is part of the LZO real-time data compression library.
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
|
|
kusano |
7d535a |
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
|
|
kusano |
7d535a |
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
|
|
kusano |
7d535a |
Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
|
|
kusano |
7d535a |
Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
|
|
kusano |
7d535a |
Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
|
|
kusano |
7d535a |
Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
|
|
kusano |
7d535a |
Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
|
|
kusano |
7d535a |
Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
|
|
kusano |
7d535a |
Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
|
|
kusano |
7d535a |
Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
|
|
kusano |
7d535a |
Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
|
|
kusano |
7d535a |
Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
|
|
kusano |
7d535a |
All Rights Reserved.
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
The LZO library is free software; you can redistribute it and/or
|
|
kusano |
7d535a |
modify it under the terms of the GNU General Public License as
|
|
kusano |
7d535a |
published by the Free Software Foundation; either version 2 of
|
|
kusano |
7d535a |
the License, or (at your option) any later version.
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
The LZO library is distributed in the hope that it will be useful,
|
|
kusano |
7d535a |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
kusano |
7d535a |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
kusano |
7d535a |
GNU General Public License for more details.
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
You should have received a copy of the GNU General Public License
|
|
kusano |
7d535a |
along with the LZO library; see the file COPYING.
|
|
kusano |
7d535a |
If not, write to the Free Software Foundation, Inc.,
|
|
kusano |
7d535a |
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
Markus F.X.J. Oberhumer
|
|
kusano |
7d535a |
<markus@oberhumer.com></markus@oberhumer.com>
|
|
kusano |
7d535a |
http://www.oberhumer.com/opensource/lzo/
|
|
kusano |
7d535a |
*/
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
#include "lzo_conf.h"
|
|
kusano |
7d535a |
#include "lzo/lzo1.h"
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/***********************************************************************
|
|
kusano |
7d535a |
// The next two defines can be changed to customize LZO1.
|
|
kusano |
7d535a |
// The default version is LZO1-5/1.
|
|
kusano |
7d535a |
************************************************************************/
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* run bits (3 - 5) - the compressor and the decompressor
|
|
kusano |
7d535a |
* must use the same value. */
|
|
kusano |
7d535a |
#if !defined(RBITS)
|
|
kusano |
7d535a |
# define RBITS 5
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* compression level (1 - 9) - this only affects the compressor.
|
|
kusano |
7d535a |
* 1 is fastest, 9 is best compression ratio */
|
|
kusano |
7d535a |
#if !defined(CLEVEL)
|
|
kusano |
7d535a |
# define CLEVEL 1 /* fastest by default */
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* check configuration */
|
|
kusano |
7d535a |
#if (RBITS < 3 || RBITS > 5)
|
|
kusano |
7d535a |
# error "invalid RBITS"
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
#if (CLEVEL < 1 || CLEVEL > 9)
|
|
kusano |
7d535a |
# error "invalid CLEVEL"
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/***********************************************************************
|
|
kusano |
7d535a |
// You should not have to change anything below this line.
|
|
kusano |
7d535a |
************************************************************************/
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/*
|
|
kusano |
7d535a |
Format of the marker byte
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
76543210
|
|
kusano |
7d535a |
--------
|
|
kusano |
7d535a |
00000000 a long run (a 'R0' run) - there are short and long R0 runs
|
|
kusano |
7d535a |
000rrrrr a short run with len r
|
|
kusano |
7d535a |
mmmooooo a short match (len = 2+m, o = offset low bits)
|
|
kusano |
7d535a |
111ooooo a long match (o = offset low bits)
|
|
kusano |
7d535a |
*/
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
#define RSIZE (1 << RBITS)
|
|
kusano |
7d535a |
#define RMASK (RSIZE - 1)
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
#define OBITS RBITS /* offset and run-length use same bits */
|
|
kusano |
7d535a |
#define OSIZE (1 << OBITS)
|
|
kusano |
7d535a |
#define OMASK (OSIZE - 1)
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
#define MBITS (8 - OBITS)
|
|
kusano |
7d535a |
#define MSIZE (1 << MBITS)
|
|
kusano |
7d535a |
#define MMASK (MSIZE - 1)
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* sanity checks */
|
|
kusano |
7d535a |
#if (OBITS < 3 || OBITS > 5)
|
|
kusano |
7d535a |
# error "invalid OBITS"
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
#if (MBITS < 3 || MBITS > 5)
|
|
kusano |
7d535a |
# error "invalid MBITS"
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/***********************************************************************
|
|
kusano |
7d535a |
// some macros to improve readability
|
|
kusano |
7d535a |
************************************************************************/
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* Minimum len of a match */
|
|
kusano |
7d535a |
#define MIN_MATCH 3
|
|
kusano |
7d535a |
#define THRESHOLD (MIN_MATCH - 1)
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* Minimum len of match coded in 2 bytes */
|
|
kusano |
7d535a |
#define MIN_MATCH_SHORT MIN_MATCH
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* Maximum len of match coded in 2 bytes */
|
|
kusano |
7d535a |
#define MAX_MATCH_SHORT (THRESHOLD + (MSIZE - 2))
|
|
kusano |
7d535a |
/* MSIZE - 2: 0 is used to indicate runs,
|
|
kusano |
7d535a |
* MSIZE-1 is used to indicate a long match */
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* Minimum len of match coded in 3 bytes */
|
|
kusano |
7d535a |
#define MIN_MATCH_LONG (MAX_MATCH_SHORT + 1)
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* Maximum len of match coded in 3 bytes */
|
|
kusano |
7d535a |
#define MAX_MATCH_LONG (MIN_MATCH_LONG + 255)
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* Maximum offset of a match */
|
|
kusano |
7d535a |
#define MAX_OFFSET (1 << (8 + OBITS))
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/*
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
RBITS | MBITS MIN THR. MSIZE MAXS MINL MAXL MAXO R0MAX R0FAST
|
|
kusano |
7d535a |
======+===============================================================
|
|
kusano |
7d535a |
3 | 5 3 2 32 32 33 288 2048 263 256
|
|
kusano |
7d535a |
4 | 4 3 2 16 16 17 272 4096 271 264
|
|
kusano |
7d535a |
5 | 3 3 2 8 8 9 264 8192 287 280
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
*/
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/***********************************************************************
|
|
kusano |
7d535a |
// internal configuration
|
|
kusano |
7d535a |
// all of these affect compression only
|
|
kusano |
7d535a |
************************************************************************/
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* choose the hashing strategy */
|
|
kusano |
7d535a |
#ifndef LZO_HASH
|
|
kusano |
7d535a |
#define LZO_HASH LZO_HASH_LZO_INCREMENTAL_A
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX2(p,5,5)) >> 5)
|
|
kusano |
7d535a |
#define D_INDEX2(d,p) d = d ^ D_MASK
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
#define DBITS (8 + RBITS)
|
|
kusano |
7d535a |
#include "lzo_dict.h"
|
|
kusano |
7d535a |
#define DVAL_LEN DVAL_LOOKAHEAD
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/***********************************************************************
|
|
kusano |
7d535a |
// get algorithm info, return memory required for compression
|
|
kusano |
7d535a |
************************************************************************/
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
LZO_EXTERN(lzo_uint) lzo1_info ( int *rbits, int *clevel );
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
LZO_PUBLIC(lzo_uint)
|
|
kusano |
7d535a |
lzo1_info ( int *rbits, int *clevel )
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
if (rbits)
|
|
kusano |
7d535a |
*rbits = RBITS;
|
|
kusano |
7d535a |
if (clevel)
|
|
kusano |
7d535a |
*clevel = CLEVEL;
|
|
kusano |
7d535a |
return D_SIZE * lzo_sizeof(lzo_bytep);
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/***********************************************************************
|
|
kusano |
7d535a |
// decode a R0 literal run (a long run)
|
|
kusano |
7d535a |
************************************************************************/
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
#define R0MIN (RSIZE) /* Minimum len of R0 run of literals */
|
|
kusano |
7d535a |
#define R0MAX (R0MIN + 255) /* Maximum len of R0 run of literals */
|
|
kusano |
7d535a |
#define R0FAST (R0MAX & ~7u) /* R0MAX aligned to 8 byte boundary */
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
#if (R0MAX - R0FAST != 7) || ((R0FAST & 7) != 0)
|
|
kusano |
7d535a |
# error "something went wrong"
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* 7 special codes from R0FAST+1 .. R0MAX
|
|
kusano |
7d535a |
* these codes mean long R0 runs with lengths
|
|
kusano |
7d535a |
* 512, 1024, 2048, 4096, 8192, 16384, 32768 */
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/***********************************************************************
|
|
kusano |
7d535a |
// LZO1 decompress a block of data.
|
|
kusano |
7d535a |
//
|
|
kusano |
7d535a |
// Could be easily translated into assembly code.
|
|
kusano |
7d535a |
************************************************************************/
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
LZO_PUBLIC(int)
|
|
kusano |
7d535a |
lzo1_decompress ( const lzo_bytep in , lzo_uint in_len,
|
|
kusano |
7d535a |
lzo_bytep out, lzo_uintp out_len,
|
|
kusano |
7d535a |
lzo_voidp wrkmem )
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
lzo_bytep op;
|
|
kusano |
7d535a |
const lzo_bytep ip;
|
|
kusano |
7d535a |
const lzo_bytep const ip_end = in + in_len;
|
|
kusano |
7d535a |
lzo_uint t;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
LZO_UNUSED(wrkmem);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
op = out;
|
|
kusano |
7d535a |
ip = in;
|
|
kusano |
7d535a |
while (ip < ip_end)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
t = *ip++; /* get marker */
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
if (t < R0MIN) /* a literal run */
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
if (t == 0) /* a R0 literal run */
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
t = *ip++;
|
|
kusano |
7d535a |
if (t >= R0FAST - R0MIN) /* a long R0 run */
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
t -= R0FAST - R0MIN;
|
|
kusano |
7d535a |
if (t == 0)
|
|
kusano |
7d535a |
t = R0FAST;
|
|
kusano |
7d535a |
else
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
#if 0
|
|
kusano |
7d535a |
t = 256u << ((unsigned) t);
|
|
kusano |
7d535a |
#else
|
|
kusano |
7d535a |
/* help the optimizer */
|
|
kusano |
7d535a |
lzo_uint tt = 256;
|
|
kusano |
7d535a |
do tt <<= 1; while (--t > 0);
|
|
kusano |
7d535a |
t = tt;
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
MEMCPY8_DS(op,ip,t);
|
|
kusano |
7d535a |
continue;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
t += R0MIN;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
MEMCPY_DS(op,ip,t);
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
else /* a match */
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
lzo_uint tt;
|
|
kusano |
7d535a |
/* get match offset */
|
|
kusano |
7d535a |
const lzo_bytep m_pos = op - 1;
|
|
kusano |
7d535a |
m_pos -= (lzo_uint)(t & OMASK) | (((lzo_uint) *ip++) << OBITS);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* get match len */
|
|
kusano |
7d535a |
if (t >= ((MSIZE - 1) << OBITS)) /* all m-bits set */
|
|
kusano |
7d535a |
tt = (MIN_MATCH_LONG - THRESHOLD) + *ip++; /* a long match */
|
|
kusano |
7d535a |
else
|
|
kusano |
7d535a |
tt = t >> OBITS; /* a short match */
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
assert(m_pos >= out);
|
|
kusano |
7d535a |
assert(m_pos < op);
|
|
kusano |
7d535a |
/* a half unrolled loop */
|
|
kusano |
7d535a |
*op++ = *m_pos++;
|
|
kusano |
7d535a |
*op++ = *m_pos++;
|
|
kusano |
7d535a |
MEMCPY_DS(op,m_pos,tt);
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
*out_len = pd(op, out);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* the next line is the only check in the decompressor ! */
|
|
kusano |
7d535a |
return (ip == ip_end ? LZO_E_OK :
|
|
kusano |
7d535a |
(ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/***********************************************************************
|
|
kusano |
7d535a |
// code a literal run
|
|
kusano |
7d535a |
************************************************************************/
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
static
|
|
kusano |
7d535a |
#if LZO_ARCH_AVR
|
|
kusano |
7d535a |
__lzo_noinline
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
lzo_bytep
|
|
kusano |
7d535a |
store_run(lzo_bytep op, const lzo_bytep ii, lzo_uint r_len)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
assert(r_len > 0);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* code a long R0 run */
|
|
kusano |
7d535a |
if (r_len >= 512)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
unsigned r_bits = 7; /* 256 << 7 == 32768 */
|
|
kusano |
7d535a |
do {
|
|
kusano |
7d535a |
while (r_len >= (256u << r_bits))
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
r_len -= (256u << r_bits);
|
|
kusano |
7d535a |
*op++ = 0; *op++ = LZO_BYTE((R0FAST - R0MIN) + r_bits);
|
|
kusano |
7d535a |
MEMCPY8_DS(op, ii, (256u << r_bits));
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
} while (--r_bits > 0);
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
while (r_len >= R0FAST)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
r_len -= R0FAST;
|
|
kusano |
7d535a |
*op++ = 0; *op++ = R0FAST - R0MIN;
|
|
kusano |
7d535a |
MEMCPY8_DS(op, ii, R0FAST);
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
if (r_len >= R0MIN)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
/* code a short R0 run */
|
|
kusano |
7d535a |
*op++ = 0; *op++ = LZO_BYTE(r_len - R0MIN);
|
|
kusano |
7d535a |
MEMCPY_DS(op, ii, r_len);
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
else if (r_len > 0)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
/* code a 'normal' run */
|
|
kusano |
7d535a |
*op++ = LZO_BYTE(r_len);
|
|
kusano |
7d535a |
MEMCPY_DS(op, ii, r_len);
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
assert(r_len == 0);
|
|
kusano |
7d535a |
return op;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/***********************************************************************
|
|
kusano |
7d535a |
// LZO1 compress a block of data.
|
|
kusano |
7d535a |
//
|
|
kusano |
7d535a |
// Could be translated into assembly code without too much effort.
|
|
kusano |
7d535a |
//
|
|
kusano |
7d535a |
// I apologize for the spaghetti code, but it really helps the optimizer.
|
|
kusano |
7d535a |
************************************************************************/
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
static int
|
|
kusano |
7d535a |
do_compress ( const lzo_bytep in , lzo_uint in_len,
|
|
kusano |
7d535a |
lzo_bytep out, lzo_uintp out_len,
|
|
kusano |
7d535a |
lzo_voidp wrkmem )
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
const lzo_bytep ip;
|
|
kusano |
7d535a |
#if defined(__LZO_HASH_INCREMENTAL)
|
|
kusano |
7d535a |
lzo_xint dv;
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
lzo_bytep op;
|
|
kusano |
7d535a |
const lzo_bytep m_pos;
|
|
kusano |
7d535a |
const lzo_bytep const ip_end = in+in_len - DVAL_LEN - MIN_MATCH_LONG;
|
|
kusano |
7d535a |
const lzo_bytep const in_end = in+in_len - DVAL_LEN;
|
|
kusano |
7d535a |
const lzo_bytep ii;
|
|
kusano |
7d535a |
lzo_dict_p const dict = (lzo_dict_p) wrkmem;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
#if !defined(NDEBUG)
|
|
kusano |
7d535a |
const lzo_bytep m_pos_sav;
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
op = out;
|
|
kusano |
7d535a |
ip = in;
|
|
kusano |
7d535a |
ii = ip; /* point to start of literal run */
|
|
kusano |
7d535a |
if (in_len <= MIN_MATCH_LONG + DVAL_LEN + 1)
|
|
kusano |
7d535a |
goto the_end;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* init dictionary */
|
|
kusano |
7d535a |
#if defined(LZO_DETERMINISTIC)
|
|
kusano |
7d535a |
BZERO8_PTR(wrkmem,sizeof(lzo_dict_t),D_SIZE);
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
DVAL_FIRST(dv,ip);
|
|
kusano |
7d535a |
UPDATE_D(dict,0,dv,ip,in);
|
|
kusano |
7d535a |
ip++;
|
|
kusano |
7d535a |
DVAL_NEXT(dv,ip);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
do {
|
|
kusano |
7d535a |
lzo_uint m_off;
|
|
kusano |
7d535a |
lzo_uint dindex;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
DINDEX1(dindex,ip);
|
|
kusano |
7d535a |
GINDEX(m_pos,m_off,dict,dindex,in);
|
|
kusano |
7d535a |
if (LZO_CHECK_MPOS(m_pos,m_off,in,ip,MAX_OFFSET))
|
|
kusano |
7d535a |
goto literal;
|
|
kusano |
7d535a |
if (m_pos[0] == ip[0] && m_pos[1] == ip[1] && m_pos[2] == ip[2])
|
|
kusano |
7d535a |
goto match;
|
|
kusano |
7d535a |
DINDEX2(dindex,ip);
|
|
kusano |
7d535a |
GINDEX(m_pos,m_off,dict,dindex,in);
|
|
kusano |
7d535a |
if (LZO_CHECK_MPOS(m_pos,m_off,in,ip,MAX_OFFSET))
|
|
kusano |
7d535a |
goto literal;
|
|
kusano |
7d535a |
if (m_pos[0] == ip[0] && m_pos[1] == ip[1] && m_pos[2] == ip[2])
|
|
kusano |
7d535a |
goto match;
|
|
kusano |
7d535a |
goto literal;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
literal:
|
|
kusano |
7d535a |
UPDATE_I(dict,0,dindex,ip,in);
|
|
kusano |
7d535a |
if (++ip >= ip_end)
|
|
kusano |
7d535a |
break;
|
|
kusano |
7d535a |
continue;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
match:
|
|
kusano |
7d535a |
UPDATE_I(dict,0,dindex,ip,in);
|
|
kusano |
7d535a |
#if !defined(NDEBUG) && defined(LZO_DICT_USE_PTR)
|
|
kusano |
7d535a |
m_pos_sav = m_pos;
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
m_pos += 3;
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
/* we have found a match (of at least length 3) */
|
|
kusano |
7d535a |
#if !defined(NDEBUG) && !defined(LZO_DICT_USE_PTR)
|
|
kusano |
7d535a |
assert((m_pos_sav = ip - m_off) == (m_pos - 3));
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
/* 1) store the current literal run */
|
|
kusano |
7d535a |
if (pd(ip,ii) > 0)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
lzo_uint t = pd(ip,ii);
|
|
kusano |
7d535a |
#if 1
|
|
kusano |
7d535a |
/* OPTIMIZED: inline the copying of a short run */
|
|
kusano |
7d535a |
if (t < R0MIN)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
*op++ = LZO_BYTE(t);
|
|
kusano |
7d535a |
MEMCPY_DS(op, ii, t);
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
else
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
op = store_run(op,ii,t);
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* 2a) compute match len */
|
|
kusano |
7d535a |
ii = ip; /* point to start of current match */
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* we already matched MIN_MATCH bytes,
|
|
kusano |
7d535a |
* m_pos also already advanced MIN_MATCH bytes */
|
|
kusano |
7d535a |
ip += MIN_MATCH;
|
|
kusano |
7d535a |
assert(m_pos < ip);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* try to match another MIN_MATCH_LONG - MIN_MATCH bytes
|
|
kusano |
7d535a |
* to see if we get a long match */
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
#define PS *m_pos++ != *ip++
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
#if (MIN_MATCH_LONG - MIN_MATCH == 2) /* MBITS == 2 */
|
|
kusano |
7d535a |
if (PS || PS)
|
|
kusano |
7d535a |
#elif (MIN_MATCH_LONG - MIN_MATCH == 6) /* MBITS == 3 */
|
|
kusano |
7d535a |
if (PS || PS || PS || PS || PS || PS)
|
|
kusano |
7d535a |
#elif (MIN_MATCH_LONG - MIN_MATCH == 14) /* MBITS == 4 */
|
|
kusano |
7d535a |
if (PS || PS || PS || PS || PS || PS || PS ||
|
|
kusano |
7d535a |
PS || PS || PS || PS || PS || PS || PS)
|
|
kusano |
7d535a |
#elif (MIN_MATCH_LONG - MIN_MATCH == 30) /* MBITS == 5 */
|
|
kusano |
7d535a |
if (PS || PS || PS || PS || PS || PS || PS || PS ||
|
|
kusano |
7d535a |
PS || PS || PS || PS || PS || PS || PS || PS ||
|
|
kusano |
7d535a |
PS || PS || PS || PS || PS || PS || PS || PS ||
|
|
kusano |
7d535a |
PS || PS || PS || PS || PS || PS)
|
|
kusano |
7d535a |
#else
|
|
kusano |
7d535a |
# error "MBITS not yet implemented"
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
lzo_uint m_len;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* 2b) code a short match */
|
|
kusano |
7d535a |
assert(pd(ip,m_pos) == m_off);
|
|
kusano |
7d535a |
--ip; /* ran one too far, point back to non-match */
|
|
kusano |
7d535a |
m_len = pd(ip, ii);
|
|
kusano |
7d535a |
assert(m_len >= MIN_MATCH_SHORT);
|
|
kusano |
7d535a |
assert(m_len <= MAX_MATCH_SHORT);
|
|
kusano |
7d535a |
assert(m_off > 0);
|
|
kusano |
7d535a |
assert(m_off <= MAX_OFFSET);
|
|
kusano |
7d535a |
assert(ii-m_off == m_pos_sav);
|
|
kusano |
7d535a |
assert(lzo_memcmp(m_pos_sav,ii,m_len) == 0);
|
|
kusano |
7d535a |
--m_off;
|
|
kusano |
7d535a |
/* code short match len + low offset bits */
|
|
kusano |
7d535a |
*op++ = LZO_BYTE(((m_len - THRESHOLD) << OBITS) |
|
|
kusano |
7d535a |
(m_off & OMASK));
|
|
kusano |
7d535a |
/* code high offset bits */
|
|
kusano |
7d535a |
*op++ = LZO_BYTE(m_off >> OBITS);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* 2c) Insert phrases (beginning with ii+1) into the dictionary. */
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
#define SI /* nothing */
|
|
kusano |
7d535a |
#define DI ++ii; DVAL_NEXT(dv,ii); UPDATE_D(dict,0,dv,ii,in);
|
|
kusano |
7d535a |
#define XI assert(ii < ip); ii = ip; DVAL_FIRST(dv,(ip));
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
#if (CLEVEL == 9) || (CLEVEL >= 7 && MBITS <= 4) || (CLEVEL >= 5 && MBITS <= 3)
|
|
kusano |
7d535a |
/* Insert the whole match (ii+1)..(ip-1) into dictionary. */
|
|
kusano |
7d535a |
++ii;
|
|
kusano |
7d535a |
do {
|
|
kusano |
7d535a |
DVAL_NEXT(dv,ii);
|
|
kusano |
7d535a |
UPDATE_D(dict,0,dv,ii,in);
|
|
kusano |
7d535a |
} while (++ii < ip);
|
|
kusano |
7d535a |
DVAL_NEXT(dv,ii);
|
|
kusano |
7d535a |
assert(ii == ip);
|
|
kusano |
7d535a |
DVAL_ASSERT(dv,ip);
|
|
kusano |
7d535a |
#elif (CLEVEL >= 3)
|
|
kusano |
7d535a |
SI DI DI XI
|
|
kusano |
7d535a |
#elif (CLEVEL >= 2)
|
|
kusano |
7d535a |
SI DI XI
|
|
kusano |
7d535a |
#else
|
|
kusano |
7d535a |
XI
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
else
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
/* we've found a long match - see how far we can still go */
|
|
kusano |
7d535a |
const lzo_bytep end;
|
|
kusano |
7d535a |
lzo_uint m_len;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
assert(ip <= in_end);
|
|
kusano |
7d535a |
assert(ii == ip - MIN_MATCH_LONG);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
if (pd(in_end,ip) <= (MAX_MATCH_LONG - MIN_MATCH_LONG))
|
|
kusano |
7d535a |
end = in_end;
|
|
kusano |
7d535a |
else
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
end = ip + (MAX_MATCH_LONG - MIN_MATCH_LONG);
|
|
kusano |
7d535a |
assert(end < in_end);
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
while (ip < end && *m_pos == *ip)
|
|
kusano |
7d535a |
m_pos++, ip++;
|
|
kusano |
7d535a |
assert(ip <= in_end);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* 2b) code the long match */
|
|
kusano |
7d535a |
m_len = pd(ip, ii);
|
|
kusano |
7d535a |
assert(m_len >= MIN_MATCH_LONG);
|
|
kusano |
7d535a |
assert(m_len <= MAX_MATCH_LONG);
|
|
kusano |
7d535a |
assert(m_off > 0);
|
|
kusano |
7d535a |
assert(m_off <= MAX_OFFSET);
|
|
kusano |
7d535a |
assert(ii-m_off == m_pos_sav);
|
|
kusano |
7d535a |
assert(lzo_memcmp(m_pos_sav,ii,m_len) == 0);
|
|
kusano |
7d535a |
assert(pd(ip,m_pos) == m_off);
|
|
kusano |
7d535a |
--m_off;
|
|
kusano |
7d535a |
/* code long match flag + low offset bits */
|
|
kusano |
7d535a |
*op++ = LZO_BYTE(((MSIZE - 1) << OBITS) | (m_off & OMASK));
|
|
kusano |
7d535a |
/* code high offset bits */
|
|
kusano |
7d535a |
*op++ = LZO_BYTE(m_off >> OBITS);
|
|
kusano |
7d535a |
/* code match len */
|
|
kusano |
7d535a |
*op++ = LZO_BYTE(m_len - MIN_MATCH_LONG);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* 2c) Insert phrases (beginning with ii+1) into the dictionary. */
|
|
kusano |
7d535a |
#if (CLEVEL == 9)
|
|
kusano |
7d535a |
/* Insert the whole match (ii+1)..(ip-1) into dictionary. */
|
|
kusano |
7d535a |
/* This is not recommended because it is slow. */
|
|
kusano |
7d535a |
++ii;
|
|
kusano |
7d535a |
do {
|
|
kusano |
7d535a |
DVAL_NEXT(dv,ii);
|
|
kusano |
7d535a |
UPDATE_D(dict,0,dv,ii,in);
|
|
kusano |
7d535a |
} while (++ii < ip);
|
|
kusano |
7d535a |
DVAL_NEXT(dv,ii);
|
|
kusano |
7d535a |
assert(ii == ip);
|
|
kusano |
7d535a |
DVAL_ASSERT(dv,ip);
|
|
kusano |
7d535a |
#elif (CLEVEL >= 8)
|
|
kusano |
7d535a |
SI DI DI DI DI DI DI DI DI XI
|
|
kusano |
7d535a |
#elif (CLEVEL >= 7)
|
|
kusano |
7d535a |
SI DI DI DI DI DI DI DI XI
|
|
kusano |
7d535a |
#elif (CLEVEL >= 6)
|
|
kusano |
7d535a |
SI DI DI DI DI DI DI XI
|
|
kusano |
7d535a |
#elif (CLEVEL >= 5)
|
|
kusano |
7d535a |
SI DI DI DI DI XI
|
|
kusano |
7d535a |
#elif (CLEVEL >= 4)
|
|
kusano |
7d535a |
SI DI DI DI XI
|
|
kusano |
7d535a |
#elif (CLEVEL >= 3)
|
|
kusano |
7d535a |
SI DI DI XI
|
|
kusano |
7d535a |
#elif (CLEVEL >= 2)
|
|
kusano |
7d535a |
SI DI XI
|
|
kusano |
7d535a |
#else
|
|
kusano |
7d535a |
XI
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* ii now points to the start of next literal run */
|
|
kusano |
7d535a |
assert(ii == ip);
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
} while (ip < ip_end);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
the_end:
|
|
kusano |
7d535a |
assert(ip <= in_end);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
#if defined(LZO_RETURN_IF_NOT_COMPRESSIBLE)
|
|
kusano |
7d535a |
/* return -1 if op == out to indicate that we
|
|
kusano |
7d535a |
* couldn't compress and didn't copy anything.
|
|
kusano |
7d535a |
*/
|
|
kusano |
7d535a |
if (op == out)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
*out_len = 0;
|
|
kusano |
7d535a |
return LZO_E_NOT_COMPRESSIBLE;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* store the final literal run */
|
|
kusano |
7d535a |
if (pd(in_end+DVAL_LEN,ii) > 0)
|
|
kusano |
7d535a |
op = store_run(op,ii,pd(in_end+DVAL_LEN,ii));
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
*out_len = pd(op, out);
|
|
kusano |
7d535a |
return 0; /* compression went ok */
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/***********************************************************************
|
|
kusano |
7d535a |
// compress public entry point.
|
|
kusano |
7d535a |
************************************************************************/
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
LZO_PUBLIC(int)
|
|
kusano |
7d535a |
lzo1_compress ( const lzo_bytep in , lzo_uint in_len,
|
|
kusano |
7d535a |
lzo_bytep out, lzo_uintp out_len,
|
|
kusano |
7d535a |
lzo_voidp wrkmem )
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
int r = LZO_E_OK;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* don't try to compress a block that's too short */
|
|
kusano |
7d535a |
if (in_len <= 0)
|
|
kusano |
7d535a |
*out_len = 0;
|
|
kusano |
7d535a |
else if (in_len <= MIN_MATCH_LONG + DVAL_LEN + 1)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
#if defined(LZO_RETURN_IF_NOT_COMPRESSIBLE)
|
|
kusano |
7d535a |
r = LZO_E_NOT_COMPRESSIBLE;
|
|
kusano |
7d535a |
#else
|
|
kusano |
7d535a |
*out_len = pd(store_run(out,in,in_len), out);
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
else
|
|
kusano |
7d535a |
r = do_compress(in,in_len,out,out_len,wrkmem);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
return r;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/*
|
|
kusano |
7d535a |
vi:ts=4:et
|
|
kusano |
7d535a |
*/
|