kusano 7d535a
/* lzo1a.c -- implementation of the LZO1A 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/lzo1a.h"
kusano 7d535a
kusano 7d535a
kusano 7d535a
/***********************************************************************
kusano 7d535a
// The next two defines can be changed to customize LZO1A.
kusano 7d535a
// The default version is LZO1A-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
 */
kusano 7d535a
#if !defined(CLEVEL)
kusano 7d535a
#  define CLEVEL    1           /* fastest by default */
kusano 7d535a
#endif
kusano 7d535a
kusano 7d535a
kusano 7d535a
/* Collect statistics */
kusano 7d535a
#if 0 && !defined(LZO_COLLECT_STATS)
kusano 7d535a
#  define LZO_COLLECT_STATS
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
/* 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
// 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
#include "lzo1a_de.h"
kusano 7d535a
#include "stats1a.h"
kusano 7d535a
kusano 7d535a
kusano 7d535a
/* check other constants */
kusano 7d535a
#if (LBITS < 5 || LBITS > 8)
kusano 7d535a
#  error "invalid LBITS"
kusano 7d535a
#endif
kusano 7d535a
kusano 7d535a
kusano 7d535a
#if defined(LZO_COLLECT_STATS)
kusano 7d535a
   static lzo1a_stats_t lzo_statistics;
kusano 7d535a
   lzo1a_stats_t *lzo1a_stats = &lzo_statistics;
kusano 7d535a
#  define lzo_stats lzo1a_stats
kusano 7d535a
#endif
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) lzo1a_info ( int *rbits, int *clevel );
kusano 7d535a
kusano 7d535a
LZO_PUBLIC(lzo_uint)
kusano 7d535a
lzo1a_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
// LZO1A 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
lzo1a_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
    register lzo_bytep op;
kusano 7d535a
    register const lzo_bytep ip;
kusano 7d535a
    register lzo_uint t;
kusano 7d535a
    register const lzo_bytep m_pos;
kusano 7d535a
    const lzo_bytep const ip_end = in + in_len;
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
        LZO_STATS(lzo_stats->marker[t]++);
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
            goto literal;
kusano 7d535a
        }
kusano 7d535a
        else if (t < R0MIN)     /* a short literal run */
kusano 7d535a
        {
kusano 7d535a
literal:
kusano 7d535a
            MEMCPY_DS(op,ip,t);
kusano 7d535a
kusano 7d535a
        /* after a literal a match must follow */
kusano 7d535a
            while (ip < ip_end)
kusano 7d535a
            {
kusano 7d535a
                t = *ip++;          /* get R1 marker */
kusano 7d535a
                if (t >= R0MIN)
kusano 7d535a
                    goto match;
kusano 7d535a
kusano 7d535a
            /* R1 match - a context sensitive 3 byte match + 1 byte literal */
kusano 7d535a
                assert((t & OMASK) == t);
kusano 7d535a
                m_pos = op - MIN_OFFSET;
kusano 7d535a
                m_pos -= t | (((lzo_uint) *ip++) << OBITS);
kusano 7d535a
                assert(m_pos >= out); assert(m_pos < op);
kusano 7d535a
                *op++ = *m_pos++;
kusano 7d535a
                *op++ = *m_pos++;
kusano 7d535a
                *op++ = *m_pos++;
kusano 7d535a
                *op++ = *ip++;
kusano 7d535a
            }
kusano 7d535a
        }
kusano 7d535a
        else                    /* a match */
