/* lzo1x_c.ch -- implementation of the LZO1[XY]-1 compression algorithm 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 http://www.oberhumer.com/opensource/lzo/ */ #if 1 && defined(DO_COMPRESS) && !defined(do_compress) /* choose a unique name to better help PGO optimizations */ # define do_compress LZO_PP_ECONCAT2(DO_COMPRESS,_core) #endif /*********************************************************************** // compress a block of data. ************************************************************************/ static __lzo_noinline lzo_uint do_compress ( const lzo_bytep in , lzo_uint in_len, lzo_bytep out, lzo_uintp out_len, lzo_uint ti, lzo_voidp wrkmem) { const lzo_bytep ip; lzo_bytep op; const lzo_bytep const in_end = in + in_len; const lzo_bytep const ip_end = in + in_len - 20; const lzo_bytep ii; lzo_dict_p const dict = (lzo_dict_p) wrkmem; op = out; ip = in; ii = ip; ip += ti < 4 ? 4 - ti : 0; for (;;) { const lzo_bytep m_pos; #if !(LZO_DETERMINISTIC) LZO_DEFINE_UNINITIALIZED_VAR(lzo_uint, m_off, 0); lzo_uint m_len; lzo_uint dindex; next: if __lzo_unlikely(ip >= ip_end) break; DINDEX1(dindex,ip); GINDEX(m_pos,m_off,dict,dindex,in); if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) goto literal; #if 1 if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) goto try_match; DINDEX2(dindex,ip); #endif GINDEX(m_pos,m_off,dict,dindex,in); if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) goto literal; if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) goto try_match; goto literal; try_match: #if (LZO_OPT_UNALIGNED32) if (UA_GET_NE32(m_pos) != UA_GET_NE32(ip)) #else if (m_pos[0] != ip[0] || m_pos[1] != ip[1] || m_pos[2] != ip[2] || m_pos[3] != ip[3]) #endif { /* a literal */ literal: UPDATE_I(dict,0,dindex,ip,in); ip += 1 + ((ip - ii) >> 5); continue; } /*match:*/ UPDATE_I(dict,0,dindex,ip,in); #else lzo_uint m_off; lzo_uint m_len; { lzo_uint32_t dv; lzo_uint dindex; literal: ip += 1 + ((ip - ii) >> 5); next: if __lzo_unlikely(ip >= ip_end) break; dv = UA_GET_LE32(ip); dindex = DINDEX(dv,ip); GINDEX(m_off,m_pos,in+dict,dindex,in); UPDATE_I(dict,0,dindex,ip,in); if __lzo_unlikely(dv != UA_GET_LE32(m_pos)) goto literal; } #endif /* a match */ ii -= ti; ti = 0; { lzo_uint t = pd(ip,ii); if (t != 0) { if (t <= 3) { op[-2] = LZO_BYTE(op[-2] | t); #if (LZO_OPT_UNALIGNED32) UA_COPY4(op, ii); op += t; #else { do *op++ = *ii++; while (--t > 0); } #endif } #if (LZO_OPT_UNALIGNED32) || (LZO_OPT_UNALIGNED64) else if (t <= 16) { *op++ = LZO_BYTE(t - 3); UA_COPY8(op, ii); UA_COPY8(op+8, ii+8); op += t; } #endif else { if (t <= 18) *op++ = LZO_BYTE(t - 3); else { lzo_uint tt = t - 18; *op++ = 0; while __lzo_unlikely(tt > 255) { tt -= 255; UA_SET1(op, 0); op++; } assert(tt > 0); *op++ = LZO_BYTE(tt); } #if (LZO_OPT_UNALIGNED32) || (LZO_OPT_UNALIGNED64) do { UA_COPY8(op, ii); UA_COPY8(op+8, ii+8); op += 16; ii += 16; t -= 16; } while (t >= 16); if (t > 0) #endif { do *op++ = *ii++; while (--t > 0); } } } } m_len = 4; { #if (LZO_OPT_UNALIGNED64) lzo_uint64_t v; v = UA_GET_NE64(ip + m_len) ^ UA_GET_NE64(m_pos + m_len); if __lzo_unlikely(v == 0) { do { m_len += 8; v = UA_GET_NE64(ip + m_len) ^ UA_GET_NE64(m_pos + m_len); if __lzo_unlikely(ip + m_len >= ip_end) goto m_len_done; } while (v == 0); } #if (LZO_ABI_BIG_ENDIAN) && defined(lzo_bitops_ctlz64) m_len += lzo_bitops_ctlz64(v) / CHAR_BIT; #elif (LZO_ABI_BIG_ENDIAN) if ((v >> (64 - CHAR_BIT)) == 0) do { v <<= CHAR_BIT; m_len += 1; } while ((v >> (64 - CHAR_BIT)) == 0); #elif (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_cttz64) m_len += lzo_bitops_cttz64(v) / CHAR_BIT; #elif (LZO_ABI_LITTLE_ENDIAN) if ((v & UCHAR_MAX) == 0) do { v >>= CHAR_BIT; m_len += 1; } while ((v & UCHAR_MAX) == 0); #else if (ip[m_len] == m_pos[m_len]) do { m_len += 1; } while (ip[m_len] == m_pos[m_len]); #endif #elif (LZO_OPT_UNALIGNED32) lzo_uint32_t v; v = UA_GET_NE32(ip + m_len) ^ UA_GET_NE32(m_pos + m_len); if __lzo_unlikely(v == 0) { do { m_len += 4; v = UA_GET_NE32(ip + m_len) ^ UA_GET_NE32(m_pos + m_len); if (v != 0) break; m_len += 4; v = UA_GET_NE32(ip + m_len) ^ UA_GET_NE32(m_pos + m_len); if __lzo_unlikely(ip + m_len >= ip_end) goto m_len_done; } while (v == 0); } #if (LZO_ABI_BIG_ENDIAN) && defined(lzo_bitops_ctlz32) m_len += lzo_bitops_ctlz32(v) / CHAR_BIT; #elif (LZO_ABI_BIG_ENDIAN) if ((v >> (32 - CHAR_BIT)) == 0) do { v <<= CHAR_BIT; m_len += 1; } while ((v >> (32 - CHAR_BIT)) == 0); #elif (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_cttz32) m_len += lzo_bitops_cttz32(v) / CHAR_BIT; #elif (LZO_ABI_LITTLE_ENDIAN) if ((v & UCHAR_MAX) == 0) do { v >>= CHAR_BIT; m_len += 1; } while ((v & UCHAR_MAX) == 0); #else if (ip[m_len] == m_pos[m_len]) do { m_len += 1; } while (ip[m_len] == m_pos[m_len]); #endif #else if __lzo_unlikely(ip[m_len] == m_pos[m_len]) { do { m_len += 1; if (ip[m_len] != m_pos[m_len]) break; m_len += 1; if (ip[m_len] != m_pos[m_len]) break; m_len += 1; if (ip[m_len] != m_pos[m_len]) break; m_len += 1; if (ip[m_len] != m_pos[m_len]) break; m_len += 1; if (ip[m_len] != m_pos[m_len]) break; m_len += 1; if (ip[m_len] != m_pos[m_len]) break; m_len += 1; if (ip[m_len] != m_pos[m_len]) break; m_len += 1; if __lzo_unlikely(ip + m_len >= ip_end) goto m_len_done; } while (ip[m_len] == m_pos[m_len]); } #endif } m_len_done: m_off = pd(ip,m_pos); ip += m_len; ii = ip; if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) { m_off -= 1; #if defined(LZO1X) *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2)); *op++ = LZO_BYTE(m_off >> 3); #elif defined(LZO1Y) *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2)); *op++ = LZO_BYTE(m_off >> 2); #endif } else if (m_off <= M3_MAX_OFFSET) { m_off -= 1; if (m_len <= M3_MAX_LEN) *op++ = LZO_BYTE(M3_MARKER | (m_len - 2)); else { m_len -= M3_MAX_LEN; *op++ = M3_MARKER | 0; while __lzo_unlikely(m_len > 255) { m_len -= 255; UA_SET1(op, 0); op++; } *op++ = LZO_BYTE(m_len); } *op++ = LZO_BYTE(m_off << 2); *op++ = LZO_BYTE(m_off >> 6); } else { m_off -= 0x4000; if (m_len <= M4_MAX_LEN) *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8) | (m_len - 2)); else { m_len -= M4_MAX_LEN; *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8)); while __lzo_unlikely(m_len > 255) { m_len -= 255; UA_SET1(op, 0); op++; } *op++ = LZO_BYTE(m_len); } *op++ = LZO_BYTE(m_off << 2); *op++ = LZO_BYTE(m_off >> 6); } goto next; } *out_len = pd(op, out); return pd(in_end,ii-ti); } /*********************************************************************** // public entry point ************************************************************************/ LZO_PUBLIC(int) DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len, lzo_bytep out, lzo_uintp out_len, lzo_voidp wrkmem ) { const lzo_bytep ip = in; lzo_bytep op = out; lzo_uint l = in_len; lzo_uint t = 0; while (l > 20) { lzo_uint ll = l; lzo_uintptr_t ll_end; #if 0 || (LZO_DETERMINISTIC) ll = LZO_MIN(ll, 49152); #endif ll_end = (lzo_uintptr_t)ip + ll; if ((ll_end + ((t + ll) >> 5)) <= ll_end || (const lzo_bytep)(ll_end + ((t + ll) >> 5)) <= ip + ll) break; #if (LZO_DETERMINISTIC) lzo_memset(wrkmem, 0, ((lzo_uint)1 << D_BITS) * sizeof(lzo_dict_t)); #endif t = do_compress(ip,ll,op,out_len,t,wrkmem); ip += ll; op += *out_len; l -= ll; } t += l; if (t > 0) { const lzo_bytep ii = in + in_len - t; if (op == out && t <= 238) *op++ = LZO_BYTE(17 + t); else if (t <= 3) op[-2] = LZO_BYTE(op[-2] | t); else if (t <= 18) *op++ = LZO_BYTE(t - 3); else { lzo_uint tt = t - 18; *op++ = 0; while (tt > 255) { tt -= 255; UA_SET1(op, 0); op++; } assert(tt > 0); *op++ = LZO_BYTE(tt); } UA_COPYN(op, ii, t); op += t; } *op++ = M4_MARKER | 1; *op++ = 0; *op++ = 0; *out_len = pd(op, out); return LZO_E_OK; } /* vi:ts=4:et */