1/* lzo1x_c.ch -- implementation of the LZO1[XY]-1 compression algorithm
2
3   This file is part of the LZO real-time data compression library.
4
5   Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer
6   All Rights Reserved.
7
8   The LZO library is free software; you can redistribute it and/or
9   modify it under the terms of the GNU General Public License as
10   published by the Free Software Foundation; either version 2 of
11   the License, or (at your option) any later version.
12
13   The LZO library is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with the LZO library; see the file COPYING.
20   If not, write to the Free Software Foundation, Inc.,
21   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22
23   Markus F.X.J. Oberhumer
24   <markus@oberhumer.com>
25   http://www.oberhumer.com/opensource/lzo/
26 */
27
28
29
30#if 1 && defined(DO_COMPRESS) && !defined(do_compress)
31   /* choose a unique name to better help PGO optimizations */
32#  define do_compress       LZO_PP_ECONCAT2(DO_COMPRESS,_core)
33#endif
34
35
36/***********************************************************************
37// compress a block of data.
38************************************************************************/
39
40static __lzo_noinline lzo_uint
41do_compress ( const lzo_bytep in , lzo_uint  in_len,
42                    lzo_bytep out, lzo_uintp out_len,
43                    lzo_uint  ti,  lzo_voidp wrkmem)
44{
45    const lzo_bytep ip;
46    lzo_bytep op;
47    const lzo_bytep const in_end = in + in_len;
48    const lzo_bytep const ip_end = in + in_len - 20;
49    const lzo_bytep ii;
50    lzo_dict_p const dict = (lzo_dict_p) wrkmem;
51
52    op = out;
53    ip = in;
54    ii = ip;
55
56    ip += ti < 4 ? 4 - ti : 0;
57    for (;;)
58    {
59        const lzo_bytep m_pos;
60#if !(LZO_DETERMINISTIC)
61        LZO_DEFINE_UNINITIALIZED_VAR(lzo_uint, m_off, 0);
62        lzo_uint m_len;
63        lzo_uint dindex;
64next:
65        if __lzo_unlikely(ip >= ip_end)
66            break;
67        DINDEX1(dindex,ip);
68        GINDEX(m_pos,m_off,dict,dindex,in);
69        if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
70            goto literal;
71#if 1
72        if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
73            goto try_match;
74        DINDEX2(dindex,ip);
75#endif
76        GINDEX(m_pos,m_off,dict,dindex,in);
77        if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
78            goto literal;
79        if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
80            goto try_match;
81        goto literal;
82
83try_match:
84#if (LZO_OPT_UNALIGNED32)
85        if (UA_GET_NE32(m_pos) != UA_GET_NE32(ip))
86#else
87        if (m_pos[0] != ip[0] || m_pos[1] != ip[1] || m_pos[2] != ip[2] || m_pos[3] != ip[3])
88#endif
89        {
90            /* a literal */
91literal:
92            UPDATE_I(dict,0,dindex,ip,in);
93            ip += 1 + ((ip - ii) >> 5);
94            continue;
95        }
96/*match:*/
97        UPDATE_I(dict,0,dindex,ip,in);
98#else
99        lzo_uint m_off;
100        lzo_uint m_len;
101        {
102        lzo_uint32_t dv;
103        lzo_uint dindex;
104literal:
105        ip += 1 + ((ip - ii) >> 5);
106next:
107        if __lzo_unlikely(ip >= ip_end)
108            break;
109        dv = UA_GET_LE32(ip);
110        dindex = DINDEX(dv,ip);
111        GINDEX(m_off,m_pos,in+dict,dindex,in);
112        UPDATE_I(dict,0,dindex,ip,in);
113        if __lzo_unlikely(dv != UA_GET_LE32(m_pos))
114            goto literal;
115        }
116#endif
117
118    /* a match */
119
120        ii -= ti; ti = 0;
121        {
122        lzo_uint t = pd(ip,ii);
123        if (t != 0)
124        {
125            if (t <= 3)
126            {
127                op[-2] = LZO_BYTE(op[-2] | t);
128#if (LZO_OPT_UNALIGNED32)
129                UA_COPY4(op, ii);
130                op += t;
131#else
132                { do *op++ = *ii++; while (--t > 0); }
133#endif
134            }
135#if (LZO_OPT_UNALIGNED32) || (LZO_OPT_UNALIGNED64)
136            else if (t <= 16)
137            {
138                *op++ = LZO_BYTE(t - 3);
139                UA_COPY8(op, ii);
140                UA_COPY8(op+8, ii+8);
141                op += t;
142            }
143#endif
144            else
145            {
146                if (t <= 18)
147                    *op++ = LZO_BYTE(t - 3);
148                else
149                {
150                    lzo_uint tt = t - 18;
151                    *op++ = 0;
152                    while __lzo_unlikely(tt > 255)
153                    {
154                        tt -= 255;
155                        UA_SET1(op, 0);
156                        op++;
157                    }
158                    assert(tt > 0);
159                    *op++ = LZO_BYTE(tt);
160                }
161#if (LZO_OPT_UNALIGNED32) || (LZO_OPT_UNALIGNED64)
162                do {
163                    UA_COPY8(op, ii);
164                    UA_COPY8(op+8, ii+8);
165                    op += 16; ii += 16; t -= 16;
166                } while (t >= 16); if (t > 0)
167#endif
168                { do *op++ = *ii++; while (--t > 0); }
169            }
170        }
171        }
172        m_len = 4;
173        {
174#if (LZO_OPT_UNALIGNED64)
175        lzo_uint64_t v;
176        v = UA_GET_NE64(ip + m_len) ^ UA_GET_NE64(m_pos + m_len);
177        if __lzo_unlikely(v == 0) {
178            do {
179                m_len += 8;
180                v = UA_GET_NE64(ip + m_len) ^ UA_GET_NE64(m_pos + m_len);
181                if __lzo_unlikely(ip + m_len >= ip_end)
182                    goto m_len_done;
183            } while (v == 0);
184        }
185#if (LZO_ABI_BIG_ENDIAN) && defined(lzo_bitops_ctlz64)
186        m_len += lzo_bitops_ctlz64(v) / CHAR_BIT;
187#elif (LZO_ABI_BIG_ENDIAN)
188        if ((v >> (64 - CHAR_BIT)) == 0) do {
189            v <<= CHAR_BIT;
190            m_len += 1;
191        } while ((v >> (64 - CHAR_BIT)) == 0);
192#elif (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_cttz64)
193        m_len += lzo_bitops_cttz64(v) / CHAR_BIT;
194#elif (LZO_ABI_LITTLE_ENDIAN)
195        if ((v & UCHAR_MAX) == 0) do {
196            v >>= CHAR_BIT;
197            m_len += 1;
198        } while ((v & UCHAR_MAX) == 0);
199#else
200        if (ip[m_len] == m_pos[m_len]) do {
201            m_len += 1;
202        } while (ip[m_len] == m_pos[m_len]);
203#endif
204#elif (LZO_OPT_UNALIGNED32)
205        lzo_uint32_t v;
206        v = UA_GET_NE32(ip + m_len) ^ UA_GET_NE32(m_pos + m_len);
207        if __lzo_unlikely(v == 0) {
208            do {
209                m_len += 4;
210                v = UA_GET_NE32(ip + m_len) ^ UA_GET_NE32(m_pos + m_len);
211                if (v != 0)
212                    break;
213                m_len += 4;
214                v = UA_GET_NE32(ip + m_len) ^ UA_GET_NE32(m_pos + m_len);
215                if __lzo_unlikely(ip + m_len >= ip_end)
216                    goto m_len_done;
217            } while (v == 0);
218        }
219#if (LZO_ABI_BIG_ENDIAN) && defined(lzo_bitops_ctlz32)
220        m_len += lzo_bitops_ctlz32(v) / CHAR_BIT;
221#elif (LZO_ABI_BIG_ENDIAN)
222        if ((v >> (32 - CHAR_BIT)) == 0) do {
223            v <<= CHAR_BIT;
224            m_len += 1;
225        } while ((v >> (32 - CHAR_BIT)) == 0);
226#elif (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_cttz32)
227        m_len += lzo_bitops_cttz32(v) / CHAR_BIT;
228#elif (LZO_ABI_LITTLE_ENDIAN)
229        if ((v & UCHAR_MAX) == 0) do {
230            v >>= CHAR_BIT;
231            m_len += 1;
232        } while ((v & UCHAR_MAX) == 0);
233#else
234        if (ip[m_len] == m_pos[m_len]) do {
235            m_len += 1;
236        } while (ip[m_len] == m_pos[m_len]);
237#endif
238#else
239        if __lzo_unlikely(ip[m_len] == m_pos[m_len]) {
240            do {
241                m_len += 1;
242                if (ip[m_len] != m_pos[m_len])
243                    break;
244                m_len += 1;
245                if (ip[m_len] != m_pos[m_len])
246                    break;
247                m_len += 1;
248                if (ip[m_len] != m_pos[m_len])
249                    break;
250                m_len += 1;
251                if (ip[m_len] != m_pos[m_len])
252                    break;
253                m_len += 1;
254                if (ip[m_len] != m_pos[m_len])
255                    break;
256                m_len += 1;
257                if (ip[m_len] != m_pos[m_len])
258                    break;
259                m_len += 1;
260                if (ip[m_len] != m_pos[m_len])
261                    break;
262                m_len += 1;
263                if __lzo_unlikely(ip + m_len >= ip_end)
264                    goto m_len_done;
265            } while (ip[m_len] == m_pos[m_len]);
266        }
267#endif
268        }
269m_len_done:
270        m_off = pd(ip,m_pos);
271        ip += m_len;
272        ii = ip;
273        if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET)
274        {
275            m_off -= 1;
276#if defined(LZO1X)
277            *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2));
278            *op++ = LZO_BYTE(m_off >> 3);
279#elif defined(LZO1Y)
280            *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2));
281            *op++ = LZO_BYTE(m_off >> 2);
282#endif
283        }
284        else if (m_off <= M3_MAX_OFFSET)
285        {
286            m_off -= 1;
287            if (m_len <= M3_MAX_LEN)
288                *op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
289            else
290            {
291                m_len -= M3_MAX_LEN;
292                *op++ = M3_MARKER | 0;
293                while __lzo_unlikely(m_len > 255)
294                {
295                    m_len -= 255;
296                    UA_SET1(op, 0);
297                    op++;
298                }
299                *op++ = LZO_BYTE(m_len);
300            }
301            *op++ = LZO_BYTE(m_off << 2);
302            *op++ = LZO_BYTE(m_off >> 6);
303        }
304        else
305        {
306            m_off -= 0x4000;
307            if (m_len <= M4_MAX_LEN)
308                *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8) | (m_len - 2));
309            else
310            {
311                m_len -= M4_MAX_LEN;
312                *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8));
313                while __lzo_unlikely(m_len > 255)
314                {
315                    m_len -= 255;
316                    UA_SET1(op, 0);
317                    op++;
318                }
319                *op++ = LZO_BYTE(m_len);
320            }
321            *op++ = LZO_BYTE(m_off << 2);
322            *op++ = LZO_BYTE(m_off >> 6);
323        }
324        goto next;
325    }
326
327    *out_len = pd(op, out);
328    return pd(in_end,ii-ti);
329}
330
331
332/***********************************************************************
333// public entry point
334************************************************************************/
335
336LZO_PUBLIC(int)
337DO_COMPRESS      ( const lzo_bytep in , lzo_uint  in_len,
338                         lzo_bytep out, lzo_uintp out_len,
339                         lzo_voidp wrkmem )
340{
341    const lzo_bytep ip = in;
342    lzo_bytep op = out;
343    lzo_uint l = in_len;
344    lzo_uint t = 0;
345
346    while (l > 20)
347    {
348        lzo_uint ll = l;
349        lzo_uintptr_t ll_end;
350#if 0 || (LZO_DETERMINISTIC)
351        ll = LZO_MIN(ll, 49152);
352#endif
353        ll_end = (lzo_uintptr_t)ip + ll;
354        if ((ll_end + ((t + ll) >> 5)) <= ll_end || (const lzo_bytep)(ll_end + ((t + ll) >> 5)) <= ip + ll)
355            break;
356#if (LZO_DETERMINISTIC)
357        lzo_memset(wrkmem, 0, ((lzo_uint)1 << D_BITS) * sizeof(lzo_dict_t));
358#endif
359        t = do_compress(ip,ll,op,out_len,t,wrkmem);
360        ip += ll;
361        op += *out_len;
362        l  -= ll;
363    }
364    t += l;
365
366    if (t > 0)
367    {
368        const lzo_bytep ii = in + in_len - t;
369
370        if (op == out && t <= 238)
371            *op++ = LZO_BYTE(17 + t);
372        else if (t <= 3)
373            op[-2] = LZO_BYTE(op[-2] | t);
374        else if (t <= 18)
375            *op++ = LZO_BYTE(t - 3);
376        else
377        {
378            lzo_uint tt = t - 18;
379
380            *op++ = 0;
381            while (tt > 255)
382            {
383                tt -= 255;
384                UA_SET1(op, 0);
385                op++;
386            }
387            assert(tt > 0);
388            *op++ = LZO_BYTE(tt);
389        }
390        UA_COPYN(op, ii, t);
391        op += t;
392    }
393
394    *op++ = M4_MARKER | 1;
395    *op++ = 0;
396    *op++ = 0;
397
398    *out_len = pd(op, out);
399    return LZO_E_OK;
400}
401
402
403/*
404vi:ts=4:et
405*/
406