Blame src/lzo1x_oo.ch

Packit 679830
/* lzo1x_oo.ch -- LZO1X compressed data optimizer
Packit 679830
Packit 679830
   This file is part of the LZO real-time data compression library.
Packit 679830
Packit 679830
   Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer
Packit 679830
   All Rights Reserved.
Packit 679830
Packit 679830
   The LZO library is free software; you can redistribute it and/or
Packit 679830
   modify it under the terms of the GNU General Public License as
Packit 679830
   published by the Free Software Foundation; either version 2 of
Packit 679830
   the License, or (at your option) any later version.
Packit 679830
Packit 679830
   The LZO library is distributed in the hope that it will be useful,
Packit 679830
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 679830
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 679830
   GNU General Public License for more details.
Packit 679830
Packit 679830
   You should have received a copy of the GNU General Public License
Packit 679830
   along with the LZO library; see the file COPYING.
Packit 679830
   If not, write to the Free Software Foundation, Inc.,
Packit 679830
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Packit 679830
Packit 679830
   Markus F.X.J. Oberhumer
Packit 679830
   <markus@oberhumer.com>
Packit 679830
   http://www.oberhumer.com/opensource/lzo/
Packit 679830
 */
Packit 679830
Packit 679830
Packit 679830
#define TEST_IP     (ip < ip_end)
Packit 679830
#define TEST_OP     (op <= op_end)
Packit 679830
#define TEST_IP_AND_TEST_OP (TEST_IP && TEST_OP)
Packit 679830
Packit 679830
#define NO_LIT      LZO_UINT_MAX
Packit 679830
Packit 679830
Packit 679830
/***********************************************************************
Packit 679830
//
Packit 679830
************************************************************************/
Packit 679830
Packit 679830
static void copy2(lzo_bytep ip, const lzo_bytep m_pos, lzo_uint off)
Packit 679830
{
Packit 679830
    assert(off > 0);
Packit 679830
    ip[0] = m_pos[0];
Packit 679830
    if (off == 1)
Packit 679830
        ip[1] = m_pos[0];
Packit 679830
    else
Packit 679830
        ip[1] = m_pos[1];
Packit 679830
}
Packit 679830
Packit 679830
Packit 679830
static void copy3(lzo_bytep ip, const lzo_bytep m_pos, lzo_uint off)
Packit 679830
{
Packit 679830
    assert(off > 0);
Packit 679830
    ip[0] = m_pos[0];
Packit 679830
    if (off == 1)
Packit 679830
    {
Packit 679830
        ip[2] = ip[1] = m_pos[0];
Packit 679830
    }
Packit 679830
    else if (off == 2)
Packit 679830
    {
Packit 679830
        ip[1] = m_pos[1];
Packit 679830
        ip[2] = m_pos[0];
Packit 679830
    }
Packit 679830
    else
Packit 679830
    {
Packit 679830
        ip[1] = m_pos[1];
Packit 679830
        ip[2] = m_pos[2];
Packit 679830
    }
Packit 679830
}
Packit 679830
Packit 679830
Packit 679830
/***********************************************************************
Packit 679830
// optimize a block of data.
Packit 679830
************************************************************************/
Packit 679830
Packit 679830
LZO_PUBLIC(int)
Packit 679830
DO_OPTIMIZE          (       lzo_bytep in , lzo_uint  in_len,
Packit 679830
                             lzo_bytep out, lzo_uintp out_len,
Packit 679830
                             lzo_voidp wrkmem )
