1/* lzo1x_oo.ch -- LZO1X compressed data optimizer 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#define TEST_IP (ip < ip_end) 30#define TEST_OP (op <= op_end) 31#define TEST_IP_AND_TEST_OP (TEST_IP && TEST_OP) 32 33#define NO_LIT LZO_UINT_MAX 34 35 36/*********************************************************************** 37// 38************************************************************************/ 39 40static void copy2(lzo_bytep ip, const lzo_bytep m_pos, lzo_uint off) 41{ 42 assert(off > 0); 43 ip[0] = m_pos[0]; 44 if (off == 1) 45 ip[1] = m_pos[0]; 46 else 47 ip[1] = m_pos[1]; 48} 49 50 51static void copy3(lzo_bytep ip, const lzo_bytep m_pos, lzo_uint off) 52{ 53 assert(off > 0); 54 ip[0] = m_pos[0]; 55 if (off == 1) 56 { 57 ip[2] = ip[1] = m_pos[0]; 58 } 59 else if (off == 2) 60 { 61 ip[1] = m_pos[1]; 62 ip[2] = m_pos[0]; 63 } 64 else 65 { 66 ip[1] = m_pos[1]; 67 ip[2] = m_pos[2]; 68 } 69} 70 71 72/*********************************************************************** 73// optimize a block of data. 74************************************************************************/ 75 76LZO_PUBLIC(int) 77DO_OPTIMIZE ( lzo_bytep in , lzo_uint in_len, 78 lzo_bytep out, lzo_uintp out_len, 79 lzo_voidp wrkmem ) 80{ 81 lzo_bytep op; 82 lzo_bytep ip; 83 lzo_uint t; 84 lzo_bytep m_pos; 85 lzo_bytep const ip_end = in + in_len; 86 lzo_bytep const op_end = out + *out_len; 87 lzo_bytep litp = NULL; 88 lzo_uint lit = 0; 89 lzo_uint next_lit = NO_LIT; 90 lzo_uint nl; 91 unsigned long o_m1_a = 0, o_m1_b = 0, o_m2 = 0, o_m3_a = 0, o_m3_b = 0; 92 93 LZO_UNUSED(wrkmem); 94 95 *out_len = 0; 96 97 op = out; 98 ip = in; 99 100 assert(in_len >= 3); 101 if (*ip > 17) 102 { 103 t = *ip++ - 17; 104 if (t < 4) 105 goto match_next; 106 goto first_literal_run; 107 } 108 assert(*ip < 16 || (*ip == 17 && in_len == 3)); 109 110 while (TEST_IP_AND_TEST_OP) 111 { 112 t = *ip++; 113 if (t >= 16) 114 goto match; 115 /* a literal run */ 116 litp = ip - 1; 117 if (t == 0) 118 { 119 t = 15; 120 while (*ip == 0) 121 t += 255, ip++; 122 t += *ip++; 123 } 124 lit = t + 3; 125 /* copy literals */ 126copy_literal_run: 127 *op++ = *ip++; *op++ = *ip++; *op++ = *ip++; 128first_literal_run: 129 do *op++ = *ip++; while (--t > 0); 130 131 132 t = *ip++; 133 134 if (t >= 16) 135 goto match; 136#if defined(LZO1X) 137 m_pos = op - 1 - 0x800; 138#elif defined(LZO1Y) 139 m_pos = op - 1 - 0x400; 140#endif 141 m_pos -= t >> 2; 142 m_pos -= *ip++ << 2; 143 *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos++; 144 lit = 0; 145 goto match_done; 146 147 148 /* handle matches */ 149 do { 150 if (t < 16) /* a M1 match */ 151 { 152 m_pos = op - 1; 153 m_pos -= t >> 2; 154 m_pos -= *ip++ << 2; 155 156 if (litp == NULL) 157 goto copy_m1; 158 159 /* assert that there was a match just before */ 160 assert(lit >= 1 && lit <= 3); 161 assert(litp == ip - 2 - lit - 2); 162 assert((lzo_uint)(*litp & 3) == lit); 163 nl = ip[-2] & 3; 164 /* test if a match follows */ 165 if (nl == 0 && lit == 1 && ip[0] >= 16) 166 { 167 next_lit = nl; 168 /* adjust length of previous short run */ 169 lit += 2; 170 *litp = LZO_BYTE((*litp & ~3) | lit); 171 /* copy over the 2 literals that replace the match */ 172 copy2(ip-2,m_pos,pd(op,m_pos)); 173 o_m1_a++; 174 } 175 /* test if a literal run follows */ 176 else if (nl == 0 && ip[0] < 16 && ip[0] != 0 && 177 (lit + 2 + ip[0] < 16)) 178 { 179 t = *ip++; 180 /* remove short run */ 181 *litp &= ~3; 182 /* copy over the 2 literals that replace the match */ 183 copy2(ip-3+1,m_pos,pd(op,m_pos)); 184 /* move literals 1 byte ahead */ 185 litp += 2; 186 if (lit > 0) 187 lzo_memmove(litp+1,litp,lit); 188 /* insert new length of long literal run */ 189 lit += 2 + t + 3; assert(lit <= 18); 190 *litp = LZO_BYTE(lit - 3); 191 192 o_m1_b++; 193 *op++ = *m_pos++; *op++ = *m_pos++; 194 goto copy_literal_run; 195 } 196copy_m1: 197 *op++ = *m_pos++; *op++ = *m_pos++; 198 } 199 else 200 { 201match: 202 if (t >= 64) /* a M2 match */ 203 { 204 m_pos = op - 1; 205#if defined(LZO1X) 206 m_pos -= (t >> 2) & 7; 207 m_pos -= *ip++ << 3; 208 t = (t >> 5) - 1; 209#elif defined(LZO1Y) 210 m_pos -= (t >> 2) & 3; 211 m_pos -= *ip++ << 2; 212 t = (t >> 4) - 3; 213#endif 214 if (litp == NULL) 215 goto copy_m; 216 217 nl = ip[-2] & 3; 218 /* test if in beetween two long literal runs */ 219 if (t == 1 && lit > 3 && nl == 0 && 220 ip[0] < 16 && ip[0] != 0 && (lit + 3 + ip[0] < 16)) 221 { 222 assert(*litp == lit - 3); 223 t = *ip++; 224 /* copy over the 3 literals that replace the match */ 225 copy3(ip-1-2,m_pos,pd(op,m_pos)); 226 /* set new length of previous literal run */ 227 lit += 3 + t + 3; assert(lit <= 18); 228 *litp = LZO_BYTE(lit - 3); 229 o_m2++; 230 *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos++; 231 goto copy_literal_run; 232 } 233 } 234 else 235 { 236 if (t >= 32) /* a M3 match */ 237 { 238 t &= 31; 239 if (t == 0) 240 { 241 t = 31; 242 while (*ip == 0) 243 t += 255, ip++; 244 t += *ip++; 245 } 246 m_pos = op - 1; 247 m_pos -= *ip++ >> 2; 248 m_pos -= *ip++ << 6; 249 } 250 else /* a M4 match */ 251 { 252 m_pos = op; 253 m_pos -= (t & 8) << 11; 254 t &= 7; 255 if (t == 0) 256 { 257 t = 7; 258 while (*ip == 0) 259 t += 255, ip++; 260 t += *ip++; 261 } 262 m_pos -= *ip++ >> 2; 263 m_pos -= *ip++ << 6; 264 if (m_pos == op) 265 goto eof_found; 266 m_pos -= 0x4000; 267 } 268 if (litp == NULL) 269 goto copy_m; 270 271 nl = ip[-2] & 3; 272 /* test if in beetween two matches */ 273 if (t == 1 && lit == 0 && nl == 0 && ip[0] >= 16) 274 { 275 assert(litp == ip - 3 - lit - 2); 276 assert((lzo_uint)(*litp & 3) == lit); 277 next_lit = nl; 278 /* make a previous short run */ 279 lit += 3; 280 *litp = LZO_BYTE((*litp & ~3) | lit); 281 /* copy over the 3 literals that replace the match */ 282 copy3(ip-3,m_pos,pd(op,m_pos)); 283 o_m3_a++; 284 } 285 /* test if a literal run follows */ 286 else if (t == 1 && lit <= 3 && nl == 0 && 287 ip[0] < 16 && ip[0] != 0 && (lit + 3 + ip[0] < 16)) 288 { 289 assert(litp == ip - 3 - lit - 2); 290 assert((lzo_uint)(*litp & 3) == lit); 291 t = *ip++; 292 /* remove short run */ 293 *litp &= ~3; 294 /* copy over the 3 literals that replace the match */ 295 copy3(ip-4+1,m_pos,pd(op,m_pos)); 296 /* move literals 1 byte ahead */ 297 litp += 2; 298 if (lit > 0) 299 lzo_memmove(litp+1,litp,lit); 300 /* insert new length of long literal run */ 301 lit += 3 + t + 3; assert(lit <= 18); 302 *litp = LZO_BYTE(lit - 3); 303 304 o_m3_b++; 305 *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos++; 306 goto copy_literal_run; 307 } 308 } 309copy_m: 310 *op++ = *m_pos++; *op++ = *m_pos++; 311 do *op++ = *m_pos++; while (--t > 0); 312 } 313 314match_done: 315 if (next_lit == NO_LIT) 316 { 317 t = ip[-2] & 3; 318 lit = t; 319 litp = ip - 2; 320 } 321 else 322 t = next_lit; 323 assert(t <= 3); 324 next_lit = NO_LIT; 325 if (t == 0) 326 break; 327 /* copy literals */ 328match_next: 329 do *op++ = *ip++; while (--t > 0); 330 t = *ip++; 331 } while (TEST_IP_AND_TEST_OP); 332 } 333 334 /* no EOF code was found */ 335 *out_len = pd(op, out); 336 return LZO_E_EOF_NOT_FOUND; 337 338eof_found: 339 assert(t == 1); 340#if 0 341 printf("optimize: %5lu %5lu %5lu %5lu %5lu\n", 342 o_m1_a, o_m1_b, o_m2, o_m3_a, o_m3_b); 343#endif 344 LZO_UNUSED(o_m1_a); LZO_UNUSED(o_m1_b); LZO_UNUSED(o_m2); 345 LZO_UNUSED(o_m3_a); LZO_UNUSED(o_m3_b); 346 *out_len = pd(op, out); 347 return (ip == ip_end ? LZO_E_OK : 348 (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); 349} 350 351 352/* 353vi:ts=4:et 354*/ 355 356