1*64c70b1cSRichard Purdie /* 2*64c70b1cSRichard Purdie * LZO1X Compressor from MiniLZO 3*64c70b1cSRichard Purdie * 4*64c70b1cSRichard Purdie * Copyright (C) 1996-2005 Markus F.X.J. Oberhumer <markus@oberhumer.com> 5*64c70b1cSRichard Purdie * 6*64c70b1cSRichard Purdie * The full LZO package can be found at: 7*64c70b1cSRichard Purdie * http://www.oberhumer.com/opensource/lzo/ 8*64c70b1cSRichard Purdie * 9*64c70b1cSRichard Purdie * Changed for kernel use by: 10*64c70b1cSRichard Purdie * Nitin Gupta <nitingupta910@gmail.com> 11*64c70b1cSRichard Purdie * Richard Purdie <rpurdie@openedhand.com> 12*64c70b1cSRichard Purdie */ 13*64c70b1cSRichard Purdie 14*64c70b1cSRichard Purdie #include <linux/module.h> 15*64c70b1cSRichard Purdie #include <linux/kernel.h> 16*64c70b1cSRichard Purdie #include <linux/lzo.h> 17*64c70b1cSRichard Purdie #include <asm/unaligned.h> 18*64c70b1cSRichard Purdie #include "lzodefs.h" 19*64c70b1cSRichard Purdie 20*64c70b1cSRichard Purdie static noinline size_t 21*64c70b1cSRichard Purdie _lzo1x_1_do_compress(const unsigned char *in, size_t in_len, 22*64c70b1cSRichard Purdie unsigned char *out, size_t *out_len, void *wrkmem) 23*64c70b1cSRichard Purdie { 24*64c70b1cSRichard Purdie const unsigned char * const in_end = in + in_len; 25*64c70b1cSRichard Purdie const unsigned char * const ip_end = in + in_len - M2_MAX_LEN - 5; 26*64c70b1cSRichard Purdie const unsigned char ** const dict = wrkmem; 27*64c70b1cSRichard Purdie const unsigned char *ip = in, *ii = ip; 28*64c70b1cSRichard Purdie const unsigned char *end, *m, *m_pos; 29*64c70b1cSRichard Purdie size_t m_off, m_len, dindex; 30*64c70b1cSRichard Purdie unsigned char *op = out; 31*64c70b1cSRichard Purdie 32*64c70b1cSRichard Purdie ip += 4; 33*64c70b1cSRichard Purdie 34*64c70b1cSRichard Purdie for (;;) { 35*64c70b1cSRichard Purdie dindex = ((0x21 * DX3(ip, 5, 5, 6)) >> 5) & D_MASK; 36*64c70b1cSRichard Purdie m_pos = dict[dindex]; 37*64c70b1cSRichard Purdie 38*64c70b1cSRichard Purdie if (m_pos < in) 39*64c70b1cSRichard Purdie goto literal; 40*64c70b1cSRichard Purdie 41*64c70b1cSRichard Purdie if (ip == m_pos || (ip - m_pos) > M4_MAX_OFFSET) 42*64c70b1cSRichard Purdie goto literal; 43*64c70b1cSRichard Purdie 44*64c70b1cSRichard Purdie m_off = ip - m_pos; 45*64c70b1cSRichard Purdie if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) 46*64c70b1cSRichard Purdie goto try_match; 47*64c70b1cSRichard Purdie 48*64c70b1cSRichard Purdie dindex = (dindex & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f); 49*64c70b1cSRichard Purdie m_pos = dict[dindex]; 50*64c70b1cSRichard Purdie 51*64c70b1cSRichard Purdie if (m_pos < in) 52*64c70b1cSRichard Purdie goto literal; 53*64c70b1cSRichard Purdie 54*64c70b1cSRichard Purdie if (ip == m_pos || (ip - m_pos) > M4_MAX_OFFSET) 55*64c70b1cSRichard Purdie goto literal; 56*64c70b1cSRichard Purdie 57*64c70b1cSRichard Purdie m_off = ip - m_pos; 58*64c70b1cSRichard Purdie if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) 59*64c70b1cSRichard Purdie goto try_match; 60*64c70b1cSRichard Purdie 61*64c70b1cSRichard Purdie goto literal; 62*64c70b1cSRichard Purdie 63*64c70b1cSRichard Purdie try_match: 64*64c70b1cSRichard Purdie if (get_unaligned((const unsigned short *)m_pos) 65*64c70b1cSRichard Purdie == get_unaligned((const unsigned short *)ip)) { 66*64c70b1cSRichard Purdie if (likely(m_pos[2] == ip[2])) 67*64c70b1cSRichard Purdie goto match; 68*64c70b1cSRichard Purdie } 69*64c70b1cSRichard Purdie 70*64c70b1cSRichard Purdie literal: 71*64c70b1cSRichard Purdie dict[dindex] = ip; 72*64c70b1cSRichard Purdie ++ip; 73*64c70b1cSRichard Purdie if (unlikely(ip >= ip_end)) 74*64c70b1cSRichard Purdie break; 75*64c70b1cSRichard Purdie continue; 76*64c70b1cSRichard Purdie 77*64c70b1cSRichard Purdie match: 78*64c70b1cSRichard Purdie dict[dindex] = ip; 79*64c70b1cSRichard Purdie if (ip != ii) { 80*64c70b1cSRichard Purdie size_t t = ip - ii; 81*64c70b1cSRichard Purdie 82*64c70b1cSRichard Purdie if (t <= 3) { 83*64c70b1cSRichard Purdie op[-2] |= t; 84*64c70b1cSRichard Purdie } else if (t <= 18) { 85*64c70b1cSRichard Purdie *op++ = (t - 3); 86*64c70b1cSRichard Purdie } else { 87*64c70b1cSRichard Purdie size_t tt = t - 18; 88*64c70b1cSRichard Purdie 89*64c70b1cSRichard Purdie *op++ = 0; 90*64c70b1cSRichard Purdie while (tt > 255) { 91*64c70b1cSRichard Purdie tt -= 255; 92*64c70b1cSRichard Purdie *op++ = 0; 93*64c70b1cSRichard Purdie } 94*64c70b1cSRichard Purdie *op++ = tt; 95*64c70b1cSRichard Purdie } 96*64c70b1cSRichard Purdie do { 97*64c70b1cSRichard Purdie *op++ = *ii++; 98*64c70b1cSRichard Purdie } while (--t > 0); 99*64c70b1cSRichard Purdie } 100*64c70b1cSRichard Purdie 101*64c70b1cSRichard Purdie ip += 3; 102*64c70b1cSRichard Purdie if (m_pos[3] != *ip++ || m_pos[4] != *ip++ 103*64c70b1cSRichard Purdie || m_pos[5] != *ip++ || m_pos[6] != *ip++ 104*64c70b1cSRichard Purdie || m_pos[7] != *ip++ || m_pos[8] != *ip++) { 105*64c70b1cSRichard Purdie --ip; 106*64c70b1cSRichard Purdie m_len = ip - ii; 107*64c70b1cSRichard Purdie 108*64c70b1cSRichard Purdie if (m_off <= M2_MAX_OFFSET) { 109*64c70b1cSRichard Purdie m_off -= 1; 110*64c70b1cSRichard Purdie *op++ = (((m_len - 1) << 5) 111*64c70b1cSRichard Purdie | ((m_off & 7) << 2)); 112*64c70b1cSRichard Purdie *op++ = (m_off >> 3); 113*64c70b1cSRichard Purdie } else if (m_off <= M3_MAX_OFFSET) { 114*64c70b1cSRichard Purdie m_off -= 1; 115*64c70b1cSRichard Purdie *op++ = (M3_MARKER | (m_len - 2)); 116*64c70b1cSRichard Purdie goto m3_m4_offset; 117*64c70b1cSRichard Purdie } else { 118*64c70b1cSRichard Purdie m_off -= 0x4000; 119*64c70b1cSRichard Purdie 120*64c70b1cSRichard Purdie *op++ = (M4_MARKER | ((m_off & 0x4000) >> 11) 121*64c70b1cSRichard Purdie | (m_len - 2)); 122*64c70b1cSRichard Purdie goto m3_m4_offset; 123*64c70b1cSRichard Purdie } 124*64c70b1cSRichard Purdie } else { 125*64c70b1cSRichard Purdie end = in_end; 126*64c70b1cSRichard Purdie m = m_pos + M2_MAX_LEN + 1; 127*64c70b1cSRichard Purdie 128*64c70b1cSRichard Purdie while (ip < end && *m == *ip) { 129*64c70b1cSRichard Purdie m++; 130*64c70b1cSRichard Purdie ip++; 131*64c70b1cSRichard Purdie } 132*64c70b1cSRichard Purdie m_len = ip - ii; 133*64c70b1cSRichard Purdie 134*64c70b1cSRichard Purdie if (m_off <= M3_MAX_OFFSET) { 135*64c70b1cSRichard Purdie m_off -= 1; 136*64c70b1cSRichard Purdie if (m_len <= 33) { 137*64c70b1cSRichard Purdie *op++ = (M3_MARKER | (m_len - 2)); 138*64c70b1cSRichard Purdie } else { 139*64c70b1cSRichard Purdie m_len -= 33; 140*64c70b1cSRichard Purdie *op++ = M3_MARKER | 0; 141*64c70b1cSRichard Purdie goto m3_m4_len; 142*64c70b1cSRichard Purdie } 143*64c70b1cSRichard Purdie } else { 144*64c70b1cSRichard Purdie m_off -= 0x4000; 145*64c70b1cSRichard Purdie if (m_len <= M4_MAX_LEN) { 146*64c70b1cSRichard Purdie *op++ = (M4_MARKER 147*64c70b1cSRichard Purdie | ((m_off & 0x4000) >> 11) 148*64c70b1cSRichard Purdie | (m_len - 2)); 149*64c70b1cSRichard Purdie } else { 150*64c70b1cSRichard Purdie m_len -= M4_MAX_LEN; 151*64c70b1cSRichard Purdie *op++ = (M4_MARKER 152*64c70b1cSRichard Purdie | ((m_off & 0x4000) >> 11)); 153*64c70b1cSRichard Purdie m3_m4_len: 154*64c70b1cSRichard Purdie while (m_len > 255) { 155*64c70b1cSRichard Purdie m_len -= 255; 156*64c70b1cSRichard Purdie *op++ = 0; 157*64c70b1cSRichard Purdie } 158*64c70b1cSRichard Purdie 159*64c70b1cSRichard Purdie *op++ = (m_len); 160*64c70b1cSRichard Purdie } 161*64c70b1cSRichard Purdie } 162*64c70b1cSRichard Purdie m3_m4_offset: 163*64c70b1cSRichard Purdie *op++ = ((m_off & 63) << 2); 164*64c70b1cSRichard Purdie *op++ = (m_off >> 6); 165*64c70b1cSRichard Purdie } 166*64c70b1cSRichard Purdie 167*64c70b1cSRichard Purdie ii = ip; 168*64c70b1cSRichard Purdie if (unlikely(ip >= ip_end)) 169*64c70b1cSRichard Purdie break; 170*64c70b1cSRichard Purdie } 171*64c70b1cSRichard Purdie 172*64c70b1cSRichard Purdie *out_len = op - out; 173*64c70b1cSRichard Purdie return in_end - ii; 174*64c70b1cSRichard Purdie } 175*64c70b1cSRichard Purdie 176*64c70b1cSRichard Purdie int lzo1x_1_compress(const unsigned char *in, size_t in_len, unsigned char *out, 177*64c70b1cSRichard Purdie size_t *out_len, void *wrkmem) 178*64c70b1cSRichard Purdie { 179*64c70b1cSRichard Purdie const unsigned char *ii; 180*64c70b1cSRichard Purdie unsigned char *op = out; 181*64c70b1cSRichard Purdie size_t t; 182*64c70b1cSRichard Purdie 183*64c70b1cSRichard Purdie if (unlikely(in_len <= M2_MAX_LEN + 5)) { 184*64c70b1cSRichard Purdie t = in_len; 185*64c70b1cSRichard Purdie } else { 186*64c70b1cSRichard Purdie t = _lzo1x_1_do_compress(in, in_len, op, out_len, wrkmem); 187*64c70b1cSRichard Purdie op += *out_len; 188*64c70b1cSRichard Purdie } 189*64c70b1cSRichard Purdie 190*64c70b1cSRichard Purdie if (t > 0) { 191*64c70b1cSRichard Purdie ii = in + in_len - t; 192*64c70b1cSRichard Purdie 193*64c70b1cSRichard Purdie if (op == out && t <= 238) { 194*64c70b1cSRichard Purdie *op++ = (17 + t); 195*64c70b1cSRichard Purdie } else if (t <= 3) { 196*64c70b1cSRichard Purdie op[-2] |= t; 197*64c70b1cSRichard Purdie } else if (t <= 18) { 198*64c70b1cSRichard Purdie *op++ = (t - 3); 199*64c70b1cSRichard Purdie } else { 200*64c70b1cSRichard Purdie size_t tt = t - 18; 201*64c70b1cSRichard Purdie 202*64c70b1cSRichard Purdie *op++ = 0; 203*64c70b1cSRichard Purdie while (tt > 255) { 204*64c70b1cSRichard Purdie tt -= 255; 205*64c70b1cSRichard Purdie *op++ = 0; 206*64c70b1cSRichard Purdie } 207*64c70b1cSRichard Purdie 208*64c70b1cSRichard Purdie *op++ = tt; 209*64c70b1cSRichard Purdie } 210*64c70b1cSRichard Purdie do { 211*64c70b1cSRichard Purdie *op++ = *ii++; 212*64c70b1cSRichard Purdie } while (--t > 0); 213*64c70b1cSRichard Purdie } 214*64c70b1cSRichard Purdie 215*64c70b1cSRichard Purdie *op++ = M4_MARKER | 1; 216*64c70b1cSRichard Purdie *op++ = 0; 217*64c70b1cSRichard Purdie *op++ = 0; 218*64c70b1cSRichard Purdie 219*64c70b1cSRichard Purdie *out_len = op - out; 220*64c70b1cSRichard Purdie return LZO_E_OK; 221*64c70b1cSRichard Purdie } 222*64c70b1cSRichard Purdie EXPORT_SYMBOL_GPL(lzo1x_1_compress); 223*64c70b1cSRichard Purdie 224*64c70b1cSRichard Purdie MODULE_LICENSE("GPL"); 225*64c70b1cSRichard Purdie MODULE_DESCRIPTION("LZO1X-1 Compressor"); 226*64c70b1cSRichard Purdie 227