1 /* p_lzo.c -- LZO compression
2
3 This file is part of the lzop file compressor.
4
5 Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer
6 All Rights Reserved.
7
8 lzop and the LZO library are free software; you can redistribute them
9 and/or modify them 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 This program 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 this program; 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/lzop/
26 */
27
28
29 #include "conf.h"
30
31
32 #if defined(WITH_LZO)
33
34
35 /*************************************************************************
36 //
37 **************************************************************************/
38
lzo_set_method(int m,int level)39 int lzo_set_method(int m, int level)
40 {
41 int l = level & 0xff;
42
43 if (m != 0 || l < 1 || l > 9)
44 return -1; /* not a LZO method */
45
46 #if defined(USE_LZO1X_1_15)
47 if (l == 1)
48 m = M_LZO1X_1_15;
49 else
50 #endif
51 #if defined(USE_LZO1X_1)
52 if (l <= 6)
53 {
54 m = M_LZO1X_1;
55 l = 5;
56 }
57 #endif
58 #if defined(USE_LZO1X_999)
59 if (l >= 7 && l <= 9)
60 {
61 m = M_LZO1X_999;
62 }
63 #endif
64
65 if (m == 0)
66 return 1; /* error */
67
68 opt_method = m;
69 opt_level = l;
70 return 0;
71 }
72
73
lzo_get_method(header_t * h)74 int lzo_get_method(header_t *h)
75 {
76 /* check method */
77 if (h->method == M_LZO1X_1)
78 {
79 h->method_name = "LZO1X-1";
80 if (h->level == 0)
81 h->level = 3;
82 }
83 else if (h->method == M_LZO1X_1_15)
84 {
85 h->method_name = "LZO1X-1(15)";
86 if (h->level == 0)
87 h->level = 1;
88 }
89 else if (h->method == M_LZO1X_999)
90 {
91 static char s[11+1] = "LZO1X-999 ";
92 s[9] = 0;
93 if (h->level == 0)
94 h->level = 9;
95 else if (h->version >= 0x0950 && h->lib_version >= 0x1020)
96 {
97 s[9] = '/';
98 s[10] = (char) (h->level + '0');
99 }
100 h->method_name = s;
101 }
102 else
103 return -1; /* not a LZO method */
104
105 /* check compression level */
106 if (h->level < 1 || h->level > 9)
107 return 15;
108
109 return 0;
110 }
111
112
lzo_init_compress_header(header_t * h)113 void lzo_init_compress_header(header_t *h)
114 {
115 if (opt_checksum)
116 {
117 if (opt_crc32)
118 {
119 h->flags |= F_CRC32_D;
120 if (opt_checksum >= 2)
121 h->flags |= F_CRC32_C;
122 }
123 else
124 {
125 h->flags |= F_ADLER32_D;
126 if (opt_checksum >= 2)
127 h->flags |= F_ADLER32_C;
128 }
129 }
130 }
131
132
133 /*************************************************************************
134 // memory setup
135 **************************************************************************/
136
137 #if defined(ACC_OS_DOS16) && !defined(ACC_ARCH_I086PM)
138 # define BLOCK_SIZE (128*1024l)
139 #else
140 # define BLOCK_SIZE (256*1024l)
141 #endif
142 #define MAX_BLOCK_SIZE (64*1024l*1024l) /* DO NOT CHANGE */
143
144 #if defined(USE_LZO1X_999)
145 # define WRK_LEN LZO1X_999_MEM_COMPRESS
146 #elif defined(USE_LZO1X_1_15)
147 # define WRK_LEN LZO1X_1_15_MEM_COMPRESS
148 #elif defined(USE_LZO1X_1)
149 # define WRK_LEN LZO1X_1_MEM_COMPRESS
150 #else
151 # error
152 #endif
153
154
155 #if 1
156 # define ALIGN_SIZE 4096
157 #else
158 # define ALIGN_SIZE 1
159 #endif
160
161 /* LZO may expand incompressible data by a small amount */
162 #define MAX_COMPRESSED_SIZE(x) ((x) + (x) / 16 + 64 + 3)
163
164
165 static mblock_t blocks[2];
166 static mblock_t wrkmem;
167
168
free_mem(void)169 static void free_mem(void)
170 {
171 mb_free(&wrkmem);
172 mb_free(&blocks[1]);
173 mb_free(&blocks[0]);
174 }
175
176
alloc_mem(lzo_uint32 s1,lzo_uint32 s2,lzo_uint32 w)177 static lzo_bool alloc_mem(lzo_uint32 s1, lzo_uint32 s2, lzo_uint32 w)
178 {
179 lzo_bool r = 1;
180
181 r &= mb_alloc(&blocks[0], s1, ALIGN_SIZE);
182 r &= mb_alloc(&blocks[1], s2, ALIGN_SIZE);
183 r &= mb_alloc(&wrkmem, w, ALIGN_SIZE);
184 if (!r)
185 free_mem();
186 return r;
187 }
188
189
190 /*************************************************************************
191 // enter / leave
192 **************************************************************************/
193
194 /* maybe make this an option ? */
195 static const lzo_uint32 block_size = BLOCK_SIZE;
196
lzo_enter(const header_t * h)197 lzo_bool lzo_enter(const header_t *h)
198 {
199 int r;
200 lzo_uint32 wrk_len;
201
202 #if defined(WITH_THREADS)
203 if (opt_num_threads > 1)
204 return lzo_threaded_enter(h);
205 #endif
206
207 if (h != NULL)
208 {
209 r = 1;
210 if ((h->flags & F_ADLER32_C) && !(h->flags & F_ADLER32_D))
211 { r = 0; assert(h->flags & F_ADLER32_D); }
212 if ((h->flags & F_CRC32_C) && !(h->flags & F_CRC32_D))
213 { r = 0; assert(h->flags & F_CRC32_D); }
214 return r;
215 }
216
217 #if 0
218 fprintf(stderr,"%lu %lu %u\n", BLOCK_SIZE, MAX_BLOCK_SIZE, ALIGN_SIZE);
219 #endif
220 assert(block_size <= BLOCK_SIZE);
221 assert(block_size <= MAX_BLOCK_SIZE);
222 assert(block_size >= 16*1024);
223
224 if (opt_method == M_LZO1X_1)
225 wrk_len = LZO1X_1_MEM_COMPRESS;
226 else if (opt_method == M_LZO1X_1_15)
227 wrk_len = LZO1X_1_15_MEM_COMPRESS;
228 else if (opt_method == M_LZO1X_999)
229 wrk_len = LZO1X_999_MEM_COMPRESS;
230 else
231 wrk_len = 0;
232 assert(wrk_len <= WRK_LEN);
233
234 if (opt_method == M_LZO1X_999)
235 {
236 if (opt_checksum < 1)
237 opt_checksum = 1; /* always compute a checksum */
238 if (opt_cmd == CMD_COMPRESS)
239 opt_optimize = 1;
240 }
241
242 switch (opt_cmd)
243 {
244 case CMD_COMPRESS:
245 r = alloc_mem(block_size, MAX_COMPRESSED_SIZE(block_size), wrk_len);
246 break;
247 case CMD_DECOMPRESS:
248 case CMD_TEST:
249 r = alloc_mem(0, MAX_COMPRESSED_SIZE(block_size), 0);
250 break;
251 case CMD_LIST:
252 case CMD_LS:
253 case CMD_INFO:
254 r = alloc_mem(0, block_size, 0);
255 break;
256 default:
257 r = alloc_mem(0, 0, 0);
258 break;
259 }
260
261 return r;
262 }
263
264
lzo_leave(const header_t * h)265 void lzo_leave(const header_t *h)
266 {
267 #if defined(WITH_THREADS)
268 if (opt_num_threads > 1) {
269 lzo_threaded_leave(h);
270 return;
271 }
272 #endif
273 if (h == NULL)
274 free_mem();
275 }
276
277
278 /*************************************************************************
279 // compress a file
280 **************************************************************************/
281
lzo_compress(file_t * fip,file_t * fop,const header_t * h)282 lzo_bool lzo_compress(file_t *fip, file_t *fop, const header_t *h)
283 {
284 int r = LZO_E_OK;
285 lzo_bytep const b1 = blocks[0].mb_mem;
286 lzo_bytep const b2 = blocks[1].mb_mem;
287 lzo_uint32 src_len = 0;
288 lzo_uint dst_len = 0;
289 lzo_uint32 c_adler32 = ADLER32_INIT_VALUE, d_adler32 = ADLER32_INIT_VALUE;
290 lzo_uint32 c_crc32 = CRC32_INIT_VALUE, d_crc32 = CRC32_INIT_VALUE;
291 lzo_int l;
292 lzo_bool ok = 1;
293
294 #if defined(WITH_THREADS)
295 if (opt_num_threads > 1)
296 return lzo_threaded_compress(fip, fop, h, skip);
297 #endif
298
299 for (;;)
300 {
301 /* read a block */
302 l = read_buf(fip, b1, block_size);
303 src_len = (lzo_uint32) (l > 0 ? l : 0);
304
305 /* write uncompressed block size */
306 write32(fop,src_len);
307
308 /* exit if last block */
309 if (src_len == 0)
310 break;
311
312 /* compute checksum of uncompressed block */
313 if (h->flags & F_ADLER32_D)
314 d_adler32 = lzo_adler32(ADLER32_INIT_VALUE,b1,src_len);
315 if (h->flags & F_CRC32_D)
316 d_crc32 = lzo_crc32(CRC32_INIT_VALUE,b1,src_len);
317
318 x_filter(b1,src_len,h);
319
320 /* compress */
321 if (h->method == M_LZO1X_1)
322 r = lzo1x_1_compress(b1, src_len, b2, &dst_len, wrkmem.mb_mem);
323 #if defined(USE_LZO1X_1_15)
324 else if (h->method == M_LZO1X_1_15)
325 r = lzo1x_1_15_compress(b1, src_len,
326 b2, &dst_len, wrkmem.mb_mem);
327 #endif
328 #if defined(USE_LZO1X_999)
329 else if (h->method == M_LZO1X_999)
330 r = lzo1x_999_compress_level(b1, src_len,
331 b2, &dst_len, wrkmem.mb_mem,
332 NULL, 0, 0, h->level);
333 #endif
334 else
335 fatal(fip,"Internal error");
336
337 #if 0
338 fprintf(stderr, "%ld %ld %ld\n", (long)src_len, (long)dst_len, (long)block2.size);
339 #endif
340 assert(dst_len <= blocks[1].mb_size);
341 if (r != LZO_E_OK)
342 fatal(fip,"Internal error - compression failed");
343
344 /* optimize */
345 if (opt_optimize && dst_len < src_len)
346 {
347 lzo_uint new_len = src_len;
348 r = lzo1x_optimize(b2, dst_len, b1, &new_len, NULL);
349 if (r != LZO_E_OK || new_len != src_len)
350 fatal(fip,"Internal error - optimization failed");
351 }
352
353 /* write compressed block size */
354 if (dst_len < src_len)
355 write32(fop, (lzo_uint32) dst_len);
356 else
357 write32(fop, src_len);
358
359 /* write checksum of uncompressed block */
360 if (h->flags & F_ADLER32_D)
361 write32(fop,d_adler32);
362 if (h->flags & F_CRC32_D)
363 write32(fop,d_crc32);
364
365 /* write checksum of compressed block */
366 if (dst_len < src_len && (h->flags & F_ADLER32_C))
367 {
368 c_adler32 = lzo_adler32(ADLER32_INIT_VALUE,b2,dst_len);
369 write32(fop,c_adler32);
370 }
371 if (dst_len < src_len && (h->flags & F_CRC32_C))
372 {
373 c_crc32 = lzo_crc32(CRC32_INIT_VALUE,b2,dst_len);
374 write32(fop,c_crc32);
375 }
376
377 /* write compressed block data */
378 if (dst_len < src_len)
379 write_buf(fop,b2,dst_len);
380 else
381 write_buf(fop,b1,src_len);
382 }
383
384 return ok;
385 }
386
387
388 /*************************************************************************
389 // decompress a file
390 **************************************************************************/
391
lzo_decompress(file_t * fip,file_t * fop,const header_t * h,lzo_bool skip)392 lzo_bool lzo_decompress(file_t *fip, file_t *fop,
393 const header_t *h, lzo_bool skip)
394 {
395 int r;
396 lzo_uint32 src_len, dst_len;
397 lzo_uint32 c_adler32 = ADLER32_INIT_VALUE, d_adler32 = ADLER32_INIT_VALUE;
398 lzo_uint32 c_crc32 = CRC32_INIT_VALUE, d_crc32 = CRC32_INIT_VALUE;
399 lzo_bool ok = 1;
400 lzo_bool use_seek;
401 mblock_t * const block = &blocks[1];
402 lzo_bytep b1;
403 lzo_bytep const b2 = block->mb_mem;
404
405 #if defined(WITH_THREADS)
406 if (opt_num_threads > 1)
407 return lzo_threaded_decompress(fip, fop, h, skip);
408 #endif
409
410 use_seek = skip || opt_cmd == CMD_LIST || opt_cmd == CMD_LS ||
411 opt_cmd == CMD_INFO;
412
413 for (;;)
414 {
415 lzo_bytep dst;
416
417 /* read uncompressed block size */
418 read32(fip,&dst_len);
419
420 /* exit if last block */
421 if (dst_len == 0)
422 break;
423
424 /* error if split file */
425 if (dst_len == 0xffffffffUL)
426 {
427 /* should not happen - not yet implemented */
428 error(fip,"this file is a split " PACKAGE " file");
429 ok = 0; break;
430 }
431
432 if (dst_len > MAX_BLOCK_SIZE)
433 {
434 error(fip, PACKAGE " file corrupted");
435 ok = 0; break;
436 }
437
438 /* read compressed block size */
439 read32(fip,&src_len);
440 if (src_len <= 0 || src_len > dst_len)
441 {
442 error(fip, PACKAGE " file corrupted");
443 ok = 0; break;
444 }
445
446 if (dst_len > BLOCK_SIZE)
447 {
448 fatal(fip,"block size too small -- recompile " PACKAGE);
449 ok = 0; break;
450 }
451 if (dst_len > block_size)
452 {
453 /* should not happen - not yet implemented */
454 fatal(fip,"block size too small -- use option '--blocksize'");
455 ok = 0; break;
456 }
457 assert(block->mb_size >= src_len);
458
459 /* read checksum of uncompressed block */
460 if (h->flags & F_ADLER32_D)
461 read32(fip,&d_adler32);
462 if (h->flags & F_CRC32_D)
463 read32(fip,&d_crc32);
464
465 /* read checksum of compressed block */
466 if (h->flags & F_ADLER32_C)
467 {
468 if (src_len < dst_len)
469 read32(fip,&c_adler32);
470 else
471 {
472 assert(h->flags & F_ADLER32_D);
473 c_adler32 = d_adler32;
474 }
475 }
476 if (h->flags & F_CRC32_C)
477 {
478 if (src_len < dst_len)
479 read32(fip,&c_crc32);
480 else
481 {
482 assert(h->flags & F_CRC32_D);
483 c_crc32 = d_crc32;
484 }
485 }
486
487 /* read the block */
488 b1 = block->mb_mem + block->mb_size - src_len;
489 if (use_seek && fip->fd != STDIN_FILENO)
490 {
491 if (lseek(fip->fd, src_len, SEEK_CUR) == -1)
492 read_error(fip);
493 }
494 else
495 {
496 if (read_buf(fip, b1, src_len) != (lzo_int) src_len)
497 read_error(fip);
498 }
499
500 fip->bytes_processed += src_len;
501 if (use_seek)
502 {
503 fop->bytes_processed += dst_len;
504 continue;
505 }
506 assert(block->mb_size >= MAX_COMPRESSED_SIZE(dst_len));
507
508 /* verify checksum of compressed block */
509 if (opt_checksum && (h->flags & F_ADLER32_C))
510 {
511 lzo_uint32 c;
512 c = lzo_adler32(ADLER32_INIT_VALUE,b1,src_len);
513 if (c != c_adler32)
514 {
515 error(fip,"Checksum error (" PACKAGE " file corrupted)");
516 ok = 0; break;
517 }
518 }
519 if (opt_checksum && (h->flags & F_CRC32_C))
520 {
521 lzo_uint32 c;
522 c = lzo_crc32(CRC32_INIT_VALUE,b1,src_len);
523 if (c != c_crc32)
524 {
525 error(fip,"Checksum error (" PACKAGE " file corrupted)");
526 ok = 0; break;
527 }
528 }
529
530 if (src_len < dst_len)
531 {
532 lzo_uint d = dst_len;
533
534 /* decompress */
535 if (opt_decompress_safe)
536 r = lzo1x_decompress_safe(b1,src_len,b2,&d,NULL);
537 else
538 r = lzo1x_decompress(b1,src_len,b2,&d,NULL);
539
540 if (r != LZO_E_OK || dst_len != d)
541 {
542 error(fip,"Compressed data violation");
543 #if 0
544 fprintf(stderr,"%d %ld %ld\n", r, (long)dst_len, (long)d);
545 #endif
546 ok = 0; break;
547 }
548 dst = b2;
549 }
550 else
551 {
552 assert(dst_len == src_len);
553 dst = b1;
554 }
555
556 x_filter(dst,dst_len,h);
557
558 /* verify checksum of uncompressed block */
559 if (opt_checksum && (h->flags & F_ADLER32_D))
560 {
561 lzo_uint32 c;
562 c = lzo_adler32(ADLER32_INIT_VALUE,dst,dst_len);
563 if (c != d_adler32)
564 {
565 error(fip,"Checksum error");
566 ok = 0; break;
567 }
568 }
569 if (opt_checksum && (h->flags & F_CRC32_D))
570 {
571 lzo_uint32 c;
572 c = lzo_crc32(CRC32_INIT_VALUE,dst,dst_len);
573 if (c != d_crc32)
574 {
575 error(fip,"Checksum error");
576 ok = 0; break;
577 }
578 }
579
580 /* write uncompressed block data */
581 write_buf(fop,dst,dst_len);
582 fop->bytes_processed += dst_len;
583 }
584
585 return ok;
586 }
587
588
589 #endif /* WITH_LZO */
590
591
592 /* vim:set ts=4 sw=4 et: */
593