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