Packit 679830
{
Packit 679830
    lzo_bytep op;
Packit 679830
    lzo_bytep ip;
Packit 679830
    lzo_uint t;
Packit 679830
    lzo_bytep m_pos;
Packit 679830
    lzo_bytep const ip_end = in + in_len;
Packit 679830
    lzo_bytep const op_end = out + *out_len;
Packit 679830
    lzo_bytep litp = NULL;
Packit 679830
    lzo_uint lit = 0;
Packit 679830
    lzo_uint next_lit = NO_LIT;
Packit 679830
    lzo_uint nl;
Packit 679830
    unsigned long o_m1_a = 0, o_m1_b = 0, o_m2 = 0, o_m3_a = 0, o_m3_b = 0;
Packit 679830
Packit 679830
    LZO_UNUSED(wrkmem);
Packit 679830
Packit 679830
    *out_len = 0;
Packit 679830
Packit 679830
    op = out;
Packit 679830
    ip = in;
Packit 679830
Packit 679830
    assert(in_len >= 3);
Packit 679830
    if (*ip > 17)
Packit 679830
    {
Packit 679830
        t = *ip++ - 17;
Packit 679830
        if (t < 4)
Packit 679830
            goto match_next;
Packit 679830
        goto first_literal_run;
Packit 679830
    }
Packit 679830
    assert(*ip < 16 || (*ip == 17 && in_len == 3));
Packit 679830
Packit 679830
    while (TEST_IP_AND_TEST_OP)
Packit 679830
    {
Packit 679830
        t = *ip++;
Packit 679830
        if (t >= 16)
Packit 679830
            goto match;
Packit 679830
        /* a literal run */
Packit 679830
        litp = ip - 1;
Packit 679830
        if (t == 0)
Packit 679830
        {
Packit 679830
            t = 15;
Packit 679830
            while (*ip == 0)
Packit 679830
                t += 255, ip++;
Packit 679830
            t += *ip++;
Packit 679830
        }
Packit 679830
        lit = t + 3;
Packit 679830
        /* copy literals */
Packit 679830
copy_literal_run:
Packit 679830
        *op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
Packit 679830
first_literal_run:
Packit 679830
        do *op++ = *ip++; while (--t > 0);
Packit 679830
Packit 679830
Packit 679830
        t = *ip++;
Packit 679830
Packit 679830
        if (t >= 16)
Packit 679830
            goto match;
Packit 679830
#if defined(LZO1X)
Packit 679830
        m_pos = op - 1 - 0x800;
Packit 679830
#elif defined(LZO1Y)
Packit 679830
        m_pos = op - 1 - 0x400;
Packit 679830
#endif
Packit 679830
        m_pos -= t >> 2;
Packit 679830
        m_pos -= *ip++ << 2;
Packit 679830
        *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos++;
Packit 679830
        lit = 0;
Packit 679830
        goto match_done;
Packit 679830
Packit 679830
Packit 679830
        /* handle matches */
Packit 679830
        do {
Packit 679830
            if (t < 16)                     /* a M1 match */
Packit 679830
            {
Packit 679830
                m_pos = op - 1;
Packit 679830
                m_pos -= t >> 2;
Packit 679830
                m_pos -= *ip++ << 2;
Packit 679830
Packit 679830
                if (litp == NULL)
Packit 679830
                    goto copy_m1;
Packit 679830
Packit 679830
                /* assert that there was a match just before */
Packit 679830
                assert(lit >= 1 && lit <= 3);
Packit 679830
                assert(litp == ip - 2 - lit - 2);
Packit 679830
                assert((lzo_uint)(*litp & 3) == lit);
Packit 679830
                nl = ip[-2] & 3;
Packit 679830
                /* test if a match follows */
Packit 679830
                if (nl == 0 && lit == 1 && ip[0] >= 16)
Packit 679830
                {
Packit 679830
                    next_lit = nl;
Packit 679830
                    /* adjust length of previous short run */
Packit 679830
                    lit += 2;
Packit 679830
                    *litp = LZO_BYTE((*litp & ~3) | lit);
Packit 679830
                    /* copy over the 2 literals that replace the match */
Packit 679830
                    copy2(ip-2,m_pos,pd(op,m_pos));
Packit 679830
                    o_m1_a++;
Packit 679830
                }
Packit 679830
                /* test if a literal run follows */
Packit 679830
                else if (nl == 0 && ip[0] < 16 && ip[0] != 0 &&
Packit 679830
                         (lit + 2 + ip[0] < 16))
Packit 679830
                {
Packit 679830
                    t = *ip++;
Packit 679830
                    /* remove short run */
Packit 679830
                    *litp &= ~3;
Packit 679830
                    /* copy over the 2 literals that replace the match */
Packit 679830
                    copy2(ip-3+1,m_pos,pd(op,m_pos));
Packit 679830
                    /* move literals 1 byte ahead */
Packit 679830
                    litp += 2;
Packit 679830
                    if (lit > 0)
Packit 679830
                        lzo_memmove(litp+1,litp,lit);
Packit 679830
                    /* insert new length of long literal run */
Packit 679830
                    lit += 2 + t + 3; assert(lit <= 18);
Packit 679830
                    *litp = LZO_BYTE(lit - 3);
Packit 679830
Packit 679830
                    o_m1_b++;
Packit 679830
                    *op++ = *m_pos++; *op++ = *m_pos++;
Packit 679830
                    goto copy_literal_run;
Packit 679830
                }
Packit 679830
copy_m1:
Packit 679830
                *op++ = *m_pos++; *op++ = *m_pos++;
Packit 679830
            }
Packit 679830
            else
Packit 679830
            {
Packit 679830
match:
Packit 679830
                if (t >= 64)                /* a M2 match */
Packit 679830
                {
Packit 679830
                    m_pos = op - 1;
Packit 679830
#if defined(LZO1X)
Packit 679830
                    m_pos -= (t >> 2) & 7;
Packit 679830
                    m_pos -= *ip++ << 3;
Packit 679830
                    t = (t >> 5) - 1;
Packit 679830
#elif defined(LZO1Y)
Packit 679830
                    m_pos -= (t >> 2) & 3;
Packit 679830
                    m_pos -= *ip++ << 2;
Packit 679830
                    t = (t >> 4) - 3;
Packit 679830
#endif
Packit 679830
                    if (litp == NULL)
Packit 679830
                        goto copy_m;
Packit 679830
Packit 679830
                    nl = ip[-2] & 3;
Packit 679830
                    /* test if in beetween two long literal runs */
Packit 679830
                    if (t == 1 && lit > 3 && nl == 0 &&
Packit 679830
                        ip[0] < 16 && ip[0] != 0 && (lit + 3 + ip[0] < 16))
Packit 679830
                    {
Packit 679830
                        assert(*litp == lit - 3);
Packit 679830
                        t = *ip++;
Packit 679830
                        /* copy over the 3 literals that replace the match */
Packit 679830
                        copy3(ip-1-2,m_pos,pd(op,m_pos));
Packit 679830
                        /* set new length of previous literal run */
Packit 679830
                        lit += 3 + t + 3; assert(lit <= 18);
Packit 679830
                        *litp = LZO_BYTE(lit - 3);
Packit 679830
                        o_m2++;
Packit 679830
                        *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos++;
Packit 679830
                        goto copy_literal_run;
Packit 679830
                    }
Packit 679830
                }
Packit 679830
                else
Packit 679830
                {
Packit 679830
                    if (t >= 32)            /* a M3 match */
Packit 679830
                    {
Packit 679830
                        t &= 31;
Packit 679830
                        if (t == 0)
Packit 679830
                        {
Packit 679830
                            t = 31;
Packit 679830
                            while (*ip == 0)
Packit 679830
                                t += 255, ip++;
Packit 679830
                            t += *ip++;
Packit 679830
                        }
Packit 679830
                        m_pos = op - 1;
Packit 679830
                        m_pos -= *ip++ >> 2;
Packit 679830
                        m_pos -= *ip++ << 6;
Packit 679830
                    }
Packit 679830
                    else                    /* a M4 match */
Packit 679830
                    {
Packit 679830
                        m_pos = op;
Packit 679830
                        m_pos -= (t & 8) << 11;
Packit 679830
                        t &= 7;
Packit 679830
                        if (t == 0)
Packit 679830
                        {
Packit 679830
                            t = 7;
Packit 679830
                            while (*ip == 0)
Packit 679830
                                t += 255, ip++;
Packit 679830
                            t += *ip++;
Packit 679830
                        }
Packit 679830
                        m_pos -= *ip++ >> 2;
Packit 679830
                        m_pos -= *ip++ << 6;
Packit 679830
                        if (m_pos == op)
Packit 679830
                            goto eof_found;
Packit 679830
                        m_pos -= 0x4000;
Packit 679830
                    }
Packit 679830
                    if (litp == NULL)
Packit 679830
                        goto copy_m;
Packit 679830
Packit 679830
                    nl = ip[-2] & 3;
Packit 679830
                    /* test if in beetween two matches */
Packit 679830
                    if (t == 1 && lit == 0 && nl == 0 && ip[0] >= 16)
Packit 679830
                    {
Packit 679830
                        assert(litp == ip - 3 - lit - 2);
Packit 679830
                        assert((lzo_uint)(*litp & 3) == lit);
Packit 679830
                        next_lit = nl;
Packit 679830
                        /* make a previous short run */
Packit 679830
                        lit += 3;
Packit 679830
                        *litp = LZO_BYTE((*litp & ~3) | lit);
Packit 679830
                        /* copy over the 3 literals that replace the match */
Packit 679830
                        copy3(ip-3,m_pos,pd(op,m_pos));
Packit 679830
                        o_m3_a++;
Packit 679830
                    }
Packit 679830
                    /* test if a literal run follows */
Packit 679830
                    else if (t == 1 && lit <= 3 && nl == 0 &&
Packit 679830
                             ip[0] < 16 && ip[0] != 0 && (lit + 3 + ip[0] < 16))
Packit 679830
                    {
Packit 679830
                        assert(litp == ip - 3 - lit - 2);
Packit 679830
                        assert((lzo_uint)(*litp & 3) == lit);
Packit 679830
                        t = *ip++;
Packit 679830
                        /* remove short run */
Packit 679830
                        *litp &= ~3;
Packit 679830
                        /* copy over the 3 literals that replace the match */
Packit 679830
                        copy3(ip-4+1,m_pos,pd(op,m_pos));
Packit 679830
                        /* move literals 1 byte ahead */
Packit 679830
                        litp += 2;
Packit 679830
                        if (lit > 0)
Packit 679830
                            lzo_memmove(litp+1,litp,lit);
Packit 679830
                        /* insert new length of long literal run */
Packit 679830
                        lit += 3 + t + 3; assert(lit <= 18);
Packit 679830
                        *litp = LZO_BYTE(lit - 3);
Packit 679830
Packit 679830
                        o_m3_b++;
Packit 679830
                        *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos++;
Packit 679830
                        goto copy_literal_run;
Packit 679830
                    }
Packit 679830
                }
Packit 679830
copy_m:
Packit 679830
                *op++ = *m_pos++; *op++ = *m_pos++;
Packit 679830
                do *op++ = *m_pos++; while (--t > 0);
Packit 679830
            }
Packit 679830
Packit 679830
match_done:
Packit 679830
            if (next_lit == NO_LIT)
Packit 679830
            {
Packit 679830
                t = ip[-2] & 3;
Packit 679830
                lit = t;
Packit 679830
                litp = ip - 2;
Packit 679830
            }
Packit 679830
            else
Packit 679830
                t = next_lit;
Packit 679830
            assert(t <= 3);
Packit 679830
            next_lit = NO_LIT;
Packit 679830
            if (t == 0)
Packit 679830
                break;
Packit 679830
            /* copy literals */
Packit 679830
match_next:
Packit 679830
            do *op++ = *ip++; while (--t > 0);
Packit 679830
            t = *ip++;
Packit 679830
        } while (TEST_IP_AND_TEST_OP);
Packit 679830
    }
Packit 679830
Packit 679830
    /* no EOF code was found */
Packit 679830
    *out_len = pd(op, out);
Packit 679830
    return LZO_E_EOF_NOT_FOUND;
Packit 679830
Packit 679830
eof_found:
Packit 679830
    assert(t == 1);
Packit 679830
#if 0
Packit 679830
    printf("optimize: %5lu %5lu   %5lu   %5lu %5lu\n",
Packit 679830
           o_m1_a, o_m1_b, o_m2, o_m3_a, o_m3_b);
Packit 679830
#endif
Packit 679830
    LZO_UNUSED(o_m1_a); LZO_UNUSED(o_m1_b); LZO_UNUSED(o_m2);
Packit 679830
    LZO_UNUSED(o_m3_a); LZO_UNUSED(o_m3_b);
Packit 679830
    *out_len = pd(op, out);
Packit 679830
    return (ip == ip_end ? LZO_E_OK :
Packit 679830
           (ip < ip_end  ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
Packit 679830
}
Packit 679830
Packit 679830
Packit 679830
/*
Packit 679830
vi:ts=4:et
Packit 679830
*/
Packit 679830