diff options
Diffstat (limited to 'src/p_lzo.c')
-rw-r--r-- | src/p_lzo.c | 595 |
1 files changed, 595 insertions, 0 deletions
diff --git a/src/p_lzo.c b/src/p_lzo.c new file mode 100644 index 0000000..bacb28d --- /dev/null +++ b/src/p_lzo.c @@ -0,0 +1,595 @@ +/* p_lzo.c -- LZO compression + + This file is part of the lzop file compressor. + + Copyright (C) 1996-2010 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + lzop and the LZO library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer + <markus@oberhumer.com> + http://www.oberhumer.com/opensource/lzop/ + */ + + +#include "conf.h" + + +#if defined(WITH_LZO) + + +/************************************************************************* +// +**************************************************************************/ + +int lzo_set_method(int m, int level) +{ + int l = level & 0xff; + + if (m != 0 || l < 1 || l > 9) + return -1; /* not a LZO method */ + +#if defined(USE_LZO1X_1_15) + if (l == 1) + m = M_LZO1X_1_15; + else +#endif +#if defined(USE_LZO1X_1) + if (l <= 6) + { + m = M_LZO1X_1; + l = 5; + } +#endif +#if defined(USE_LZO1X_999) + if (l >= 7 && l <= 9) + { + m = M_LZO1X_999; + } +#endif + + if (m == 0) + return 1; /* error */ + + opt_method = m; + opt_level = l; + return 0; +} + + +int lzo_get_method(header_t *h) +{ +/* check method */ + if (h->method == M_LZO1X_1) + { + h->method_name = "LZO1X-1"; + if (h->level == 0) + h->level = 3; + } + else if (h->method == M_LZO1X_1_15) + { + h->method_name = "LZO1X-1(15)"; + if (h->level == 0) + h->level = 1; + } + else if (h->method == M_LZO1X_999) + { + static char s[11+1] = "LZO1X-999 "; + s[9] = 0; + if (h->level == 0) + h->level = 9; + else if (h->version >= 0x0950 && h->lib_version >= 0x1020) + { + s[9] = '/'; + s[10] = (char) (h->level + '0'); + } + h->method_name = s; + } + else + return -1; /* not a LZO method */ + +/* check compression level */ + if (h->level < 1 || h->level > 9) + return 15; + + return 0; +} + + +void lzo_init_compress_header(header_t *h) +{ + if (opt_checksum) + { + if (opt_crc32) + { + h->flags |= F_CRC32_D; + if (opt_checksum >= 2) + h->flags |= F_CRC32_C; + } + else + { + h->flags |= F_ADLER32_D; + if (opt_checksum >= 2) + h->flags |= F_ADLER32_C; + } + } +} + + +/************************************************************************* +// memory setup +**************************************************************************/ + +#if defined(ACC_OS_DOS16) && !defined(ACC_ARCH_I086PM) +# define BLOCK_SIZE (128*1024l) +#else +# define BLOCK_SIZE (256*1024l) +#endif +#define MAX_BLOCK_SIZE (64*1024l*1024l) /* DO NOT CHANGE */ + +#if defined(USE_LZO1X_999) +# define WRK_LEN LZO1X_999_MEM_COMPRESS +#elif defined(USE_LZO1X_1_15) +# define WRK_LEN LZO1X_1_15_MEM_COMPRESS +#elif defined(USE_LZO1X_1) +# define WRK_LEN LZO1X_1_MEM_COMPRESS +#else +# error +#endif + + +#if 1 +# define ALIGN_SIZE 4096 +#else +# define ALIGN_SIZE 1 +#endif + +/* LZO may expand uncompressible data by a small amount */ +#define MAX_COMPRESSED_SIZE(x) ((x) + (x) / 16 + 64 + 3) + + +static mblock_t blocks[2]; +static mblock_t wrkmem; + + +static void free_mem(void) +{ + mb_free(&wrkmem); + mb_free(&blocks[1]); + mb_free(&blocks[0]); +} + + +static lzo_bool alloc_mem(lzo_uint32 s1, lzo_uint32 s2, lzo_uint32 w) +{ + lzo_bool r = 1; + + r &= mb_alloc(&blocks[0], s1, ALIGN_SIZE); + r &= mb_alloc(&blocks[1], s2, ALIGN_SIZE); + r &= mb_alloc(&wrkmem, w, ALIGN_SIZE); + if (!r) + free_mem(); + return r; +} + + +/************************************************************************* +// enter / leave +**************************************************************************/ + +/* maybe make this an option ? */ +static const lzo_uint block_size = BLOCK_SIZE; + +lzo_bool lzo_enter(const header_t *h) +{ + int r; + lzo_uint32 wrk_len; + +#if defined(WITH_THREADS) + if (opt_num_threads > 1) + return lzo_threaded_enter(h); +#endif + + if (h != NULL) + { + r = 1; + if ((h->flags & F_ADLER32_C) && !(h->flags & F_ADLER32_D)) + { r = 0; assert(h->flags & F_ADLER32_D); } + if ((h->flags & F_CRC32_C) && !(h->flags & F_CRC32_D)) + { r = 0; assert(h->flags & F_CRC32_D); } + return r; + } + +#if 0 + fprintf(stderr,"%lu %lu %u\n", BLOCK_SIZE, MAX_BLOCK_SIZE, ALIGN_SIZE); +#endif + assert(block_size <= BLOCK_SIZE); + assert(block_size <= MAX_BLOCK_SIZE); + assert(block_size >= 16*1024); + + if (opt_method == M_LZO1X_1) + wrk_len = LZO1X_1_MEM_COMPRESS; + else if (opt_method == M_LZO1X_1_15) + wrk_len = LZO1X_1_15_MEM_COMPRESS; + else if (opt_method == M_LZO1X_999) + wrk_len = LZO1X_999_MEM_COMPRESS; + else + wrk_len = 0; + assert(wrk_len <= WRK_LEN); + + if (opt_method == M_LZO1X_999) + { + if (opt_checksum < 1) + opt_checksum = 1; /* always compute a checksum */ + if (opt_cmd == CMD_COMPRESS) + opt_optimize = 1; + } + + switch (opt_cmd) + { + case CMD_COMPRESS: + r = alloc_mem(block_size, MAX_COMPRESSED_SIZE(block_size), wrk_len); + break; + case CMD_DECOMPRESS: + case CMD_TEST: + r = alloc_mem(0, MAX_COMPRESSED_SIZE(block_size), 0); + break; + case CMD_LIST: + case CMD_LS: + case CMD_INFO: + r = alloc_mem(0, block_size, 0); + break; + default: + r = alloc_mem(0, 0, 0); + break; + } + + return r; +} + + +void lzo_leave(const header_t *h) +{ +#if defined(WITH_THREADS) + if (opt_num_threads > 1) { + lzo_threaded_leave(h); + return; + } +#endif + if (h == NULL) + free_mem(); +} + + +/************************************************************************* +// compress a file +**************************************************************************/ + +lzo_bool lzo_compress(file_t *fip, file_t *fop, const header_t *h) +{ + int r = LZO_E_OK; + lzo_bytep const b1 = blocks[0].mb_mem; + lzo_bytep const b2 = blocks[1].mb_mem; + lzo_uint32 src_len = 0; + lzo_uint dst_len = 0; + lzo_uint32 c_adler32 = ADLER32_INIT_VALUE, d_adler32 = ADLER32_INIT_VALUE; + lzo_uint32 c_crc32 = CRC32_INIT_VALUE, d_crc32 = CRC32_INIT_VALUE; + lzo_int l; + lzo_bool ok = 1; + +#if defined(WITH_THREADS) + if (opt_num_threads > 1) + return lzo_threaded_compress(fip, fop, h, skip); +#endif + + for (;;) + { + /* read a block */ + l = read_buf(fip, b1, block_size); + src_len = (l > 0 ? l : 0); + + /* write uncompressed block size */ + write32(fop,src_len); + + /* exit if last block */ + if (src_len == 0) + break; + + /* compute checksum of uncompressed block */ + if (h->flags & F_ADLER32_D) + d_adler32 = lzo_adler32(ADLER32_INIT_VALUE,b1,src_len); + if (h->flags & F_CRC32_D) + d_crc32 = lzo_crc32(CRC32_INIT_VALUE,b1,src_len); + + x_filter(b1,src_len,h); + + /* compress */ + if (h->method == M_LZO1X_1) + r = lzo1x_1_compress(b1, src_len, b2, &dst_len, wrkmem.mb_mem); +#if defined(USE_LZO1X_1_15) + else if (h->method == M_LZO1X_1_15) + r = lzo1x_1_15_compress(b1, src_len, + b2, &dst_len, wrkmem.mb_mem); +#endif +#if defined(USE_LZO1X_999) + else if (h->method == M_LZO1X_999) + r = lzo1x_999_compress_level(b1, src_len, + b2, &dst_len, wrkmem.mb_mem, + NULL, 0, 0, h->level); +#endif + else + fatal(fip,"Internal error"); + +#if 0 + fprintf(stderr, "%ld %ld %ld\n", (long)src_len, (long)dst_len, (long)block2.size); +#endif + assert(dst_len <= blocks[1].mb_size); + if (r != LZO_E_OK) + fatal(fip,"Internal error - compression failed"); + + /* optimize */ + if (opt_optimize && dst_len < src_len) + { + lzo_uint new_len = src_len; + r = lzo1x_optimize(b2, dst_len, b1, &new_len, NULL); + if (r != LZO_E_OK || new_len != src_len) + fatal(fip,"Internal error - optimization failed"); + } + + /* write compressed block size */ + if (dst_len < src_len) + write32(fop,dst_len); + else + write32(fop,src_len); + + /* write checksum of uncompressed block */ + if (h->flags & F_ADLER32_D) + write32(fop,d_adler32); + if (h->flags & F_CRC32_D) + write32(fop,d_crc32); + + /* write checksum of compressed block */ + if (dst_len < src_len && (h->flags & F_ADLER32_C)) + { + c_adler32 = lzo_adler32(ADLER32_INIT_VALUE,b2,dst_len); + write32(fop,c_adler32); + } + if (dst_len < src_len && (h->flags & F_CRC32_C)) + { + c_crc32 = lzo_crc32(CRC32_INIT_VALUE,b2,dst_len); + write32(fop,c_crc32); + } + + /* write compressed block data */ + if (dst_len < src_len) + write_buf(fop,b2,dst_len); + else + write_buf(fop,b1,src_len); + } + + return ok; +} + + +/************************************************************************* +// decompress a file +**************************************************************************/ + +lzo_bool lzo_decompress(file_t *fip, file_t *fop, + const header_t *h, lzo_bool skip) +{ + int r; + lzo_uint32 src_len, dst_len; + lzo_uint32 c_adler32 = ADLER32_INIT_VALUE, d_adler32 = ADLER32_INIT_VALUE; + lzo_uint32 c_crc32 = CRC32_INIT_VALUE, d_crc32 = CRC32_INIT_VALUE; + lzo_bool ok = 1; + lzo_bool use_seek; + mblock_t * const block = &blocks[1]; + lzo_bytep b1; + lzo_bytep const b2 = block->mb_mem; + +#if defined(WITH_THREADS) + if (opt_num_threads > 1) + return lzo_threaded_decompress(fip, fop, h, skip); +#endif + + use_seek = skip || opt_cmd == CMD_LIST || opt_cmd == CMD_LS || + opt_cmd == CMD_INFO; + + for (;;) + { + lzo_bytep dst; + + /* read uncompressed block size */ + read32(fip,&dst_len); + + /* exit if last block */ + if (dst_len == 0) + break; + + /* error if split file */ + if (dst_len == 0xffffffffUL) + { + /* should not happen - not yet implemented */ + error(fip,"this file is a split " PACKAGE " file"); + ok = 0; break; + } + + if (dst_len > MAX_BLOCK_SIZE) + { + error(fip, PACKAGE " file corrupted"); + ok = 0; break; + } + + /* read compressed block size */ + read32(fip,&src_len); + if (src_len <= 0 || src_len > dst_len) + { + error(fip, PACKAGE " file corrupted"); + ok = 0; break; + } + + if (dst_len > BLOCK_SIZE) + { + fatal(fip,"block size too small -- recompile " PACKAGE); + ok = 0; break; + } + if (dst_len > block_size) + { + /* should not happen - not yet implemented */ + fatal(fip,"block size too small -- use option '--blocksize'"); + ok = 0; break; + } + assert(block->mb_size >= src_len); + + /* read checksum of uncompressed block */ + if (h->flags & F_ADLER32_D) + read32(fip,&d_adler32); + if (h->flags & F_CRC32_D) + read32(fip,&d_crc32); + + /* read checksum of compressed block */ + if (h->flags & F_ADLER32_C) + { + if (src_len < dst_len) + read32(fip,&c_adler32); + else + { + assert(h->flags & F_ADLER32_D); + c_adler32 = d_adler32; + } + } + if (h->flags & F_CRC32_C) + { + if (src_len < dst_len) + read32(fip,&c_crc32); + else + { + assert(h->flags & F_CRC32_D); + c_crc32 = d_crc32; + } + } + + /* read the block */ + b1 = block->mb_mem + block->mb_size - src_len; + if (use_seek && fip->fd != STDIN_FILENO) + { + if (lseek(fip->fd, src_len, SEEK_CUR) == -1) + read_error(fip); + } + else + { + if (read_buf(fip, b1, src_len) != (lzo_int) src_len) + read_error(fip); + } + + fip->bytes_processed += src_len; + if (use_seek) + { + fop->bytes_processed += dst_len; + continue; + } + assert(block->mb_size >= MAX_COMPRESSED_SIZE(dst_len)); + + /* verify checksum of compressed block */ + if (opt_checksum && (h->flags & F_ADLER32_C)) + { + lzo_uint32 c; + c = lzo_adler32(ADLER32_INIT_VALUE,b1,src_len); + if (c != c_adler32) + { + error(fip,"Checksum error (" PACKAGE " file corrupted)"); + ok = 0; break; + } + } + if (opt_checksum && (h->flags & F_CRC32_C)) + { + lzo_uint32 c; + c = lzo_crc32(CRC32_INIT_VALUE,b1,src_len); + if (c != c_crc32) + { + error(fip,"Checksum error (" PACKAGE " file corrupted)"); + ok = 0; break; + } + } + + if (src_len < dst_len) + { + lzo_uint d = dst_len; + + /* decompress */ + if (opt_decompress_safe) + r = lzo1x_decompress_safe(b1,src_len,b2,&d,NULL); + else + r = lzo1x_decompress(b1,src_len,b2,&d,NULL); + + if (r != LZO_E_OK || dst_len != d) + { + error(fip,"Compressed data violation"); +#if 0 + fprintf(stderr,"%d %ld %ld\n", r, (long)dst_len, (long)d); +#endif + ok = 0; break; + } + dst = b2; + } + else + { + assert(dst_len == src_len); + dst = b1; + } + + x_filter(dst,dst_len,h); + + /* verify checksum of uncompressed block */ + if (opt_checksum && (h->flags & F_ADLER32_D)) + { + lzo_uint32 c; + c = lzo_adler32(ADLER32_INIT_VALUE,dst,dst_len); + if (c != d_adler32) + { + error(fip,"Checksum error"); + ok = 0; break; + } + } + if (opt_checksum && (h->flags & F_CRC32_D)) + { + lzo_uint32 c; + c = lzo_crc32(CRC32_INIT_VALUE,dst,dst_len); + if (c != d_crc32) + { + error(fip,"Checksum error"); + ok = 0; break; + } + } + + /* write uncompressed block data */ + write_buf(fop,dst,dst_len); + fop->bytes_processed += dst_len; + } + + return ok; +} + + +#endif /* WITH_LZO */ + + +/* +vi:ts=4:et +*/ + |