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
*/