/* lzo_mchw.ch -- matching functions using a window

   This file is part of the LZO real-time data compression library.

   Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer
   All Rights Reserved.

   The LZO library is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License, or (at your option) any later version.

   The LZO library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with the LZO library; see the file COPYING.
   If not, write to the Free Software Foundation, Inc.,
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

   Markus F.X.J. Oberhumer
   <markus@oberhumer.com>
   http://www.oberhumer.com/opensource/lzo/
 */


/***********************************************************************
//
************************************************************************/

typedef struct
{
    unsigned init;

    lzo_uint look;          /* bytes in lookahead buffer */

    lzo_uint m_len;
    lzo_uint m_off;

    lzo_uint last_m_len;
    lzo_uint last_m_off;

    const lzo_bytep bp;
    const lzo_bytep ip;
    const lzo_bytep in;
    const lzo_bytep in_end;
    lzo_bytep out;

    lzo_callback_p cb;

    lzo_uint textsize;      /* text size counter */
    lzo_uint codesize;      /* code size counter */
    lzo_uint printcount;    /* counter for reporting progress every 1K bytes */

    /* some stats */
    unsigned long lit_bytes;
    unsigned long match_bytes;
    unsigned long rep_bytes;
    unsigned long lazy;

#if defined(LZO1B)
    lzo_uint r1_m_len;

    /* some stats */
    unsigned long r1_r, m3_r, m2_m, m3_m;
#endif

#if defined(LZO1C)
    lzo_uint r1_m_len;
    lzo_bytep m3;

    /* some stats */
    unsigned long r1_r, m3_r, m2_m, m3_m;
#endif

#if defined(LZO1F)
    lzo_uint r1_lit;
    lzo_uint r1_m_len;

    /* some stats */
    unsigned long r1_r, m2_m, m3_m;
#endif

#if defined(LZO1X) || defined(LZO1Y) || defined(LZO1Z)
    lzo_uint r1_lit;
    lzo_uint r1_m_len;

    /* some stats */
    unsigned long m1a_m, m1b_m, m2_m, m3_m, m4_m;
    unsigned long lit1_r, lit2_r, lit3_r;
#endif

#if defined(LZO2A)
    /* some stats */
    unsigned long m1, m2, m3, m4;
#endif
}
LZO_COMPRESS_T;


#define getbyte(c)  ((c).ip < (c).in_end ? *((c).ip)++ : (-1))

#include "lzo_swd.ch"


/***********************************************************************
//
************************************************************************/

static int
init_match ( LZO_COMPRESS_T *c, lzo_swd_p s,
             const lzo_bytep dict, lzo_uint dict_len,
             lzo_uint32_t flags )
{
    int r;

    assert(!c->init);
    c->init = 1;

    s->c = c;

    c->last_m_len = c->last_m_off = 0;

    c->textsize = c->codesize = c->printcount = 0;
    c->lit_bytes = c->match_bytes = c->rep_bytes = 0;
    c->lazy = 0;

    r = swd_init(s,dict,dict_len);
    if (r != LZO_E_OK)
    {
        swd_exit(s);
        return r;
    }

    s->use_best_off = (flags & 1) ? 1 : 0;
    return LZO_E_OK;
}


/***********************************************************************
//
************************************************************************/

static int
find_match ( LZO_COMPRESS_T *c, lzo_swd_p s,
             lzo_uint this_len, lzo_uint skip )
{
    assert(c->init);

    if (skip > 0)
    {
        assert(this_len >= skip);
        swd_accept(s, this_len - skip);
        c->textsize += this_len - skip + 1;
    }
    else
    {
        assert(this_len <= 1);
        c->textsize += this_len - skip;
    }

    s->m_len = SWD_THRESHOLD;
    s->m_off = 0;
#ifdef SWD_BEST_OFF
    if (s->use_best_off)
        lzo_memset(s->best_pos,0,sizeof(s->best_pos));
#endif
    swd_findbest(s);
    c->m_len = s->m_len;
    c->m_off = s->m_off;

    swd_getbyte(s);

    if (s->b_char < 0)
    {
        c->look = 0;
        c->m_len = 0;
        swd_exit(s);
    }
    else
    {
        c->look = s->look + 1;
    }
    c->bp = c->ip - c->look;

#if 0
    /* brute force match search */
    if (c->m_len > SWD_THRESHOLD && c->m_len + 1 <= c->look)
    {
        const lzo_bytep ip = c->bp;
        const lzo_bytep m  = c->bp - c->m_off;
        const lzo_bytep in = c->in;

        if (ip - in > s->swd_n)
            in = ip - s->swd_n;
        for (;;)
        {
            while (*in != *ip)
                in++;
            if (in == ip)
                break;
            if (in != m)
                if (lzo_memcmp(in,ip,c->m_len+1) == 0)
                    printf("%p %p %p %5d\n",in,ip,m,c->m_len);
            in++;
        }
    }
#endif

    if (c->cb && c->cb->nprogress && c->textsize > c->printcount)
    {
        (*c->cb->nprogress)(c->cb, c->textsize, c->codesize, 0);
        c->printcount += 1024;
    }

    return LZO_E_OK;
}


/*
vi:ts=4:et
*/

