Line | Count | Source |
1 | | /* lzo1.c -- implementation of the LZO1 algorithm |
2 | | |
3 | | This file is part of the LZO real-time data compression library. |
4 | | |
5 | | Copyright (C) 1996-2017 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 | | #include "lzo_conf.h" |
30 | | #include <lzo/lzo1.h> |
31 | | |
32 | | |
33 | | /*********************************************************************** |
34 | | // The next two defines can be changed to customize LZO1. |
35 | | // The default version is LZO1-5/1. |
36 | | ************************************************************************/ |
37 | | |
38 | | /* run bits (3 - 5) - the compressor and the decompressor |
39 | | * must use the same value. */ |
40 | | #if !defined(RBITS) |
41 | 5.95M | # define RBITS 5 |
42 | | #endif |
43 | | |
44 | | /* compression level (1 - 9) - this only affects the compressor. |
45 | | * 1 is fastest, 9 is best compression ratio */ |
46 | | #if !defined(CLEVEL) |
47 | 0 | # define CLEVEL 1 /* fastest by default */ |
48 | | #endif |
49 | | |
50 | | |
51 | | /* check configuration */ |
52 | | #if (RBITS < 3 || RBITS > 5) |
53 | | # error "invalid RBITS" |
54 | | #endif |
55 | | #if (CLEVEL < 1 || CLEVEL > 9) |
56 | | # error "invalid CLEVEL" |
57 | | #endif |
58 | | |
59 | | |
60 | | /*********************************************************************** |
61 | | // You should not have to change anything below this line. |
62 | | ************************************************************************/ |
63 | | |
64 | | /* |
65 | | Format of the marker byte |
66 | | |
67 | | |
68 | | 76543210 |
69 | | -------- |
70 | | 00000000 a long run (a 'R0' run) - there are short and long R0 runs |
71 | | 000rrrrr a short run with len r |
72 | | mmmooooo a short match (len = 2+m, o = offset low bits) |
73 | | 111ooooo a long match (o = offset low bits) |
74 | | */ |
75 | | |
76 | | |
77 | 1.36M | #define RSIZE (1 << RBITS) |
78 | | #define RMASK (RSIZE - 1) |
79 | | |
80 | 4.58M | #define OBITS RBITS /* offset and run-length use same bits */ |
81 | 760k | #define OSIZE (1 << OBITS) |
82 | 760k | #define OMASK (OSIZE - 1) |
83 | | |
84 | 1.80M | #define MBITS (8 - OBITS) |
85 | 1.80M | #define MSIZE (1 << MBITS) |
86 | | #define MMASK (MSIZE - 1) |
87 | | |
88 | | |
89 | | /* sanity checks */ |
90 | | #if (OBITS < 3 || OBITS > 5) |
91 | | # error "invalid OBITS" |
92 | | #endif |
93 | | #if (MBITS < 3 || MBITS > 5) |
94 | | # error "invalid MBITS" |
95 | | #endif |
96 | | |
97 | | |
98 | | /*********************************************************************** |
99 | | // some macros to improve readability |
100 | | ************************************************************************/ |
101 | | |
102 | | /* Minimum len of a match */ |
103 | 1.71M | #define MIN_MATCH 3 |
104 | 1.29M | #define THRESHOLD (MIN_MATCH - 1) |
105 | | |
106 | | /* Minimum len of match coded in 2 bytes */ |
107 | | #define MIN_MATCH_SHORT MIN_MATCH |
108 | | |
109 | | /* Maximum len of match coded in 2 bytes */ |
110 | 1.04M | #define MAX_MATCH_SHORT (THRESHOLD + (MSIZE - 2)) |
111 | | /* MSIZE - 2: 0 is used to indicate runs, |
112 | | * MSIZE-1 is used to indicate a long match */ |
113 | | |
114 | | /* Minimum len of match coded in 3 bytes */ |
115 | 1.04M | #define MIN_MATCH_LONG (MAX_MATCH_SHORT + 1) |
116 | | |
117 | | /* Maximum len of match coded in 3 bytes */ |
118 | 393k | #define MAX_MATCH_LONG (MIN_MATCH_LONG + 255) |
119 | | |
120 | | /* Maximum offset of a match */ |
121 | | #define MAX_OFFSET (1 << (8 + OBITS)) |
122 | | |
123 | | |
124 | | /* |
125 | | |
126 | | RBITS | MBITS MIN THR. MSIZE MAXS MINL MAXL MAXO R0MAX R0FAST |
127 | | ======+=============================================================== |
128 | | 3 | 5 3 2 32 32 33 288 2048 263 256 |
129 | | 4 | 4 3 2 16 16 17 272 4096 271 264 |
130 | | 5 | 3 3 2 8 8 9 264 8192 287 280 |
131 | | |
132 | | */ |
133 | | |
134 | | |
135 | | /*********************************************************************** |
136 | | // internal configuration |
137 | | // all of these affect compression only |
138 | | ************************************************************************/ |
139 | | |
140 | | /* choose the hashing strategy */ |
141 | | #ifndef LZO_HASH |
142 | | #define LZO_HASH LZO_HASH_LZO_INCREMENTAL_A |
143 | | #endif |
144 | 9.82M | #define D_INDEX1(d,p) d = DM(DMUL(0x21,DX2(p,5,5)) >> 5) |
145 | 6.40M | #define D_INDEX2(d,p) d = d ^ D_MASK |
146 | | |
147 | | #define DBITS (8 + RBITS) |
148 | | #include "lzo_dict.h" |
149 | 1.37k | #define DVAL_LEN DVAL_LOOKAHEAD |
150 | | |
151 | | |
152 | | /*********************************************************************** |
153 | | // get algorithm info, return memory required for compression |
154 | | ************************************************************************/ |
155 | | |
156 | | LZO_EXTERN(lzo_uint) lzo1_info ( int *rbits, int *clevel ); |
157 | | |
158 | | LZO_PUBLIC(lzo_uint) |
159 | | lzo1_info ( int *rbits, int *clevel ) |
160 | 0 | { |
161 | 0 | if (rbits) |
162 | 0 | *rbits = RBITS; |
163 | 0 | if (clevel) |
164 | 0 | *clevel = CLEVEL; |
165 | 0 | return D_SIZE * lzo_sizeof(lzo_bytep); |
166 | 0 | } |
167 | | |
168 | | |
169 | | /*********************************************************************** |
170 | | // decode a R0 literal run (a long run) |
171 | | ************************************************************************/ |
172 | | |
173 | 1.36M | #define R0MIN (RSIZE) /* Minimum len of R0 run of literals */ |
174 | 56.5k | #define R0MAX (R0MIN + 255) /* Maximum len of R0 run of literals */ |
175 | 56.5k | #define R0FAST (R0MAX & ~7u) /* R0MAX aligned to 8 byte boundary */ |
176 | | |
177 | | #if (R0MAX - R0FAST != 7) || ((R0FAST & 7) != 0) |
178 | | # error "something went wrong" |
179 | | #endif |
180 | | |
181 | | /* 7 special codes from R0FAST+1 .. R0MAX |
182 | | * these codes mean long R0 runs with lengths |
183 | | * 512, 1024, 2048, 4096, 8192, 16384, 32768 */ |
184 | | |
185 | | |
186 | | /*********************************************************************** |
187 | | // LZO1 decompress a block of data. |
188 | | // |
189 | | // Could be easily translated into assembly code. |
190 | | ************************************************************************/ |
191 | | |
192 | | LZO_PUBLIC(int) |
193 | | lzo1_decompress ( const lzo_bytep in , lzo_uint in_len, |
194 | | lzo_bytep out, lzo_uintp out_len, |
195 | | lzo_voidp wrkmem ) |
196 | 682 | { |
197 | 682 | lzo_bytep op; |
198 | 682 | const lzo_bytep ip; |
199 | 682 | const lzo_bytep const ip_end = in + in_len; |
200 | 682 | lzo_uint t; |
201 | | |
202 | 682 | LZO_UNUSED(wrkmem); |
203 | | |
204 | 682 | op = out; |
205 | 682 | ip = in; |
206 | 1.09M | while (ip < ip_end) |
207 | 1.09M | { |
208 | 1.09M | t = *ip++; /* get marker */ |
209 | | |
210 | 1.09M | if (t < R0MIN) /* a literal run */ |
211 | 338k | { |
212 | 338k | if (t == 0) /* a R0 literal run */ |
213 | 25.0k | { |
214 | 25.0k | t = *ip++; |
215 | 25.0k | if (t >= R0FAST - R0MIN) /* a long R0 run */ |
216 | 9.79k | { |
217 | 9.79k | t -= R0FAST - R0MIN; |
218 | 9.79k | if (t == 0) |
219 | 3.48k | t = R0FAST; |
220 | 6.30k | else |
221 | 6.30k | { |
222 | | #if 0 |
223 | | t = 256u << ((unsigned) t); |
224 | | #else |
225 | | /* help the optimizer */ |
226 | 6.30k | lzo_uint tt = 256; |
227 | 11.8k | do tt <<= 1; while (--t > 0); |
228 | 6.30k | t = tt; |
229 | 6.30k | #endif |
230 | 6.30k | } |
231 | 9.79k | MEMCPY8_DS(op,ip,t); |
232 | 9.79k | continue; |
233 | 9.79k | } |
234 | 15.2k | t += R0MIN; |
235 | 15.2k | } |
236 | 328k | MEMCPY_DS(op,ip,t); |
237 | 328k | } |
238 | 760k | else /* a match */ |
239 | 760k | { |
240 | 760k | lzo_uint tt; |
241 | | /* get match offset */ |
242 | 760k | const lzo_bytep m_pos = op - 1; |
243 | 760k | m_pos -= (lzo_uint)(t & OMASK) | (((lzo_uint) *ip++) << OBITS); |
244 | | |
245 | | /* get match len */ |
246 | 760k | if (t >= ((MSIZE - 1) << OBITS)) /* all m-bits set */ |
247 | 251k | tt = (MIN_MATCH_LONG - THRESHOLD) + *ip++; /* a long match */ |
248 | 508k | else |
249 | 508k | tt = t >> OBITS; /* a short match */ |
250 | | |
251 | 760k | assert(m_pos >= out); |
252 | 760k | assert(m_pos < op); |
253 | | /* a half unrolled loop */ |
254 | 760k | *op++ = *m_pos++; |
255 | 760k | *op++ = *m_pos++; |
256 | 760k | MEMCPY_DS(op,m_pos,tt); |
257 | 760k | } |
258 | 1.09M | } |
259 | | |
260 | 682 | *out_len = pd(op, out); |
261 | | |
262 | | /* the next line is the only check in the decompressor ! */ |
263 | 682 | return (ip == ip_end ? LZO_E_OK : |
264 | 682 | (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); |
265 | 682 | } |
266 | | |
267 | | |
268 | | /*********************************************************************** |
269 | | // code a literal run |
270 | | ************************************************************************/ |
271 | | |
272 | | static |
273 | | #if LZO_ARCH_AVR |
274 | | __lzo_noinline |
275 | | #endif |
276 | | lzo_bytep |
277 | | store_run(lzo_bytep op, const lzo_bytep ii, lzo_uint r_len) |
278 | 10.9k | { |
279 | 10.9k | assert(r_len > 0); |
280 | | |
281 | | /* code a long R0 run */ |
282 | 10.9k | if (r_len >= 512) |
283 | 2.88k | { |
284 | 2.88k | unsigned r_bits = 7; /* 256 << 7 == 32768 */ |
285 | 20.1k | do { |
286 | 24.2k | while (r_len >= (256u << r_bits)) |
287 | 4.11k | { |
288 | 4.11k | r_len -= (256u << r_bits); |
289 | 4.11k | *op++ = 0; *op++ = LZO_BYTE((R0FAST - R0MIN) + r_bits); |
290 | 4.11k | MEMCPY8_DS(op, ii, (256u << r_bits)); |
291 | 4.11k | } |
292 | 20.1k | } while (--r_bits > 0); |
293 | 2.88k | } |
294 | 13.3k | while (r_len >= R0FAST) |
295 | 2.42k | { |
296 | 2.42k | r_len -= R0FAST; |
297 | 2.42k | *op++ = 0; *op++ = R0FAST - R0MIN; |
298 | 2.42k | MEMCPY8_DS(op, ii, R0FAST); |
299 | 2.42k | } |
300 | | |
301 | 10.9k | if (r_len >= R0MIN) |
302 | 9.93k | { |
303 | | /* code a short R0 run */ |
304 | 9.93k | *op++ = 0; *op++ = LZO_BYTE(r_len - R0MIN); |
305 | 9.93k | MEMCPY_DS(op, ii, r_len); |
306 | 9.93k | } |
307 | 1.02k | else if (r_len > 0) |
308 | 923 | { |
309 | | /* code a 'normal' run */ |
310 | 923 | *op++ = LZO_BYTE(r_len); |
311 | 923 | MEMCPY_DS(op, ii, r_len); |
312 | 923 | } |
313 | | |
314 | 10.9k | assert(r_len == 0); |
315 | 10.9k | return op; |
316 | 10.9k | } |
317 | | |
318 | | |
319 | | |
320 | | /*********************************************************************** |
321 | | // LZO1 compress a block of data. |
322 | | // |
323 | | // Could be translated into assembly code without too much effort. |
324 | | // |
325 | | // I apologize for the spaghetti code, but it really helps the optimizer. |
326 | | ************************************************************************/ |
327 | | |
328 | | static int |
329 | | do_compress ( const lzo_bytep in , lzo_uint in_len, |
330 | | lzo_bytep out, lzo_uintp out_len, |
331 | | lzo_voidp wrkmem ) |
332 | 341 | { |
333 | 341 | const lzo_bytep ip; |
334 | 341 | #if defined(__LZO_HASH_INCREMENTAL) |
335 | 341 | lzo_xint dv; |
336 | 341 | #endif |
337 | 341 | lzo_bytep op; |
338 | 341 | const lzo_bytep m_pos; |
339 | 341 | const lzo_bytep const ip_end = in+in_len - DVAL_LEN - MIN_MATCH_LONG; |
340 | 341 | const lzo_bytep const in_end = in+in_len - DVAL_LEN; |
341 | 341 | const lzo_bytep ii; |
342 | 341 | lzo_dict_p const dict = (lzo_dict_p) wrkmem; |
343 | | |
344 | | #if !defined(NDEBUG) |
345 | | const lzo_bytep m_pos_sav; |
346 | | #endif |
347 | | |
348 | 341 | op = out; |
349 | 341 | ip = in; |
350 | 341 | ii = ip; /* point to start of literal run */ |
351 | 341 | if (in_len <= MIN_MATCH_LONG + DVAL_LEN + 1) |
352 | 0 | goto the_end; |
353 | | |
354 | | /* init dictionary */ |
355 | 341 | #if (LZO_DETERMINISTIC) |
356 | 341 | BZERO8_PTR(wrkmem,sizeof(lzo_dict_t),D_SIZE); |
357 | 341 | #endif |
358 | | |
359 | 341 | DVAL_FIRST(dv,ip); |
360 | 341 | UPDATE_D(dict,0,dv,ip,in); |
361 | 341 | ip++; |
362 | 341 | DVAL_NEXT(dv,ip); |
363 | | |
364 | 9.82M | do { |
365 | 9.82M | LZO_DEFINE_UNINITIALIZED_VAR(lzo_uint, m_off, 0); |
366 | 9.82M | lzo_uint dindex; |
367 | | |
368 | 9.82M | DINDEX1(dindex,ip); |
369 | 9.82M | GINDEX(m_pos,m_off,dict,dindex,in); |
370 | 9.82M | if (LZO_CHECK_MPOS(m_pos,m_off,in,ip,MAX_OFFSET)) |
371 | 3.41M | goto literal; |
372 | 6.40M | if (m_pos[0] == ip[0] && m_pos[1] == ip[1] && m_pos[2] == ip[2]) |
373 | 379k | goto match; |
374 | 6.02M | DINDEX2(dindex,ip); |
375 | 6.02M | GINDEX(m_pos,m_off,dict,dindex,in); |
376 | 6.02M | if (LZO_CHECK_MPOS(m_pos,m_off,in,ip,MAX_OFFSET)) |
377 | 1.53M | goto literal; |
378 | 4.49M | if (m_pos[0] == ip[0] && m_pos[1] == ip[1] && m_pos[2] == ip[2]) |
379 | 42.5k | goto match; |
380 | 4.45M | goto literal; |
381 | | |
382 | | |
383 | 9.40M | literal: |
384 | 9.40M | UPDATE_I(dict,0,dindex,ip,in); |
385 | 9.40M | if (++ip >= ip_end) |
386 | 135 | break; |
387 | 9.40M | continue; |
388 | | |
389 | 9.40M | match: |
390 | 422k | UPDATE_I(dict,0,dindex,ip,in); |
391 | | #if !defined(NDEBUG) && (LZO_DICT_USE_PTR) |
392 | | m_pos_sav = m_pos; |
393 | | #endif |
394 | 422k | m_pos += 3; |
395 | 422k | { |
396 | | /* we have found a match (of at least length 3) */ |
397 | | #if !defined(NDEBUG) && !(LZO_DICT_USE_PTR) |
398 | | assert((m_pos_sav = ip - m_off) == (m_pos - 3)); |
399 | | #endif |
400 | | /* 1) store the current literal run */ |
401 | 422k | if (pd(ip,ii) > 0) |
402 | 148k | { |
403 | 148k | lzo_uint t = pd(ip,ii); |
404 | 148k | #if 1 |
405 | | /* OPTIMIZED: inline the copying of a short run */ |
406 | 148k | if (t < R0MIN) |
407 | 138k | { |
408 | 138k | *op++ = LZO_BYTE(t); |
409 | 138k | MEMCPY_DS(op, ii, t); |
410 | 138k | } |
411 | 10.6k | else |
412 | 10.6k | #endif |
413 | 10.6k | op = store_run(op,ii,t); |
414 | 148k | } |
415 | | |
416 | | /* 2a) compute match len */ |
417 | 422k | ii = ip; /* point to start of current match */ |
418 | | |
419 | | /* we already matched MIN_MATCH bytes, |
420 | | * m_pos also already advanced MIN_MATCH bytes */ |
421 | 422k | ip += MIN_MATCH; |
422 | 422k | assert(m_pos < ip); |
423 | | |
424 | | /* try to match another MIN_MATCH_LONG - MIN_MATCH bytes |
425 | | * to see if we get a long match */ |
426 | | |
427 | 3.82M | #define PS *m_pos++ != *ip++ |
428 | | |
429 | | #if (MIN_MATCH_LONG - MIN_MATCH == 2) /* MBITS == 2 */ |
430 | | if (PS || PS) |
431 | | #elif (MIN_MATCH_LONG - MIN_MATCH == 6) /* MBITS == 3 */ |
432 | 422k | if (PS || PS || PS || PS || PS || PS) |
433 | | #elif (MIN_MATCH_LONG - MIN_MATCH == 14) /* MBITS == 4 */ |
434 | | if (PS || PS || PS || PS || PS || PS || PS || |
435 | | PS || PS || PS || PS || PS || PS || PS) |
436 | | #elif (MIN_MATCH_LONG - MIN_MATCH == 30) /* MBITS == 5 */ |
437 | | if (PS || PS || PS || PS || PS || PS || PS || PS || |
438 | | PS || PS || PS || PS || PS || PS || PS || PS || |
439 | | PS || PS || PS || PS || PS || PS || PS || PS || |
440 | | PS || PS || PS || PS || PS || PS) |
441 | | #else |
442 | | # error "MBITS not yet implemented" |
443 | | #endif |
444 | 225k | { |
445 | 225k | lzo_uint m_len; |
446 | | |
447 | | /* 2b) code a short match */ |
448 | 225k | assert(pd(ip,m_pos) == m_off); |
449 | 225k | --ip; /* ran one too far, point back to non-match */ |
450 | 225k | m_len = pd(ip, ii); |
451 | 225k | assert(m_len >= MIN_MATCH_SHORT); |
452 | 225k | assert(m_len <= MAX_MATCH_SHORT); |
453 | 225k | assert(m_off > 0); |
454 | 225k | assert(m_off <= MAX_OFFSET); |
455 | 225k | assert(ii-m_off == m_pos_sav); |
456 | 225k | assert(lzo_memcmp(m_pos_sav,ii,m_len) == 0); |
457 | 225k | --m_off; |
458 | | /* code short match len + low offset bits */ |
459 | 225k | *op++ = LZO_BYTE(((m_len - THRESHOLD) << OBITS) | |
460 | 225k | (m_off & OMASK)); |
461 | | /* code high offset bits */ |
462 | 225k | *op++ = LZO_BYTE(m_off >> OBITS); |
463 | | |
464 | | |
465 | | /* 2c) Insert phrases (beginning with ii+1) into the dictionary. */ |
466 | | |
467 | 225k | #define SI /* nothing */ |
468 | 225k | #define DI ++ii; DVAL_NEXT(dv,ii); UPDATE_D(dict,0,dv,ii,in); |
469 | 422k | #define XI assert(ii < ip); ii = ip; DVAL_FIRST(dv,(ip)); |
470 | | |
471 | | #if (CLEVEL == 9) || (CLEVEL >= 7 && MBITS <= 4) || (CLEVEL >= 5 && MBITS <= 3) |
472 | | /* Insert the whole match (ii+1)..(ip-1) into dictionary. */ |
473 | | ++ii; |
474 | | do { |
475 | | DVAL_NEXT(dv,ii); |
476 | | UPDATE_D(dict,0,dv,ii,in); |
477 | | } while (++ii < ip); |
478 | | DVAL_NEXT(dv,ii); |
479 | | assert(ii == ip); |
480 | | DVAL_ASSERT(dv,ip); |
481 | | #elif (CLEVEL >= 3) |
482 | | SI DI DI XI |
483 | | #elif (CLEVEL >= 2) |
484 | | SI DI XI |
485 | | #else |
486 | 225k | XI |
487 | 225k | #endif |
488 | | |
489 | 225k | } |
490 | 197k | else |
491 | 197k | { |
492 | | /* we've found a long match - see how far we can still go */ |
493 | 197k | const lzo_bytep end; |
494 | 197k | lzo_uint m_len; |
495 | | |
496 | 197k | assert(ip <= in_end); |
497 | 197k | assert(ii == ip - MIN_MATCH_LONG); |
498 | | |
499 | 197k | if (pd(in_end,ip) <= (MAX_MATCH_LONG - MIN_MATCH_LONG)) |
500 | 426 | end = in_end; |
501 | 196k | else |
502 | 196k | { |
503 | 196k | end = ip + (MAX_MATCH_LONG - MIN_MATCH_LONG); |
504 | 196k | assert(end < in_end); |
505 | 196k | } |
506 | | |
507 | 18.3M | while (ip < end && *m_pos == *ip) |
508 | 18.1M | { m_pos++; ip++; } |
509 | 197k | assert(ip <= in_end); |
510 | | |
511 | | /* 2b) code the long match */ |
512 | 197k | m_len = pd(ip, ii); |
513 | 197k | assert(m_len >= MIN_MATCH_LONG); |
514 | 197k | assert(m_len <= MAX_MATCH_LONG); |
515 | 197k | assert(m_off > 0); |
516 | 197k | assert(m_off <= MAX_OFFSET); |
517 | 197k | assert(ii-m_off == m_pos_sav); |
518 | 197k | assert(lzo_memcmp(m_pos_sav,ii,m_len) == 0); |
519 | 197k | assert(pd(ip,m_pos) == m_off); |
520 | 197k | --m_off; |
521 | | /* code long match flag + low offset bits */ |
522 | 197k | *op++ = LZO_BYTE(((MSIZE - 1) << OBITS) | (m_off & OMASK)); |
523 | | /* code high offset bits */ |
524 | 197k | *op++ = LZO_BYTE(m_off >> OBITS); |
525 | | /* code match len */ |
526 | 197k | *op++ = LZO_BYTE(m_len - MIN_MATCH_LONG); |
527 | | |
528 | | |
529 | | /* 2c) Insert phrases (beginning with ii+1) into the dictionary. */ |
530 | | #if (CLEVEL == 9) |
531 | | /* Insert the whole match (ii+1)..(ip-1) into dictionary. */ |
532 | | /* This is not recommended because it is slow. */ |
533 | | ++ii; |
534 | | do { |
535 | | DVAL_NEXT(dv,ii); |
536 | | UPDATE_D(dict,0,dv,ii,in); |
537 | | } while (++ii < ip); |
538 | | DVAL_NEXT(dv,ii); |
539 | | assert(ii == ip); |
540 | | DVAL_ASSERT(dv,ip); |
541 | | #elif (CLEVEL >= 8) |
542 | | SI DI DI DI DI DI DI DI DI XI |
543 | | #elif (CLEVEL >= 7) |
544 | | SI DI DI DI DI DI DI DI XI |
545 | | #elif (CLEVEL >= 6) |
546 | | SI DI DI DI DI DI DI XI |
547 | | #elif (CLEVEL >= 5) |
548 | | SI DI DI DI DI XI |
549 | | #elif (CLEVEL >= 4) |
550 | | SI DI DI DI XI |
551 | | #elif (CLEVEL >= 3) |
552 | | SI DI DI XI |
553 | | #elif (CLEVEL >= 2) |
554 | | SI DI XI |
555 | | #else |
556 | 197k | XI |
557 | 197k | #endif |
558 | 197k | } |
559 | | |
560 | | /* ii now points to the start of next literal run */ |
561 | 422k | assert(ii == ip); |
562 | 422k | } |
563 | 9.82M | } while (ip < ip_end); |
564 | | |
565 | | |
566 | | |
567 | 341 | the_end: |
568 | 341 | assert(ip <= in_end); |
569 | | |
570 | | |
571 | | #if defined(LZO_RETURN_IF_NOT_COMPRESSIBLE) |
572 | | /* return -1 if op == out to indicate that we |
573 | | * couldn't compress and didn't copy anything. |
574 | | */ |
575 | | if (op == out) |
576 | | { |
577 | | *out_len = 0; |
578 | | return LZO_E_NOT_COMPRESSIBLE; |
579 | | } |
580 | | #endif |
581 | | |
582 | | |
583 | | /* store the final literal run */ |
584 | 341 | if (pd(in_end+DVAL_LEN,ii) > 0) |
585 | 341 | op = store_run(op,ii,pd(in_end+DVAL_LEN,ii)); |
586 | | |
587 | 341 | *out_len = pd(op, out); |
588 | 341 | return 0; /* compression went ok */ |
589 | 341 | } |
590 | | |
591 | | |
592 | | /*********************************************************************** |
593 | | // compress public entry point. |
594 | | ************************************************************************/ |
595 | | |
596 | | LZO_PUBLIC(int) |
597 | | lzo1_compress ( const lzo_bytep in , lzo_uint in_len, |
598 | | lzo_bytep out, lzo_uintp out_len, |
599 | | lzo_voidp wrkmem ) |
600 | 351 | { |
601 | 351 | int r = LZO_E_OK; |
602 | | |
603 | | /* don't try to compress a block that's too short */ |
604 | 351 | if (in_len == 0) |
605 | 1 | *out_len = 0; |
606 | 350 | else if (in_len <= MIN_MATCH_LONG + DVAL_LEN + 1) |
607 | 9 | { |
608 | | #if defined(LZO_RETURN_IF_NOT_COMPRESSIBLE) |
609 | | r = LZO_E_NOT_COMPRESSIBLE; |
610 | | #else |
611 | 9 | *out_len = pd(store_run(out,in,in_len), out); |
612 | 9 | #endif |
613 | 9 | } |
614 | 341 | else |
615 | 341 | r = do_compress(in,in_len,out,out_len,wrkmem); |
616 | | |
617 | 351 | return r; |
618 | 351 | } |
619 | | |
620 | | |
621 | | /* vim:set ts=4 sw=4 et: */ |