kusano 7d535a
        {
kusano 7d535a
match:
kusano 7d535a
            /* get match offset */
kusano 7d535a
            m_pos = op - MIN_OFFSET;
kusano 7d535a
            m_pos -= (t & OMASK) | (((lzo_uint) *ip++) << OBITS);
kusano 7d535a
            assert(m_pos >= out); assert(m_pos < op);
kusano 7d535a
kusano 7d535a
            /* get match len */
kusano 7d535a
            if (t < ((MSIZE - 1) << OBITS))         /* a short match */
kusano 7d535a
            {
kusano 7d535a
                t >>= OBITS;
kusano 7d535a
                *op++ = *m_pos++;
kusano 7d535a
                *op++ = *m_pos++;
kusano 7d535a
                MEMCPY_DS(op,m_pos,t);
kusano 7d535a
            }
kusano 7d535a
            else                                     /* a long match */
kusano 7d535a
            {
kusano 7d535a
#if (LBITS < 8)
kusano 7d535a
                t = (MIN_MATCH_LONG - THRESHOLD) + ((lzo_uint)(*ip++) & LMASK);
kusano 7d535a
#else
kusano 7d535a
                t = (MIN_MATCH_LONG - THRESHOLD) + (lzo_uint)(*ip++);
kusano 7d535a
#endif
kusano 7d535a
                *op++ = *m_pos++;
kusano 7d535a
                *op++ = *m_pos++;
kusano 7d535a
                MEMCPY_DS(op,m_pos,t);
kusano 7d535a
#if (LBITS < 8)
kusano 7d535a
                /* a very short literal following a long match */
kusano 7d535a
                t = ip[-1] >> LBITS;
kusano 7d535a
                if (t) do
kusano 7d535a
                    *op++ = *ip++;
kusano 7d535a
                while (--t);
kusano 7d535a
#endif
kusano 7d535a
            }
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
/***********************************************************************
kusano 7d535a
// LZO1A compress a block of data.
kusano 7d535a
//
kusano 7d535a
// I apologize for the spaghetti code, but it really helps the optimizer.
kusano 7d535a
************************************************************************/
kusano 7d535a
kusano 7d535a
#include "lzo1a_cr.ch"
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
    register const lzo_bytep ip;
kusano 7d535a
#if defined(__LZO_HASH_INCREMENTAL)
kusano 7d535a
    lzo_xint dv;
kusano 7d535a
#endif
kusano 7d535a
    const lzo_bytep m_pos;
kusano 7d535a
    lzo_bytep op;
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
    const lzo_bytep r1 = ip_end;    /* pointer for R1 match (none yet) */
kusano 7d535a
#if (LBITS < 8)
kusano 7d535a
    const lzo_bytep im = ip_end;    /* pointer to last match start */
kusano 7d535a
#endif
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 current literal run */
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); UPDATE_D(dict,0,dv,ip,in); 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_NON_DET(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_NON_DET(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
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
        assert(m_pos == NULL || m_pos >= in);
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
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
kusano 7d535a
            assert(m_pos >= in);
kusano 7d535a
            assert(ip < ip_end);
kusano 7d535a
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
kusano 7d535a
                if (ip - r1 == MIN_MATCH + 1)
kusano 7d535a
                {
kusano 7d535a
                /* Code a context sensitive R1 match.
kusano 7d535a
                 * This is tricky and somewhat difficult to explain:
kusano 7d535a
                 * multiplex a literal run of length 1 into the previous
kusano 7d535a
                 * short match of length MIN_MATCH.
kusano 7d535a
                 * The key idea is:
kusano 7d535a
                 *  - after a short run a match MUST follow
kusano 7d535a
                 *  - therefore the value m = 000 in the mmmooooo marker is free
kusano 7d535a
                 *  - use 000ooooo to indicate a MIN_MATCH match (this
kusano 7d535a
                 *    is already coded) plus a 1 byte literal
kusano 7d535a
                 */
kusano 7d535a
                    assert(t == 1);
kusano 7d535a
                    /* modify marker byte */
kusano 7d535a
                    assert((op[-2] >> OBITS) == (MIN_MATCH - THRESHOLD));
kusano 7d535a
                    op[-2] &= OMASK;
kusano 7d535a
                    assert((op[-2] >> OBITS) == 0);
kusano 7d535a
                    /* copy 1 literal */
kusano 7d535a
                    *op++ = *ii;
kusano 7d535a
                    LZO_STATS(lzo_stats->r1_matches++);
kusano 7d535a
                    r1 = ip;                /* set new R1 pointer */
kusano 7d535a
                }
kusano 7d535a
                else if (t < R0MIN)
kusano 7d535a
                {
kusano 7d535a
                    /* inline the copying of a short run */
kusano 7d535a
#if (LBITS < 8)
kusano 7d535a
                    if (t < (1 << (8-LBITS)) && ii - im >= MIN_MATCH_LONG)
kusano 7d535a
                    {
kusano 7d535a
                    /* Code a very short literal run into the
kusano 7d535a
                     * previous long match length byte.
kusano 7d535a
                     */
kusano 7d535a
                        LZO_STATS(lzo_stats->lit_runs_after_long_match++);
kusano 7d535a
                        LZO_STATS(lzo_stats->lit_run_after_long_match[t]++);
kusano 7d535a
                        assert(ii - im <= MAX_MATCH_LONG);
kusano 7d535a
                        assert((op[-1] >> LBITS) == 0);
kusano 7d535a
                        op[-1] |= t << LBITS;
kusano 7d535a
                        MEMCPY_DS(op, ii, t);
kusano 7d535a
                    }
kusano 7d535a
                    else
kusano 7d535a
#endif
kusano 7d535a
                    {
kusano 7d535a
                        LZO_STATS(lzo_stats->lit_runs++);
kusano 7d535a
                        LZO_STATS(lzo_stats->lit_run[t]++);
kusano 7d535a
                        *op++ = LZO_BYTE(t);
kusano 7d535a
                        MEMCPY_DS(op, ii, t);
kusano 7d535a
                        r1 = ip;                /* set new R1 pointer */
kusano 7d535a
                    }
kusano 7d535a
                }
kusano 7d535a
                else if (t < R0FAST)
kusano 7d535a
                {
kusano 7d535a
                    /* inline the copying of a short R0 run */
kusano 7d535a
                    LZO_STATS(lzo_stats->r0short_runs++);
kusano 7d535a
                    *op++ = 0; *op++ = LZO_BYTE(t - R0MIN);
kusano 7d535a
                    MEMCPY_DS(op, ii, t);
kusano 7d535a
                    r1 = ip;                /* set new R1 pointer */
kusano 7d535a
                }
kusano 7d535a
                else
kusano 7d535a
                    op = store_run(op,ii,t);
kusano 7d535a
            }
kusano 7d535a
#if (LBITS < 8)
kusano 7d535a
            im = ip;
kusano 7d535a
#endif
kusano 7d535a
kusano 7d535a
kusano 7d535a
            /* 2) 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
            /* we've found a short match */
kusano 7d535a
                lzo_uint m_len;
kusano 7d535a
kusano 7d535a
            /* 2a) compute match parameters */
kusano 7d535a
                    assert(ip-m_pos == (int)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 >= MIN_OFFSET);
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 -= MIN_OFFSET;
kusano 7d535a
kusano 7d535a
            /* 2b) code a short match */
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
#if defined(LZO_COLLECT_STATS)
kusano 7d535a
                lzo_stats->short_matches++;
kusano 7d535a
                lzo_stats->short_match[m_len]++;
kusano 7d535a
                if (m_off < OSIZE)
kusano 7d535a
                    lzo_stats->short_match_offset_osize[m_len]++;
kusano 7d535a
                if (m_off < 256)
kusano 7d535a
                    lzo_stats->short_match_offset_256[m_len]++;
kusano 7d535a
                if (m_off < 1024)
kusano 7d535a
                    lzo_stats->short_match_offset_1024[m_len]++;
kusano 7d535a
#endif
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
            /* 2a) compute match parameters */
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 >= MIN_OFFSET);
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 -= MIN_OFFSET;
kusano 7d535a
kusano 7d535a
            /* 2b) code the long match */
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
#if defined(LZO_COLLECT_STATS)
kusano 7d535a
                lzo_stats->long_matches++;
kusano 7d535a
                lzo_stats->long_match[m_len]++;
kusano 7d535a
#endif
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 the next literal run */
kusano 7d535a
            assert(ii == ip);
kusano 7d535a
        }
kusano 7d535a
kusano 7d535a
    } while (ip < ip_end);
kusano 7d535a
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
    /* 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
// LZO1A compress public entry point.
kusano 7d535a
************************************************************************/
kusano 7d535a
kusano 7d535a
LZO_PUBLIC(int)
kusano 7d535a
lzo1a_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
kusano 7d535a
#if defined(LZO_COLLECT_STATS)
kusano 7d535a
    lzo_memset(lzo_stats,0,sizeof(*lzo_stats));
kusano 7d535a
    lzo_stats->rbits  = RBITS;
kusano 7d535a
    lzo_stats->clevel = CLEVEL;
kusano 7d535a
    lzo_stats->dbits  = DBITS;
kusano 7d535a
    lzo_stats->lbits  = LBITS;
kusano 7d535a
    lzo_stats->min_match_short = MIN_MATCH_SHORT;
kusano 7d535a
    lzo_stats->max_match_short = MAX_MATCH_SHORT;
kusano 7d535a
    lzo_stats->min_match_long  = MIN_MATCH_LONG;
kusano 7d535a
    lzo_stats->max_match_long  = MAX_MATCH_LONG;
kusano 7d535a
    lzo_stats->min_offset      = MIN_OFFSET;
kusano 7d535a
    lzo_stats->max_offset      = MAX_OFFSET;
kusano 7d535a
    lzo_stats->r0min  = R0MIN;
kusano 7d535a
    lzo_stats->r0fast = R0FAST;
kusano 7d535a
    lzo_stats->r0max  = R0MAX;
kusano 7d535a
    lzo_stats->in_len = in_len;
kusano 7d535a
#endif
kusano 7d535a
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
kusano 7d535a
#if defined(LZO_COLLECT_STATS)
kusano 7d535a
    lzo_stats->short_matches -= lzo_stats->r1_matches;
kusano 7d535a
    lzo_stats->short_match[MIN_MATCH] -= lzo_stats->r1_matches;
kusano 7d535a
    lzo_stats->out_len = *out_len;
kusano 7d535a
#endif
kusano 7d535a
kusano 7d535a
    return r;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
/*
kusano 7d535a
vi:ts=4:et
kusano 7d535a
*/